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