rpm 5.2.1

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

- File List
- Globals

rpmio/mire.c
Go to the documentation of this file.

    00001
    00004 #include "system.h"
    00005
    00006 #include <rpmiotypes.h>
    00007 #include <rpmio.h>
    00008 #include <rpmlog.h>
    00009
    00010 #define _MIRE_INTERNAL
    00011 #include <mire.h>
    00012
    00013 #include "debug.h"
    00014
    00015 /*@access regex_t @*/
    00016
    00017 /*@unchecked@*/
    00018 int _mire_debug = 0;
    00019
    00020 /*@unchecked@*/
    00021 const unsigned char * _mirePCREtables = NULL;
    00022
    00023 /*@unchecked@*/
    00024 mireEL_t _mireEL = EL_LF;
    00025
    00026 /*@unchecked@*/
    00027 int _mireSTRINGoptions = 0;
    00028
    00029 /*@unchecked@*/
    00030 int _mireGLOBoptions = FNM_EXTMATCH | FNM_PATHNAME | FNM_PERIOD;
    00031
    00032 /*@unchecked@*/
    00033 int _mireREGEXoptions = REG_EXTENDED | REG_NEWLINE;
    00034
    00035 /*@unchecked@*/
    00036 int _mirePCREoptions = 0;
    00037
    00038 int mireClean(miRE mire)
    00039 {
    00040     if (mire == NULL) return 0;
    00041 /*@-modfilesys@*/
    00042 if (_mire_debug)
    00043 fprintf(stderr, "--> mireClean(%p)\n", mire);
    00044 /*@=modfilesys@*/
    00045     mire->pattern = _free(mire->pattern);
    00046     if (mire->mode == RPMMIRE_REGEX) {
    00047         if (mire->preg != NULL) {
    00048             regfree(mire->preg);
    00049             /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
    00050             mire->preg = _free(mire->preg);
    00051             /*@=voidabstract =usereleased @*/
    00052         }
    00053     }
    00054     if (mire->mode == RPMMIRE_PCRE) {   /* TODO: (*pcre_free)(_p) override */
    00055         mire->pcre = _free(mire->pcre);
    00056         mire->hints = _free(mire->hints);
    00057     }
    00058     mire->errmsg = NULL;
    00059     mire->erroff = 0;
    00060     mire->errcode = 0;
    00061     mire->fnflags = 0;
    00062     mire->cflags = 0;
    00063     mire->eflags = 0;
    00064     mire->coptions = 0;
    00065     mire->eoptions = 0;
    00066     mire->notmatch = 0;
    00067     return 0;
    00068 }
    00069
    00070 static void mireFini(void * _mire)
    00071         /*@modifies _mire @*/
    00072 {
    00073     miRE mire = _mire;
    00074     (void) mireClean(mire);
    00075 }
    00076
    00077 /*@unchecked@*/ /*@only@*/ /*@null@*/
    00078 rpmioPool _mirePool;
    00079
    00080 miRE mireGetPool(rpmioPool pool)
    00081 {
    00082     miRE mire;
    00083
    00084     if (_mirePool == NULL) {
    00085         _mirePool = rpmioNewPool("mire", sizeof(*mire), -1, _mire_debug,
    00086                         NULL, NULL, mireFini);
    00087         pool = _mirePool;
    00088     }
    00089     return (miRE) rpmioGetPool(pool, sizeof(*mire));
    00090 }
    00091
    00092 /*@-onlytrans@*/        /* XXX miRE array, not refcounted. */
    00093 void * mireFreeAll(miRE mire, int nmire)
    00094 {
    00095     if (mire != NULL) {
    00096         int i;
    00097         for (i = 0; i < nmire; i++)
    00098             (void) mireClean(mire + i);
    00099         /* XXX rpmgrep doesn't use mire pools yet. retrofit a fix. */
    00100         if (mire->_item.use != NULL && mire->_item.pool != NULL) {
    00101         /* XXX only the 1st element in the array has a usage mutex. */
    00102         mire = xrealloc(mire, sizeof(*mire));
    00103         mire = (miRE)rpmioFreePoolItem((rpmioItem)mire, __FUNCTION__, __FILE__, __LINE__);
    00104         } else
    00105             mire = _free(mire);
    00106     }
    00107     return NULL;
    00108 }
    00109 /*@=onlytrans@*/
    00110
    00111 miRE mireNew(rpmMireMode mode, int tag)
    00112 {
    00113     miRE mire = mireGetPool(_mirePool);
    00114     mire->mode = mode;
    00115     mire->tag = tag;
    00116     return mireLink(mire);
    00117 }
    00118
    00119 int mireSetCOptions(miRE mire, rpmMireMode mode, int tag, int options,
    00120                 const unsigned char * table)
    00121 {
    00122     int rc = 0;
    00123     mire->mode = mode;
    00124     mire->tag = tag;
    00125     switch (mire->mode) {
    00126     case RPMMIRE_DEFAULT:
    00127         break;
    00128     case RPMMIRE_STRCMP:
    00129         /* XXX strcasecmp? */
    00130         break;
    00131     case RPMMIRE_GLOB:
    00132         if (options == 0)
    00133             options = _mireGLOBoptions;
    00134         mire->fnflags = options;
    00135         break;
    00136     case RPMMIRE_REGEX:
    00137         if (options == 0)
    00138             options = _mireREGEXoptions;
    00139         mire->cflags = options;
    00140         break;
    00141     case RPMMIRE_PCRE:
    00142         if (options == 0)
    00143             options = _mirePCREoptions;
    00144         /* XXX check default compile options? */
    00145         mire->coptions = options;
    00146 /*@-assignexpose -temptrans @*/
    00147         mire->table = table;
    00148 /*@=assignexpose =temptrans @*/
    00149         break;
    00150     }
    00151     return rc;
    00152 }
    00153
    00154 int mireSetEOptions(miRE mire, int * offsets, int noffsets)
    00155 {
    00156     int rc = 0;
    00157     if (mire->mode == RPMMIRE_PCRE) {
    00158         mire->startoff = 0;
    00159         mire->eoptions = 0;
    00160 /*@-assignexpose@*/
    00161         mire->offsets = offsets;
    00162 /*@=assignexpose@*/
    00163         mire->noffsets = noffsets;
    00164     } else
    00165     if (mire->mode == RPMMIRE_REGEX) {
    00166         mire->startoff = 0;
    00167         mire->eoptions = 0;
    00168 /*@-assignexpose@*/
    00169         mire->offsets = offsets;
    00170 /*@=assignexpose@*/
    00171         mire->noffsets = noffsets;
    00172     } else
    00173         rc = -1;
    00174
    00175     return rc;
    00176 }
    00177
    00178 int mireSetGOptions(const char * newline, int caseless, int multiline, int utf8)
    00179 {
    00180     int rc = 0;
    00181
    00182     if (caseless) {
    00183 #if defined(PCRE_CASELESS)
    00184         _mirePCREoptions |= PCRE_CASELESS;
    00185 #endif
    00186         _mireREGEXoptions |= REG_ICASE;
    00187 #if defined(FNM_CASEFOLD)
    00188         _mireGLOBoptions |= FNM_CASEFOLD;
    00189 #endif
    00190     } else {
    00191 #if defined(PCRE_CASELESS)
    00192         _mirePCREoptions &= ~PCRE_CASELESS;
    00193 #endif
    00194         _mireREGEXoptions &= ~REG_ICASE;
    00195 #if defined(FNM_CASEFOLD)
    00196         _mireGLOBoptions &= ~FNM_CASEFOLD;
    00197 #endif
    00198     }
    00199
    00200     if (multiline) {
    00201 #if defined(PCRE_MULTILINE)
    00202         _mirePCREoptions |= PCRE_MULTILINE|PCRE_FIRSTLINE;
    00203 #endif
    00204     } else {
    00205 #if defined(PCRE_MULTILINE)
    00206         _mirePCREoptions &= ~(PCRE_MULTILINE|PCRE_FIRSTLINE);
    00207 #endif
    00208     }
    00209
    00210     if (utf8) {
    00211 #if defined(PCRE_UTF8)
    00212         _mirePCREoptions |= PCRE_UTF8;
    00213 #endif
    00214     } else {
    00215 #if defined(PCRE_UTF8)
    00216         _mirePCREoptions &= ~PCRE_UTF8;
    00217 #endif
    00218     }
    00219
    00220     /*
    00221      * Set the default line ending value from the default in the PCRE library;
    00222      * "lf", "cr", "crlf", and "any" are supported. Anything else is treated
    00223      * as "lf".
    00224      */
    00225     if (newline == NULL) {
    00226         int val = 0;
    00227 #if defined(PCRE_CONFIG_NEWLINE)
    00228 /*@-modunconnomods@*/
    00229         (void)pcre_config(PCRE_CONFIG_NEWLINE, &val);
    00230 /*@=modunconnomods@*/
    00231 #endif
    00232         switch (val) {
    00233         default:        newline = "lf";         break;
    00234         case '\r':      newline = "cr";         break;
    00235 /*@-shiftimplementation@*/
    00236         case ('\r' << 8) | '\n': newline = "crlf"; break;
    00237 /*@=shiftimplementation@*/
    00238         case -1:        newline = "any";        break;
    00239         case -2:        newline = "anycrlf";    break;
    00240         }
    00241     }
    00242
    00243     /* Interpret the newline type; the default settings are Unix-like. */
    00244     if (!strcasecmp(newline, "cr")) {
    00245 #if defined(PCRE_NEWLINE_CR)
    00246         _mirePCREoptions |= PCRE_NEWLINE_CR;
    00247 #endif
    00248         _mireEL = EL_CR;
    00249     } else if (!strcasecmp(newline, "lf")) {
    00250 #if defined(PCRE_NEWLINE_LF)
    00251         _mirePCREoptions |= PCRE_NEWLINE_LF;
    00252 #endif
    00253         _mireEL = EL_LF;
    00254     } else if (!strcasecmp(newline, "crlf")) {
    00255 #if defined(PCRE_NEWLINE_CRLF)
    00256         _mirePCREoptions |= PCRE_NEWLINE_CRLF;
    00257 #endif
    00258         _mireEL = EL_CRLF;
    00259     } else if (!strcasecmp(newline, "any")) {
    00260 #if defined(PCRE_NEWLINE_ANY)
    00261         _mirePCREoptions |= PCRE_NEWLINE_ANY;
    00262 #endif
    00263         _mireEL = EL_ANY;
    00264     } else if (!strcasecmp(newline, "anycrlf")) {
    00265 #if defined(PCRE_NEWLINE_ANYCRLF)
    00266         _mirePCREoptions |= PCRE_NEWLINE_ANYCRLF;
    00267 #endif
    00268         _mireEL = EL_ANYCRLF;
    00269     } else {
    00270         rc = -1;
    00271     }
    00272
    00273     return rc;
    00274 }
    00275
    00276 int mireSetLocale(/*@unused@*/ miRE mire, const char * locale)
    00277 {
    00278     const char * locale_from = NULL;
    00279     int rc = -1;        /* assume failure */
    00280
    00281     /* XXX TODO: --locale jiggery-pokery should be done env LC_ALL=C rpmgrep */
    00282     if (locale == NULL) {
    00283         if (locale)
    00284             locale_from = "--locale";
    00285         else {
    00286             /*
    00287              * If a locale has not been provided as an option, see if the
    00288              * LC_CTYPE or LC_ALL environment variable is set, and if so,
    00289              * use it.
    00290              */
    00291 /*@-dependenttrans -observertrans@*/
    00292             if ((locale = getenv("LC_ALL")) != NULL)
    00293                 locale_from = "LC_ALL";
    00294             else if ((locale = getenv("LC_CTYPE")) != NULL)
    00295                 locale_from = "LC_CTYPE";
    00296 /*@=dependenttrans =observertrans@*/
    00297             if (locale)
    00298                 locale = xstrdup(locale);
    00299         }
    00300     }
    00301
    00302     /*
    00303     * If a locale has been provided, set it, and generate the tables PCRE
    00304     * needs. Otherwise, _mirePCREtables == NULL, which uses default tables.
    00305     */
    00306     if (locale != NULL) {
    00307         const char * olocale = setlocale(LC_CTYPE, locale);
    00308         if (olocale == NULL) {
    00309 /*@-modfilesys@*/
    00310             fprintf(stderr,
    00311                 _("%s: Failed to set locale %s (obtained from %s)\n"),
    00312                 __progname, locale, locale_from);
    00313 /*@=modfilesys@*/
    00314             goto exit;
    00315         }
    00316 #if defined(WITH_PCRE)
    00317 /*@-evalorderuncon -onlytrans @*/
    00318         _mirePCREtables = pcre_maketables();
    00319 /*@=evalorderuncon =onlytrans @*/
    00320 #ifdef  NOTYET
    00321         if (setlocale(LC_CTYPE, olocale) == NULL)
    00322             goto exit;
    00323 #endif
    00324 #endif
    00325     }
    00326     rc = 0;
    00327
    00328 exit:
    00329     return rc;
    00330 }
    00331
    00332 int mireRegcomp(miRE mire, const char * pattern)
    00333 {
    00334     int rc = 0;
    00335
    00336     mire->pattern = xstrdup(pattern);
    00337
    00338     switch (mire->mode) {
    00339     case RPMMIRE_STRCMP:
    00340         break;
    00341     case RPMMIRE_PCRE:
    00342 #ifdef  WITH_PCRE
    00343         mire->errcode = 0;
    00344         mire->errmsg = NULL;
    00345         mire->erroff = 0;
    00346         mire->pcre = pcre_compile2(mire->pattern, mire->coptions,
    00347                 &mire->errcode, &mire->errmsg, &mire->erroff, mire->table);
    00348         if (mire->pcre == NULL) {
    00349             if (_mire_debug)
    00350                 rpmlog(RPMLOG_ERR,
    00351                     _("pcre_compile2 failed: %s(%d) at offset %d of \"%s\"\n"),
    00352                     mire->errmsg, mire->errcode, mire->erroff, mire->pattern);
    00353             rc = -1;
    00354             goto exit;  /* XXX HACK: rpmgrep is not expecting mireClean. */
    00355         }
    00356 #else
    00357         rc = -99;
    00358 #endif
    00359         break;
    00360     case RPMMIRE_DEFAULT:
    00361     case RPMMIRE_REGEX:
    00362         mire->preg = xcalloc(1, sizeof(*mire->preg));
    00363         if (mire->cflags == 0)
    00364             mire->cflags = _mireREGEXoptions;
    00365         rc = regcomp(mire->preg, mire->pattern, mire->cflags);
    00366         if (rc) {
    00367             char msg[256];
    00368             (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
    00369             msg[sizeof(msg)-1] = '\0';
    00370             rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n"),
    00371                         mire->pattern, msg);
    00372         }
    00373         break;
    00374     case RPMMIRE_GLOB:
    00375         if (mire->fnflags == 0)
    00376             mire->fnflags = _mireGLOBoptions;
    00377         break;
    00378     default:
    00379         rc = -1;
    00380         break;
    00381     }
    00382
    00383     if (rc)
    00384         (void) mireClean(mire);
    00385
    00386 #ifdef  WITH_PCRE
    00387 exit:
    00388 #endif
    00389 /*@-modfilesys@*/
    00390 if (_mire_debug)
    00391 fprintf(stderr, "--> mireRegcomp(%p, \"%s\") rc %d\n", mire, pattern, rc);
    00392 /*@=modfilesys@*/
    00393     return rc;
    00394 }
    00395
    00396 int mireRegexec(miRE mire, const char * val, size_t vallen)
    00397 {
    00398     int rc = 0;
    00399
    00400     switch (mire->mode) {
    00401     case RPMMIRE_STRCMP:
    00402         /* XXX strcasecmp? strncmp? */
    00403         rc = strcmp(mire->pattern, val);
    00404         if (rc) rc = -1;
    00405         break;
    00406     case RPMMIRE_DEFAULT:
    00407     case RPMMIRE_REGEX:
    00408         /* XXX rpmgrep: ensure that the string is NUL terminated. */
    00409         if (vallen > 0) {
    00410             if (val[vallen] != '\0') {
    00411                 char * t = strncpy(alloca(vallen+1), val, vallen);
    00412                 t[vallen] = '\0';
    00413                 val = t;
    00414             }
    00415         }
    00416 /*@-nullpass@*/
    00417         /* XXX HACK: PCRE returns 2/3 of array, POSIX dimensions regmatch_t. */
    00418         rc = regexec(mire->preg, val,
    00419                 mire->noffsets/3, (regmatch_t *)mire->offsets, mire->eflags);
    00420 /*@=nullpass@*/
    00421         switch (rc) {
    00422         case 0:                 rc = 0; /*@innerbreak@*/ break;
    00423         case REG_NOMATCH:       rc = -1;/*@innerbreak@*/ break;
    00424         default:
    00425           { char msg[256];
    00426             (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
    00427             msg[sizeof(msg)-1] = '\0';
    00428             rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s(%d)\n"),
    00429                         mire->pattern, msg, rc);
    00430             if (rc < 0) rc -= 1;        /* XXX ensure -1 is nomatch. */
    00431             if (rc > 0) rc = -(rc+1);   /* XXX ensure errors are negative. */
    00432           } /*@innerbreak@*/ break;
    00433         }
    00434         break;
    00435     case RPMMIRE_PCRE:
    00436 #ifdef  WITH_PCRE
    00437         if (vallen == 0)
    00438             vallen = strlen(val);
    00439         rc = pcre_exec(mire->pcre, mire->hints, val, (int)vallen, mire->startoff,
    00440                 mire->eoptions, mire->offsets, mire->noffsets);
    00441         switch (rc) {
    00442         case 0:                         rc = 0; /*@innerbreak@*/ break;
    00443         case PCRE_ERROR_NOMATCH:        rc = -1;/*@innerbreak@*/ break;
    00444         default:
    00445             if (_mire_debug && rc < 0)
    00446                 rpmlog(RPMLOG_ERR, _("pcre_exec failed: return %d\n"), rc);
    00447             /*@innerbreak@*/ break;
    00448         }
    00449 #else
    00450         rc = -99;
    00451 #endif
    00452         break;
    00453     case RPMMIRE_GLOB:
    00454         rc = fnmatch(mire->pattern, val, mire->fnflags);
    00455         switch (rc) {
    00456         case 0:                 rc = 0; /*@innerbreak@*/ break;
    00457         case FNM_NOMATCH:       rc = -1;/*@innerbreak@*/ break;
    00458         default:
    00459             if (_mire_debug)
    00460                 rpmlog(RPMLOG_ERR, _("fnmatch failed: return %d\n"), rc);
    00461             if (rc < 0) rc -= 1;        /* XXX ensure -1 is nomatch. */
    00462             if (rc > 0) rc = -(rc+1);   /* XXX ensure errors are negative. */
    00463             /*@innerbreak@*/ break;
    00464         }
    00465         break;
    00466     default:
    00467         rc = -1;
    00468         break;
    00469     }
    00470
    00471 /*@-modfilesys@*/
    00472 if (_mire_debug)
    00473 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);
    00474 /*@=modfilesys@*/
    00475     return rc;
    00476 }
    00477
    00478 /*@-onlytrans@*/        /* XXX miRE array, not refcounted. */
    00479 int mireAppend(rpmMireMode mode, int tag, const char * pattern,
    00480                 const unsigned char * table, miRE * mirep, int * nmirep)
    00481 {
    00482     miRE mire;
    00483     int xx;
    00484
    00485     if (*mirep == NULL) {
    00486         (*mirep) = mireGetPool(_mirePool);
    00487         mire = (*mirep);
    00488     } else {
    00489         void *use =  (*mirep)->_item.use;
    00490         void *pool = (*mirep)->_item.pool;
    00491
    00492         /* XXX only the 1st element in the array has a usage mutex. */
    00493         (*mirep) = xrealloc((*mirep), ((*nmirep) + 1) * sizeof(*mire));
    00494         mire = (*mirep) + (*nmirep);
    00495         memset(mire, 0, sizeof(*mire));
    00496         /* XXX ensure no segfault, copy the use/pool from 1st item. */
    00497 /*@-assignexpose@*/
    00498         mire->_item.use = use;
    00499         mire->_item.pool = pool;
    00500 /*@=assignexpose@*/
    00501     }
    00502
    00503     (*nmirep)++;
    00504     xx = mireSetCOptions(mire, mode, tag, 0, table);
    00505 /*@-usereleased@*/
    00506     return mireRegcomp(mire, pattern);
    00507 /*@=usereleased@*/
    00508 }
    00509 /*@=onlytrans@*/
    00510
    00511 int mireLoadPatterns(rpmMireMode mode, int tag, const char ** patterns,
    00512                 const unsigned char * table, miRE * mirep, int * nmirep)
    00513 {
    00514     const char *pattern;
    00515     int rc = -1;        /* assume failure */
    00516
    00517     if (patterns != NULL)       /* note rc=0 return with no patterns to load. */
    00518     while ((pattern = *patterns++) != NULL) {
    00519         /* XXX pcre_options is not used. should it be? */
    00520         /* XXX more realloc's than necessary. */
    00521         int xx = mireAppend(mode, tag, pattern, table, mirep, nmirep);
    00522         if (xx) {
    00523             rc = xx;
    00524             goto exit;
    00525         }
    00526     }
    00527     rc = 0;
    00528
    00529 exit:
    00530     return rc;
    00531 }
    00532
    00533 int mireApply(miRE mire, int nmire, const char *s, size_t slen, int rc)
    00534 {
    00535     int i;
    00536
    00537     if (slen == 0)
    00538         slen = strlen(s);
    00539
    00540     if (mire)
    00541     for (i = 0; i < nmire; mire++, i++) {
    00542         int xx = mireRegexec(mire, s, slen);
    00543
    00544         /* Check if excluding or including condition applies. */
    00545         if (rc < 0 && xx < 0)
    00546             continue;   /* excluding: continue on negative matches. */
    00547         if (rc > 0 && xx >= 0)
    00548             continue;   /* including: continue on positive matches. */
    00549         /* Save 1st found termination condition and exit. */
    00550         rc = xx;
    00551         break;
    00552     }
    00553     return rc;
    00554 }
    00555
    00556 int mireStudy(miRE mire, int nmires)
    00557 {
    00558     int rc = -1;        /* assume failure */
    00559     int j;
    00560
    00561     /* Study the PCRE regex's, as we will be running them many times */
    00562     if (mire)           /* note rc=0 return with no mire's. */
    00563     for (j = 0; j < nmires; mire++, j++) {
    00564         if (mire->mode != RPMMIRE_PCRE)
    00565             continue;
    00566 #if defined(WITH_PCRE)
    00567       { const char * error;
    00568         mire->hints = pcre_study(mire->pcre, 0, &error);
    00569         if (error != NULL) {
    00570             char s[32];
    00571             if (nmires == 1) s[0] = '\0'; else sprintf(s, _(" number %d"), j);
    00572             rpmlog(RPMLOG_ERR, _("%s: Error while studying regex%s: %s\n"),
    00573                 __progname, s, error);
    00574             goto exit;
    00575         }
    00576       }
    00577 #endif
    00578     }
    00579     rc = 0;
    00580
    00581 #if defined(WITH_PCRE)
    00582 exit:
    00583 #endif
    00584     return rc;
    00585 }