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