2 * "$Id: search.c 9793 2011-05-20 03:49:49Z mike $"
4 * Search routines for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
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/".
17 * cgiCompileSearch() - Compile a search string.
18 * cgiDoSearch() - Do a search of some text.
19 * cgiFreeSearch() - Free a compiled search context.
23 * Include necessary headers...
26 #include "cgi-private.h"
31 * 'cgiCompileSearch()' - Compile a search string.
34 void * /* O - Search context */
35 cgiCompileSearch(const char *query) /* I - Query string */
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 */
50 DEBUG_printf(("cgiCompileSearch(query=\"%s\")\n", query));
53 * Range check input...
60 * Allocate a regular expression storage structure...
63 if ((re = (regex_t *)calloc(1, sizeof(regex_t))) == NULL)
67 * Allocate a buffer to hold the regular expression string, starting
68 * at 1024 bytes or 3 times the length of the query string, whichever
69 * is greater. We'll expand the string as needed...
72 slen = strlen(query) * 3;
76 if ((s = (char *)malloc(slen)) == NULL)
83 * Copy the query string to the regular expression, handling basic
95 * Skip leading whitespace...
98 while (isspace(*qptr & 255))
105 * Find the end of the current word...
108 if (*qptr == '\"' || *qptr == '\'')
111 * Scan quoted string...
115 for (qend = qptr; *qend && *qend != quoted; qend ++);
120 * No closing quote, error out!
135 * Scan whitespace-delimited string...
139 for (qend = qptr + 1; *qend && !isspace(*qend); qend ++);
145 * Look for logic words: AND, OR
148 if (wlen == 3 && !_cups_strncasecmp(qptr, "AND", 3))
151 * Logical AND with the following text...
159 else if (wlen == 2 && !_cups_strncasecmp(qptr, "OR", 2))
162 * Logical OR with the following text...
173 * Add a search word, making sure we have enough room for the
174 * string + RE overhead...
177 wlen = (sptr - s) + 2 * 4 * wlen + 2 * strlen(prefix) + 11;
179 wlen += strlen(lword);
184 * Expand the RE string buffer...
187 char *temp; /* Temporary string pointer */
191 temp = (char *)realloc(s, slen);
203 sptr = temp + (sptr - s);
208 * Add the prefix string...
211 strcpy(sptr, prefix);
212 sptr += strlen(sptr);
215 * Then quote the remaining word characters as needed for the
224 * Quote: ^ . [ $ ( ) | * + ? { \
227 if (strchr("^.[$()|*+?{\\", *qptr))
236 * For "word1 AND word2", add reciprocal "word2 AND word1"...
239 if (!strcmp(prefix, ".*") && lword)
241 char *lword2; /* New "last word" */
244 if ((lword2 = strdup(sword)) == NULL)
252 strcpy(sptr, ".*|.*");
255 strcpy(sptr, lword2);
256 sptr += strlen(sptr);
262 sptr += strlen(sptr);
272 lword = strdup(sword);
279 * Advance to the next string...
294 * No query data, return NULL...
304 * Compile the regular expression...
307 DEBUG_printf((" s=\"%s\"\n", s));
309 if (regcomp(re, s, REG_EXTENDED | REG_ICASE))
318 * Free the RE string and return the new regular expression we compiled...
328 * 'cgiDoSearch()' - Do a search of some text.
331 int /* O - Number of matches */
332 cgiDoSearch(void *search, /* I - Search context */
333 const char *text) /* I - Text to search */
335 int i; /* Looping var */
336 regmatch_t matches[100]; /* RE matches */
343 if (!search || !text)
350 if (!regexec((regex_t *)search, text, sizeof(matches) / sizeof(matches[0]),
354 * Figure out the number of matches in the string...
357 for (i = 0; i < (int)(sizeof(matches) / sizeof(matches[0])); i ++)
358 if (matches[i].rm_so < 0)
369 * 'cgiFreeSearch()' - Free a compiled search context.
373 cgiFreeSearch(void *search) /* I - Search context */
375 regfree((regex_t *)search);
380 * End of "$Id: search.c 9793 2011-05-20 03:49:49Z mike $".