]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/search.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / cgi-bin / search.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Search routines for CUPS.
ef416fc2 3 *
7e86f2f6
MS
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
7e86f2f6
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
18#include "cgi-private.h"
19#include <regex.h>
20
21
22/*
23 * 'cgiCompileSearch()' - Compile a search string.
24 */
25
26void * /* O - Search context */
27cgiCompileSearch(const char *query) /* I - Query string */
28{
29 regex_t *re; /* Regular expression */
30 char *s, /* Regular expression string */
31 *sptr, /* Pointer into RE string */
32 *sword; /* Pointer to start of word */
7e86f2f6 33 size_t slen; /* Allocated size of RE string */
ef416fc2 34 const char *qptr, /* Pointer into query string */
35 *qend; /* End of current word */
36 const char *prefix; /* Prefix to add to next word */
37 int quoted; /* Word is quoted */
7e86f2f6 38 size_t wlen; /* Word length */
ef416fc2 39 char *lword; /* Last word in query */
40
41
1f0275e3
MS
42 DEBUG_printf(("cgiCompileSearch(query=\"%s\")\n", query));
43
44 /*
45 * Range check input...
46 */
47
48 if (!query)
49 return (NULL);
ef416fc2 50
51 /*
52 * Allocate a regular expression storage structure...
53 */
54
91c84a35
MS
55 if ((re = (regex_t *)calloc(1, sizeof(regex_t))) == NULL)
56 return (NULL);
ef416fc2 57
58 /*
59 * Allocate a buffer to hold the regular expression string, starting
60 * at 1024 bytes or 3 times the length of the query string, whichever
61 * is greater. We'll expand the string as needed...
62 */
63
64 slen = strlen(query) * 3;
65 if (slen < 1024)
66 slen = 1024;
67
91c84a35
MS
68 if ((s = (char *)malloc(slen)) == NULL)
69 {
70 free(re);
71 return (NULL);
72 }
ef416fc2 73
74 /*
75 * Copy the query string to the regular expression, handling basic
76 * AND and OR logic...
77 */
78
79 prefix = ".*";
80 qptr = query;
81 sptr = s;
82 lword = NULL;
83
84 while (*qptr)
85 {
86 /*
87 * Skip leading whitespace...
88 */
89
90 while (isspace(*qptr & 255))
91 qptr ++;
92
93 if (!*qptr)
94 break;
95
96 /*
97 * Find the end of the current word...
98 */
99
100 if (*qptr == '\"' || *qptr == '\'')
101 {
102 /*
103 * Scan quoted string...
104 */
105
106 quoted = *qptr ++;
107 for (qend = qptr; *qend && *qend != quoted; qend ++);
108
109 if (!*qend)
110 {
111 /*
112 * No closing quote, error out!
113 */
114
115 free(s);
116 free(re);
117
118 if (lword)
119 free(lword);
120
121 return (NULL);
122 }
123 }
124 else
125 {
126 /*
127 * Scan whitespace-delimited string...
128 */
129
130 quoted = 0;
131 for (qend = qptr + 1; *qend && !isspace(*qend); qend ++);
132 }
133
7e86f2f6 134 wlen = (size_t)(qend - qptr);
ef416fc2 135
136 /*
137 * Look for logic words: AND, OR
138 */
139
88f9aafc 140 if (wlen == 3 && !_cups_strncasecmp(qptr, "AND", 3))
ef416fc2 141 {
142 /*
143 * Logical AND with the following text...
144 */
145
146 if (sptr > s)
147 prefix = ".*";
148
149 qptr = qend;
150 }
88f9aafc 151 else if (wlen == 2 && !_cups_strncasecmp(qptr, "OR", 2))
ef416fc2 152 {
153 /*
154 * Logical OR with the following text...
155 */
156
157 if (sptr > s)
158 prefix = ".*|.*";
159
160 qptr = qend;
161 }
162 else
163 {
164 /*
165 * Add a search word, making sure we have enough room for the
166 * string + RE overhead...
167 */
168
7e86f2f6 169 wlen = (size_t)(sptr - s) + 2 * 4 * wlen + 2 * strlen(prefix) + 11;
839a51c8
MS
170 if (lword)
171 wlen += strlen(lword);
ef416fc2 172
173 if (wlen > slen)
174 {
175 /*
176 * Expand the RE string buffer...
177 */
178
179 char *temp; /* Temporary string pointer */
180
181
182 slen = wlen + 128;
183 temp = (char *)realloc(s, slen);
184 if (!temp)
185 {
186 free(s);
187 free(re);
188
189 if (lword)
190 free(lword);
191
192 return (NULL);
193 }
194
195 sptr = temp + (sptr - s);
196 s = temp;
197 }
198
199 /*
200 * Add the prefix string...
201 */
202
5a9febac 203 memcpy(sptr, prefix, strlen(prefix) + 1);
ef416fc2 204 sptr += strlen(sptr);
205
206 /*
207 * Then quote the remaining word characters as needed for the
208 * RE...
209 */
210
211 sword = sptr;
212
213 while (qptr < qend)
214 {
215 /*
216 * Quote: ^ . [ $ ( ) | * + ? { \
217 */
218
219 if (strchr("^.[$()|*+?{\\", *qptr))
220 *sptr++ = '\\';
221
222 *sptr++ = *qptr++;
223 }
224
07725fee 225 *sptr = '\0';
226
ef416fc2 227 /*
228 * For "word1 AND word2", add reciprocal "word2 AND word1"...
229 */
230
231 if (!strcmp(prefix, ".*") && lword)
232 {
233 char *lword2; /* New "last word" */
234
235
91c84a35
MS
236 if ((lword2 = strdup(sword)) == NULL)
237 {
238 free(lword);
239 free(s);
240 free(re);
241 return (NULL);
242 }
ef416fc2 243
5a9febac 244 memcpy(sptr, ".*|.*", 6);
ef416fc2 245 sptr += 5;
246
5a9febac 247 memcpy(sptr, lword2, strlen(lword2) + 1);
ef416fc2 248 sptr += strlen(sptr);
249
5a9febac 250 memcpy(sptr, ".*", 3);
ef416fc2 251 sptr += 2;
252
5a9febac 253 memcpy(sptr, lword, strlen(lword) + 1);
ef416fc2 254 sptr += strlen(sptr);
255
256 free(lword);
257 lword = lword2;
258 }
259 else
260 {
261 if (lword)
262 free(lword);
263
264 lword = strdup(sword);
265 }
266
267 prefix = ".*|.*";
268 }
269
270 /*
271 * Advance to the next string...
272 */
273
274 if (quoted)
275 qptr ++;
276 }
277
278 if (lword)
279 free(lword);
280
281 if (sptr > s)
5a9febac 282 memcpy(sptr, ".*", 3);
ef416fc2 283 else
284 {
285 /*
286 * No query data, return NULL...
287 */
288
289 free(s);
290 free(re);
291
292 return (NULL);
293 }
294
295 /*
296 * Compile the regular expression...
297 */
298
299 DEBUG_printf((" s=\"%s\"\n", s));
300
301 if (regcomp(re, s, REG_EXTENDED | REG_ICASE))
302 {
303 free(re);
304 free(s);
305
306 return (NULL);
307 }
308
309 /*
310 * Free the RE string and return the new regular expression we compiled...
311 */
312
313 free(s);
314
315 return ((void *)re);
316}
317
318
319/*
320 * 'cgiDoSearch()' - Do a search of some text.
321 */
322
323int /* O - Number of matches */
324cgiDoSearch(void *search, /* I - Search context */
325 const char *text) /* I - Text to search */
326{
327 int i; /* Looping var */
328 regmatch_t matches[100]; /* RE matches */
329
330
331 /*
332 * Range check...
333 */
334
335 if (!search || !text)
336 return (0);
337
338 /*
339 * Do a lookup...
340 */
341
342 if (!regexec((regex_t *)search, text, sizeof(matches) / sizeof(matches[0]),
343 matches, 0))
344 {
345 /*
346 * Figure out the number of matches in the string...
347 */
348
349 for (i = 0; i < (int)(sizeof(matches) / sizeof(matches[0])); i ++)
350 if (matches[i].rm_so < 0)
351 break;
352
353 return (i);
354 }
355 else
356 return (0);
357}
358
359
360/*
361 * 'cgiFreeSearch()' - Free a compiled search context.
362 */
363
364void
365cgiFreeSearch(void *search) /* I - Search context */
366{
367 regfree((regex_t *)search);
368}