rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

mire.c
Go to the documentation of this file.
1
4 #include "system.h"
5
6 #include <rpmiotypes.h>
7 #include <rpmio.h>
8 #include <rpmlog.h>
9
10 #define _MIRE_INTERNAL
11 #include <mire.h>
12
13 #include "debug.h"
14
15 /*@access regex_t @*/
16
17 /*@unchecked@*/
18 int _mire_debug = 0;
19
20 /*@unchecked@*/
21 const unsigned char * _mirePCREtables = NULL;
22
23 /*@unchecked@*/
24 mireEL_t _mireEL = EL_LF;
25
26 /*@unchecked@*/
27 int _mireSTRINGoptions = 0;
28
29 /*@unchecked@*/
30 int _mireGLOBoptions = FNM_EXTMATCH | FNM_PATHNAME | FNM_PERIOD;
31
32 /*@unchecked@*/
33 int _mireREGEXoptions = REG_EXTENDED | REG_NEWLINE;
34
35 /*@unchecked@*/
36 int _mirePCREoptions = 0;
37
38 int mireClean(miRE mire)
39 {
40 if (mire == NULL) return 0;
41 /*@-modfilesys@*/
42 if (_mire_debug)
43 fprintf(stderr, "--> mireClean(%p)\n", mire);
44 /*@=modfilesys@*/
45 mire->pattern = _free(mire->pattern);
46 if (mire->mode == RPMMIRE_REGEX) {
47 if (mire->preg != NULL) {
48 regfree(mire->preg);
49 /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
50 mire->preg = _free(mire->preg);
51 /*@=voidabstract =usereleased @*/
52 }
53 }
54 if (mire->mode == RPMMIRE_PCRE) { /* TODO: (*pcre_free)(_p) override */
55 mire->pcre = _free(mire->pcre);
56 mire->hints = _free(mire->hints);
57 }
58 mire->errmsg = NULL;
59 mire->erroff = 0;
60 mire->errcode = 0;
61 mire->fnflags = 0;
62 mire->cflags = 0;
63 mire->eflags = 0;
64 mire->coptions = 0;
65 mire->eoptions = 0;
66 mire->notmatch = 0;
67 return 0;
68 }
69
70 static void mireFini(void * _mire)
71 /*@modifies _mire @*/
72 {
73 miRE mire = _mire;
74 (void) mireClean(mire);
75 }
76
77 /*@unchecked@*/ /*@only@*/ /*@null@*/
78 rpmioPool _mirePool;
79
80 miRE mireGetPool(rpmioPool pool)
81 {
82 miRE mire;
83
84 if (_mirePool == NULL) {
85 _mirePool = rpmioNewPool("mire", sizeof(*mire), -1, _mire_debug,
86 NULL, NULL, mireFini);
87 pool = _mirePool;
88 }
89 return (miRE) rpmioGetPool(pool, sizeof(*mire));
90 }
91
92 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */
93 void * mireFreeAll(miRE mire, int nmire)
94 {
95 if (mire != NULL) {
96 int i;
97 for (i = 0; i < nmire; i++)
98 (void) mireClean(mire + i);
99 /* XXX rpmgrep doesn't use mire pools yet. retrofit a fix. */
100 if (mire->_item.use != NULL && mire->_item.pool != NULL) {
101 /* XXX only the 1st element in the array has a usage mutex. */
102 mire = xrealloc(mire, sizeof(*mire));
103 mire = (miRE)rpmioFreePoolItem((rpmioItem)mire, __FUNCTION__, __FILE__, __LINE__);
104 } else
105 mire = _free(mire);
106 }
107 return NULL;
108 }
109 /*@=onlytrans@*/
110
111 miRE mireNew(rpmMireMode mode, int tag)
112 {
113 miRE mire = mireGetPool(_mirePool);
114 mire->mode = mode;
115 mire->tag = tag;
116 return mireLink(mire);
117 }
118
119 int mireSetCOptions(miRE mire, rpmMireMode mode, int tag, int options,
120 const unsigned char * table)
121 {
122 int rc = 0;
123 mire->mode = mode;
124 mire->tag = tag;
125 switch (mire->mode) {
126 case RPMMIRE_DEFAULT:
127 break;
128 case RPMMIRE_STRCMP:
129 /* XXX strcasecmp? */
130 break;
131 case RPMMIRE_GLOB:
132 if (options == 0)
133 options = _mireGLOBoptions;
134 mire->fnflags = options;
135 break;
136 case RPMMIRE_REGEX:
137 if (options == 0)
138 options = _mireREGEXoptions;
139 mire->cflags = options;
140 break;
141 case RPMMIRE_PCRE:
142 if (options == 0)
143 options = _mirePCREoptions;
144 /* XXX check default compile options? */
145 mire->coptions = options;
146 /*@-assignexpose -temptrans @*/
147 mire->table = table;
148 /*@=assignexpose =temptrans @*/
149 break;
150 }
151 return rc;
152 }
153
154 int mireSetEOptions(miRE mire, int * offsets, int noffsets)
155 {
156 int rc = 0;
157 if (mire->mode == RPMMIRE_PCRE) {
158 mire->startoff = 0;
159 mire->eoptions = 0;
160 /*@-assignexpose@*/
161 mire->offsets = offsets;
162 /*@=assignexpose@*/
163 mire->noffsets = noffsets;
164 } else
165 if (mire->mode == RPMMIRE_REGEX) {
166 mire->startoff = 0;
167 mire->eoptions = 0;
168 /*@-assignexpose@*/
169 mire->offsets = offsets;
170 /*@=assignexpose@*/
171 mire->noffsets = noffsets;
172 } else
173 rc = -1;
174
175 return rc;
176 }
177
178 int mireSetGOptions(const char * newline, int caseless, int multiline, int utf8)
179 {
180 int rc = 0;
181
182 if (caseless) {
183 #if defined(PCRE_CASELESS)
184 _mirePCREoptions |= PCRE_CASELESS;
185 #endif
186 _mireREGEXoptions |= REG_ICASE;
187 #if defined(FNM_CASEFOLD)
188 _mireGLOBoptions |= FNM_CASEFOLD;
189 #endif
190 } else {
191 #if defined(PCRE_CASELESS)
192 _mirePCREoptions &= ~PCRE_CASELESS;
193 #endif
194 _mireREGEXoptions &= ~REG_ICASE;
195 #if defined(FNM_CASEFOLD)
196 _mireGLOBoptions &= ~FNM_CASEFOLD;
197 #endif
198 }
199
200 if (multiline) {
201 #if defined(PCRE_MULTILINE)
202 _mirePCREoptions |= PCRE_MULTILINE|PCRE_FIRSTLINE;
203 #endif
204 } else {
205 #if defined(PCRE_MULTILINE)
206 _mirePCREoptions &= ~(PCRE_MULTILINE|PCRE_FIRSTLINE);
207 #endif
208 }
209
210 if (utf8) {
211 #if defined(PCRE_UTF8)
212 _mirePCREoptions |= PCRE_UTF8;
213 #endif
214 } else {
215 #if defined(PCRE_UTF8)
216 _mirePCREoptions &= ~PCRE_UTF8;
217 #endif
218 }
219
220 /*
221 * Set the default line ending value from the default in the PCRE library;
222 * "lf", "cr", "crlf", and "any" are supported. Anything else is treated
223 * as "lf".
224 */
225 if (newline == NULL) {
226 int val = 0;
227 #if defined(PCRE_CONFIG_NEWLINE)
228 /*@-modunconnomods@*/
229 (void)pcre_config(PCRE_CONFIG_NEWLINE, &val);
230 /*@=modunconnomods@*/
231 #endif
232 switch (val) {
233 default: newline = "lf"; break;
234 case '\r': newline = "cr"; break;
235 /*@-shiftimplementation@*/
236 case ('\r' << 8) | '\n': newline = "crlf"; break;
237 /*@=shiftimplementation@*/
238 case -1: newline = "any"; break;
239 case -2: newline = "anycrlf"; break;
240 }
241 }
242
243 /* Interpret the newline type; the default settings are Unix-like. */
244 if (!strcasecmp(newline, "cr")) {
245 #if defined(PCRE_NEWLINE_CR)
246 _mirePCREoptions |= PCRE_NEWLINE_CR;
247 #endif
248 _mireEL = EL_CR;
249 } else if (!strcasecmp(newline, "lf")) {
250 #if defined(PCRE_NEWLINE_LF)
251 _mirePCREoptions |= PCRE_NEWLINE_LF;
252 #endif
253 _mireEL = EL_LF;
254 } else if (!strcasecmp(newline, "crlf")) {
255 #if defined(PCRE_NEWLINE_CRLF)
256 _mirePCREoptions |= PCRE_NEWLINE_CRLF;
257 #endif
258 _mireEL = EL_CRLF;
259 } else if (!strcasecmp(newline, "any")) {
260 #if defined(PCRE_NEWLINE_ANY)
261 _mirePCREoptions |= PCRE_NEWLINE_ANY;
262 #endif
263 _mireEL = EL_ANY;
264 } else if (!strcasecmp(newline, "anycrlf")) {
265 #if defined(PCRE_NEWLINE_ANYCRLF)
266 _mirePCREoptions |= PCRE_NEWLINE_ANYCRLF;
267 #endif
268 _mireEL = EL_ANYCRLF;
269 } else {
270 rc = -1;
271 }
272
273 return rc;
274 }
275
276 int mireSetLocale(/*@unused@*/ miRE mire, const char * locale)
277 {
278 const char * locale_from = NULL;
279 int rc = -1; /* assume failure */
280
281 /* XXX TODO: --locale jiggery-pokery should be done env LC_ALL=C rpmgrep */
282 if (locale == NULL) {
283 if (locale)
284 locale_from = "--locale";
285 else {
286 /*
287 * If a locale has not been provided as an option, see if the
288 * LC_CTYPE or LC_ALL environment variable is set, and if so,
289 * use it.
290 */
291 /*@-dependenttrans -observertrans@*/
292 if ((locale = getenv("LC_ALL")) != NULL)
293 locale_from = "LC_ALL";
294 else if ((locale = getenv("LC_CTYPE")) != NULL)
295 locale_from = "LC_CTYPE";
296 /*@=dependenttrans =observertrans@*/
297 if (locale)
298 locale = xstrdup(locale);
299 }
300 }
301
302 /*
303 * If a locale has been provided, set it, and generate the tables PCRE
304 * needs. Otherwise, _mirePCREtables == NULL, which uses default tables.
305 */
306 if (locale != NULL) {
307 const char * olocale = setlocale(LC_CTYPE, locale);
308 if (olocale == NULL) {
309 /*@-modfilesys@*/
310 fprintf(stderr,
311 _("%s: Failed to set locale %s (obtained from %s)\n"),
312 __progname, locale, locale_from);
313 /*@=modfilesys@*/
314 goto exit;
315 }
316 #if defined(WITH_PCRE)
317 /*@-evalorderuncon -onlytrans @*/
318 _mirePCREtables = pcre_maketables();
319 /*@=evalorderuncon =onlytrans @*/
320 #ifdef NOTYET
321 if (setlocale(LC_CTYPE, olocale) == NULL)
322 goto exit;
323 #endif
324 #endif
325 }
326 rc = 0;
327
328 exit:
329 return rc;
330 }
331
332 int mireRegcomp(miRE mire, const char * pattern)
333 {
334 int rc = 0;
335
336 mire->pattern = xstrdup(pattern);
337
338 switch (mire->mode) {
339 case RPMMIRE_STRCMP:
340 break;
341 case RPMMIRE_PCRE:
342 #ifdef WITH_PCRE
343 mire->errcode = 0;
344 mire->errmsg = NULL;
345 mire->erroff = 0;
346 mire->pcre = pcre_compile2(mire->pattern, mire->coptions,
347 &mire->errcode, &mire->errmsg, &mire->erroff, mire->table);
348 if (mire->pcre == NULL) {
349 if (_mire_debug)
350 rpmlog(RPMLOG_ERR,
351 _("pcre_compile2 failed: %s(%d) at offset %d of \"%s\"\n"),
352 mire->errmsg, mire->errcode, mire->erroff, mire->pattern);
353 rc = -1;
354 goto exit; /* XXX HACK: rpmgrep is not expecting mireClean. */
355 }
356 #else
357 rc = -99;
358 #endif
359 break;
360 case RPMMIRE_DEFAULT:
361 case RPMMIRE_REGEX:
362 mire->preg = xcalloc(1, sizeof(*mire->preg));
363 if (mire->cflags == 0)
364 mire->cflags = _mireREGEXoptions;
365 rc = regcomp(mire->preg, mire->pattern, mire->cflags);
366 if (rc) {
367 char msg[256];
368 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
369 msg[sizeof(msg)-1] = '\0';
370 rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n"),
371 mire->pattern, msg);
372 }
373 break;
374 case RPMMIRE_GLOB:
375 if (mire->fnflags == 0)
376 mire->fnflags = _mireGLOBoptions;
377 break;
378 default:
379 rc = -1;
380 break;
381 }
382
383 if (rc)
384 (void) mireClean(mire);
385
386 #ifdef WITH_PCRE
387 exit:
388 #endif
389 /*@-modfilesys@*/
390 if (_mire_debug)
391 fprintf(stderr, "--> mireRegcomp(%p, \"%s\") rc %d\n", mire, pattern, rc);
392 /*@=modfilesys@*/
393 return rc;
394 }
395
396 int mireRegexec(miRE mire, const char * val, size_t vallen)
397 {
398 int rc = 0;
399
400 switch (mire->mode) {
401 case RPMMIRE_STRCMP:
402 /* XXX strcasecmp? strncmp? */
403 rc = strcmp(mire->pattern, val);
404 if (rc) rc = -1;
405 break;
406 case RPMMIRE_DEFAULT:
407 case RPMMIRE_REGEX:
408 /* XXX rpmgrep: ensure that the string is NUL terminated. */
409 if (vallen > 0) {
410 if (val[vallen] != '\0') {
411 char * t = strncpy(alloca(vallen+1), val, vallen);
412 t[vallen] = '\0';
413 val = t;
414 }
415 }
416 /*@-nullpass@*/
417 /* XXX HACK: PCRE returns 2/3 of array, POSIX dimensions regmatch_t. */
418 rc = regexec(mire->preg, val,
419 mire->noffsets/3, (regmatch_t *)mire->offsets, mire->eflags);
420 /*@=nullpass@*/
421 switch (rc) {
422 case 0: rc = 0; /*@innerbreak@*/ break;
423 case REG_NOMATCH: rc = -1;/*@innerbreak@*/ break;
424 default:
425 { char msg[256];
426 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
427 msg[sizeof(msg)-1] = '\0';
428 rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s(%d)\n"),
429 mire->pattern, msg, rc);
430 if (rc < 0) rc -= 1; /* XXX ensure -1 is nomatch. */
431 if (rc > 0) rc = -(rc+1); /* XXX ensure errors are negative. */
432 } /*@innerbreak@*/ break;
433 }
434 break;
435 case RPMMIRE_PCRE:
436 #ifdef WITH_PCRE
437 if (vallen == 0)
438 vallen = strlen(val);
439 rc = pcre_exec(mire->pcre, mire->hints, val, (int)vallen, mire->startoff,
440 mire->eoptions, mire->offsets, mire->noffsets);
441 switch (rc) {
442 case 0: rc = 0; /*@innerbreak@*/ break;
443 case PCRE_ERROR_NOMATCH: rc = -1;/*@innerbreak@*/ break;
444 default:
445 if (_mire_debug && rc < 0)
446 rpmlog(RPMLOG_ERR, _("pcre_exec failed: return %d\n"), rc);
447 /*@innerbreak@*/ break;
448 }
449 #else
450 rc = -99;
451 #endif
452 break;
453 case RPMMIRE_GLOB:
454 rc = fnmatch(mire->pattern, val, mire->fnflags);
455 switch (rc) {
456 case 0: rc = 0; /*@innerbreak@*/ break;
457 case FNM_NOMATCH: rc = -1;/*@innerbreak@*/ break;
458 default:
459 if (_mire_debug)
460 rpmlog(RPMLOG_ERR, _("fnmatch failed: return %d\n"), rc);
461 if (rc < 0) rc -= 1; /* XXX ensure -1 is nomatch. */
462 if (rc > 0) rc = -(rc+1); /* XXX ensure errors are negative. */
463 /*@innerbreak@*/ break;
464 }
465 break;
466 default:
467 rc = -1;
468 break;
469 }
470
471 /*@-modfilesys@*/
472 if (_mire_debug)
473 fprintf(stderr, "--> mireRegexec(%p, %p[%u]) rc %d mode %d \"%.*s\"\n", mire, val, (unsigned)vallen, rc, mire->mode, (int)(vallen < 20 ? vallen : 20), val);
474 /*@=modfilesys@*/
475 return rc;
476 }
477
478 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */
479 int mireAppend(rpmMireMode mode, int tag, const char * pattern,
480 const unsigned char * table, miRE * mirep, int * nmirep)
481 {
482 miRE mire;
483 int xx;
484
485 if (*mirep == NULL) {
486 (*mirep) = mireGetPool(_mirePool);
487 mire = (*mirep);
488 } else {
489 void *use = (*mirep)->_item.use;
490 void *pool = (*mirep)->_item.pool;
491
492 /* XXX only the 1st element in the array has a usage mutex. */
493 (*mirep) = xrealloc((*mirep), ((*nmirep) + 1) * sizeof(*mire));
494 mire = (*mirep) + (*nmirep);
495 memset(mire, 0, sizeof(*mire));
496 /* XXX ensure no segfault, copy the use/pool from 1st item. */
497 /*@-assignexpose@*/
498 mire->_item.use = use;
499 mire->_item.pool = pool;
500 /*@=assignexpose@*/
501 }
502
503 (*nmirep)++;
504 xx = mireSetCOptions(mire, mode, tag, 0, table);
505 /*@-usereleased@*/
506 return mireRegcomp(mire, pattern);
507 /*@=usereleased@*/
508 }
509 /*@=onlytrans@*/
510
511 int mireLoadPatterns(rpmMireMode mode, int tag, const char ** patterns,
512 const unsigned char * table, miRE * mirep, int * nmirep)
513 {
514 const char *pattern;
515 int rc = -1; /* assume failure */
516
517 if (patterns != NULL) /* note rc=0 return with no patterns to load. */
518 while ((pattern = *patterns++) != NULL) {
519 /* XXX pcre_options is not used. should it be? */
520 /* XXX more realloc's than necessary. */
521 int xx = mireAppend(mode, tag, pattern, table, mirep, nmirep);
522 if (xx) {
523 rc = xx;
524 goto exit;
525 }
526 }
527 rc = 0;
528
529 exit:
530 return rc;
531 }
532
533 int mireApply(miRE mire, int nmire, const char *s, size_t slen, int rc)
534 {
535 int i;
536
537 if (slen == 0)
538 slen = strlen(s);
539
540 if (mire)
541 for (i = 0; i < nmire; mire++, i++) {
542 int xx = mireRegexec(mire, s, slen);
543
544 /* Check if excluding or including condition applies. */
545 if (rc < 0 && xx < 0)
546 continue; /* excluding: continue on negative matches. */
547 if (rc > 0 && xx >= 0)
548 continue; /* including: continue on positive matches. */
549 /* Save 1st found termination condition and exit. */
550 rc = xx;
551 break;
552 }
553 return rc;
554 }
555
556 int mireStudy(miRE mire, int nmires)
557 {
558 int rc = -1; /* assume failure */
559 int j;
560
561 /* Study the PCRE regex's, as we will be running them many times */
562 if (mire) /* note rc=0 return with no mire's. */
563 for (j = 0; j < nmires; mire++, j++) {
564 if (mire->mode != RPMMIRE_PCRE)
565 continue;
566 #if defined(WITH_PCRE)
567 { const char * error;
568 mire->hints = pcre_study(mire->pcre, 0, &error);
569 if (error != NULL) {
570 char s[32];
571 if (nmires == 1) s[0] = '\0'; else sprintf(s, _(" number %d"), j);
572 rpmlog(RPMLOG_ERR, _("%s: Error while studying regex%s: %s\n"),
573 __progname, s, error);
574 goto exit;
575 }
576 }
577 #endif
578 }
579 rc = 0;
580
581 #if defined(WITH_PCRE)
582 exit:
583 #endif
584 return rc;
585 }