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