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
00016
00017
00018 int _mire_debug = 0;
00019
00020
00021 const unsigned char * _mirePCREtables = NULL;
00022
00023
00024 mireEL_t _mireEL = EL_LF;
00025
00026
00027 int _mireSTRINGoptions = 0;
00028
00029
00030 int _mireGLOBoptions = FNM_EXTMATCH | FNM_PATHNAME | FNM_PERIOD;
00031
00032
00033 int _mireREGEXoptions = REG_EXTENDED | REG_NEWLINE;
00034
00035
00036 int _mirePCREoptions = 0;
00037
00038 int mireClean(miRE mire)
00039 {
00040 if (mire == NULL) return 0;
00041
00042 if (_mire_debug)
00043 fprintf(stderr, "--> mireClean(%p)\n", mire);
00044
00045 mire->pattern = _free(mire->pattern);
00046 if (mire->mode == RPMMIRE_REGEX) {
00047 if (mire->preg != NULL) {
00048 regfree(mire->preg);
00049
00050 mire->preg = _free(mire->preg);
00051
00052 }
00053 }
00054 if (mire->mode == RPMMIRE_PCRE) {
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
00072 {
00073 miRE mire = _mire;
00074 (void) mireClean(mire);
00075 }
00076
00077
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
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
00100 if (mire->_item.use != NULL && mire->_item.pool != NULL) {
00101
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
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
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
00145 mire->coptions = options;
00146
00147 mire->table = table;
00148
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
00161 mire->offsets = offsets;
00162
00163 mire->noffsets = noffsets;
00164 } else
00165 if (mire->mode == RPMMIRE_REGEX) {
00166 mire->startoff = 0;
00167 mire->eoptions = 0;
00168
00169 mire->offsets = offsets;
00170
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
00222
00223
00224
00225 if (newline == NULL) {
00226 int val = 0;
00227 #if defined(PCRE_CONFIG_NEWLINE)
00228
00229 (void)pcre_config(PCRE_CONFIG_NEWLINE, &val);
00230
00231 #endif
00232 switch (val) {
00233 default: newline = "lf"; break;
00234 case '\r': newline = "cr"; break;
00235
00236 case ('\r' << 8) | '\n': newline = "crlf"; break;
00237
00238 case -1: newline = "any"; break;
00239 case -2: newline = "anycrlf"; break;
00240 }
00241 }
00242
00243
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( miRE mire, const char * locale)
00277 {
00278 const char * locale_from = NULL;
00279 int rc = -1;
00280
00281
00282 if (locale == NULL) {
00283 if (locale)
00284 locale_from = "--locale";
00285 else {
00286
00287
00288
00289
00290
00291
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
00297 if (locale)
00298 locale = xstrdup(locale);
00299 }
00300 }
00301
00302
00303
00304
00305
00306 if (locale != NULL) {
00307 const char * olocale = setlocale(LC_CTYPE, locale);
00308 if (olocale == NULL) {
00309
00310 fprintf(stderr,
00311 _("%s: Failed to set locale %s (obtained from %s)\n"),
00312 __progname, locale, locale_from);
00313
00314 goto exit;
00315 }
00316 #if defined(WITH_PCRE)
00317
00318 _mirePCREtables = pcre_maketables();
00319
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;
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
00390 if (_mire_debug)
00391 fprintf(stderr, "--> mireRegcomp(%p, \"%s\") rc %d\n", mire, pattern, rc);
00392
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
00403 rc = strcmp(mire->pattern, val);
00404 if (rc) rc = -1;
00405 break;
00406 case RPMMIRE_DEFAULT:
00407 case RPMMIRE_REGEX:
00408
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
00417
00418 rc = regexec(mire->preg, val,
00419 mire->noffsets/3, (regmatch_t *)mire->offsets, mire->eflags);
00420
00421 switch (rc) {
00422 case 0: rc = 0; break;
00423 case REG_NOMATCH: rc = -1; 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;
00431 if (rc > 0) rc = -(rc+1);
00432 } 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; break;
00443 case PCRE_ERROR_NOMATCH: rc = -1; break;
00444 default:
00445 if (_mire_debug && rc < 0)
00446 rpmlog(RPMLOG_ERR, _("pcre_exec failed: return %d\n"), rc);
00447 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; break;
00457 case FNM_NOMATCH: rc = -1; break;
00458 default:
00459 if (_mire_debug)
00460 rpmlog(RPMLOG_ERR, _("fnmatch failed: return %d\n"), rc);
00461 if (rc < 0) rc -= 1;
00462 if (rc > 0) rc = -(rc+1);
00463 break;
00464 }
00465 break;
00466 default:
00467 rc = -1;
00468 break;
00469 }
00470
00471
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
00475 return rc;
00476 }
00477
00478
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
00493 (*mirep) = xrealloc((*mirep), ((*nmirep) + 1) * sizeof(*mire));
00494 mire = (*mirep) + (*nmirep);
00495 memset(mire, 0, sizeof(*mire));
00496
00497
00498 mire->_item.use = use;
00499 mire->_item.pool = pool;
00500
00501 }
00502
00503 (*nmirep)++;
00504 xx = mireSetCOptions(mire, mode, tag, 0, table);
00505
00506 return mireRegcomp(mire, pattern);
00507
00508 }
00509
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;
00516
00517 if (patterns != NULL)
00518 while ((pattern = *patterns++) != NULL) {
00519
00520
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
00545 if (rc < 0 && xx < 0)
00546 continue;
00547 if (rc > 0 && xx >= 0)
00548 continue;
00549
00550 rc = xx;
00551 break;
00552 }
00553 return rc;
00554 }
00555
00556 int mireStudy(miRE mire, int nmires)
00557 {
00558 int rc = -1;
00559 int j;
00560
00561
00562 if (mire)
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 }