Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * ts_utils.c
4 : : * various support functions
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/tsearch/ts_utils.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include <ctype.h>
18 : :
19 : : #include "miscadmin.h"
20 : : #include "tsearch/ts_locale.h"
21 : : #include "tsearch/ts_public.h"
22 : :
23 : :
24 : : /*
25 : : * Given the base name and extension of a tsearch config file, return
26 : : * its full path name. The base name is assumed to be user-supplied,
27 : : * and is checked to prevent pathname attacks. The extension is assumed
28 : : * to be safe.
29 : : *
30 : : * The result is a palloc'd string.
31 : : */
32 : : char *
6081 tgl@sss.pgh.pa.us 33 :CBC 192 : get_tsearch_config_filename(const char *basename,
34 : : const char *extension)
35 : : {
36 : : char sharepath[MAXPGPATH];
37 : : char *result;
38 : :
39 : : /*
40 : : * We limit the basename to contain a-z, 0-9, and underscores. This may
41 : : * be overly restrictive, but we don't want to allow access to anything
42 : : * outside the tsearch_data directory, so for instance '/' *must* be
43 : : * rejected, and on some platforms '\' and ':' are risky as well. Allowing
44 : : * uppercase might result in incompatible behavior between case-sensitive
45 : : * and case-insensitive filesystems, and non-ASCII characters create other
46 : : * interesting risks, so on the whole a tight policy seems best.
47 : : */
6067 48 [ - + ]: 192 : if (strspn(basename, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(basename))
6067 tgl@sss.pgh.pa.us 49 [ # # ]:UBC 0 : ereport(ERROR,
50 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
51 : : errmsg("invalid text search configuration file name \"%s\"",
52 : : basename)));
53 : :
6081 tgl@sss.pgh.pa.us 54 :CBC 192 : get_share_path(my_exec_path, sharepath);
55 : 192 : result = palloc(MAXPGPATH);
56 : 192 : snprintf(result, MAXPGPATH, "%s/tsearch_data/%s.%s",
57 : : sharepath, basename, extension);
58 : :
59 : 192 : return result;
60 : : }
61 : :
62 : : /*
63 : : * Reads a stop-word file. Each word is run through 'wordop'
64 : : * function, if given. wordop may either modify the input in-place,
65 : : * or palloc a new version.
66 : : */
67 : : void
5995 bruce@momjian.us 68 : 19 : readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *))
69 : : {
6081 tgl@sss.pgh.pa.us 70 : 19 : char **stop = NULL;
71 : :
72 : 19 : s->len = 0;
6077 73 [ + - + - ]: 19 : if (fname && *fname)
74 : : {
75 : 19 : char *filename = get_tsearch_config_filename(fname, "stop");
76 : : tsearch_readline_state trst;
77 : : char *line;
6081 78 : 19 : int reallen = 0;
79 : :
5779 80 [ - + ]: 19 : if (!tsearch_readline_begin(&trst, filename))
6081 tgl@sss.pgh.pa.us 81 [ # # ]:UBC 0 : ereport(ERROR,
82 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
83 : : errmsg("could not open stop-word file \"%s\": %m",
84 : : filename)));
85 : :
5779 tgl@sss.pgh.pa.us 86 [ + + ]:CBC 2432 : while ((line = tsearch_readline(&trst)) != NULL)
87 : : {
5995 bruce@momjian.us 88 : 2413 : char *pbuf = line;
89 : :
90 : : /* Trim trailing space */
6077 tgl@sss.pgh.pa.us 91 [ + - + + ]: 11818 : while (*pbuf && !t_isspace(pbuf))
5778 92 : 9405 : pbuf += pg_mblen(pbuf);
6081 93 : 2413 : *pbuf = '\0';
94 : :
95 : : /* Skip empty lines */
6077 96 [ - + ]: 2413 : if (*line == '\0')
97 : : {
6077 tgl@sss.pgh.pa.us 98 :UBC 0 : pfree(line);
99 : 0 : continue;
100 : : }
101 : :
6081 tgl@sss.pgh.pa.us 102 [ + + ]:CBC 2413 : if (s->len >= reallen)
103 : : {
104 [ + + ]: 38 : if (reallen == 0)
105 : : {
6077 106 : 19 : reallen = 64;
6081 107 : 19 : stop = (char **) palloc(sizeof(char *) * reallen);
108 : : }
109 : : else
110 : : {
111 : 19 : reallen *= 2;
432 peter@eisentraut.org 112 : 19 : stop = (char **) repalloc(stop, sizeof(char *) * reallen);
113 : : }
114 : : }
115 : :
6077 tgl@sss.pgh.pa.us 116 [ + - ]: 2413 : if (wordop)
117 : : {
118 : 2413 : stop[s->len] = wordop(line);
119 [ + - ]: 2413 : if (stop[s->len] != line)
120 : 2413 : pfree(line);
121 : : }
122 : : else
6077 tgl@sss.pgh.pa.us 123 :UBC 0 : stop[s->len] = line;
124 : :
6081 tgl@sss.pgh.pa.us 125 :CBC 2413 : (s->len)++;
126 : : }
127 : :
5779 128 : 19 : tsearch_readline_end(&trst);
6081 129 : 19 : pfree(filename);
130 : : }
131 : :
132 : 19 : s->stop = stop;
133 : :
134 : : /* Sort to allow binary searching */
135 [ + - + - ]: 19 : if (s->stop && s->len > 0)
4286 rhaas@postgresql.org 136 : 19 : qsort(s->stop, s->len, sizeof(char *), pg_qsort_strcmp);
6081 tgl@sss.pgh.pa.us 137 : 19 : }
138 : :
139 : : bool
5995 bruce@momjian.us 140 : 7629 : searchstoplist(StopList *s, char *key)
141 : : {
6081 tgl@sss.pgh.pa.us 142 [ + + + - : 12764 : return (s->stop && s->len > 0 &&
+ + ]
143 : 5135 : bsearch(&key, s->stop, s->len,
144 : : sizeof(char *), pg_qsort_strcmp));
145 : : }
|