Annotation of embedaddon/php/ext/ereg/regex/regcomp.c, revision 1.1
1.1 ! misho 1: #include <sys/types.h>
! 2: #include <stdio.h>
! 3: #include <string.h>
! 4: #include <ctype.h>
! 5: #include <limits.h>
! 6: #include <stdlib.h>
! 7:
! 8: #define POSIX_MISTAKE
! 9:
! 10: #include "utils.h"
! 11: #include "regex.h"
! 12: #include "regex2.h"
! 13:
! 14: #include "cclass.h"
! 15: #include "cname.h"
! 16:
! 17: /*
! 18: * parse structure, passed up and down to avoid global variables and
! 19: * other clumsinesses
! 20: */
! 21: struct parse {
! 22: unsigned char *next; /* next character in RE */
! 23: unsigned char *end; /* end of string (-> NUL normally) */
! 24: int error; /* has an error been seen? */
! 25: sop *strip; /* malloced strip */
! 26: sopno ssize; /* malloced strip size (allocated) */
! 27: sopno slen; /* malloced strip length (used) */
! 28: int ncsalloc; /* number of csets allocated */
! 29: struct re_guts *g;
! 30: # define NPAREN 10 /* we need to remember () 1-9 for back refs */
! 31: sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
! 32: sopno pend[NPAREN]; /* -> ) ([0] unused) */
! 33: };
! 34:
! 35: #include "regcomp.ih"
! 36:
! 37: static unsigned char nuls[10]; /* place to point scanner in event of error */
! 38:
! 39: /*
! 40: * macros for use with parse structure
! 41: * BEWARE: these know that the parse structure is named `p' !!!
! 42: */
! 43: #define PEEK() (*p->next)
! 44: #define PEEK2() (*(p->next+1))
! 45: #define MORE() (p->next < p->end)
! 46: #define MORE2() (p->next+1 < p->end)
! 47: #define SEE(c) (MORE() && PEEK() == (c))
! 48: #define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
! 49: #define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
! 50: #define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
! 51: #define NEXT() (p->next++)
! 52: #define NEXT2() (p->next += 2)
! 53: #define NEXTn(n) (p->next += (n))
! 54: #define GETNEXT() (*p->next++)
! 55: #define SETERROR(e) seterr(p, (e))
! 56: #define REQUIRE(co, e) (void) ((co) || SETERROR(e))
! 57: #define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
! 58: #define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
! 59: #define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
! 60: #define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
! 61: #define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
! 62: #define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
! 63: #define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
! 64: #define HERE() (p->slen)
! 65: #define THERE() (p->slen - 1)
! 66: #define THERETHERE() (p->slen - 2)
! 67: #define DROP(n) (p->slen -= (n))
! 68:
! 69: #ifndef NDEBUG
! 70: static int never = 0; /* for use in asserts; shuts lint up */
! 71: #else
! 72: #define never 0 /* some <assert.h>s have bugs too */
! 73: #endif
! 74:
! 75: /*
! 76: - regcomp - interface for parser and compilation
! 77: = API_EXPORT(int) regcomp(regex_t *, const char *, int);
! 78: = #define REG_BASIC 0000
! 79: = #define REG_EXTENDED 0001
! 80: = #define REG_ICASE 0002
! 81: = #define REG_NOSUB 0004
! 82: = #define REG_NEWLINE 0010
! 83: = #define REG_NOSPEC 0020
! 84: = #define REG_PEND 0040
! 85: = #define REG_DUMP 0200
! 86: */
! 87: API_EXPORT(int) /* 0 success, otherwise REG_something */
! 88: regcomp(preg, pattern, cflags)
! 89: regex_t *preg;
! 90: const char *pattern;
! 91: int cflags;
! 92: {
! 93: struct parse pa;
! 94: register struct re_guts *g;
! 95: register struct parse *p = &pa;
! 96: register int i;
! 97: register size_t len;
! 98: #ifdef REDEBUG
! 99: # define GOODFLAGS(f) (f)
! 100: #else
! 101: # define GOODFLAGS(f) ((f)&~REG_DUMP)
! 102: #endif
! 103:
! 104: cflags = GOODFLAGS(cflags);
! 105: if ((cflags®_EXTENDED) && (cflags®_NOSPEC))
! 106: return(REG_INVARG);
! 107:
! 108: if (cflags®_PEND) {
! 109: if (preg->re_endp < pattern)
! 110: return(REG_INVARG);
! 111: len = preg->re_endp - pattern;
! 112: } else
! 113: len = strlen((char *)pattern);
! 114:
! 115: /* do the mallocs early so failure handling is easy */
! 116: g = (struct re_guts *)malloc(sizeof(struct re_guts) +
! 117: (NC-1)*sizeof(cat_t));
! 118: if (g == NULL)
! 119: return(REG_ESPACE);
! 120: p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
! 121: p->strip = (sop *)malloc(p->ssize * sizeof(sop));
! 122: p->slen = 0;
! 123: if (p->strip == NULL) {
! 124: free((char *)g);
! 125: return(REG_ESPACE);
! 126: }
! 127:
! 128: /* set things up */
! 129: p->g = g;
! 130: p->next = (unsigned char *)pattern; /* convenience; we do not modify it */
! 131: p->end = p->next + len;
! 132: p->error = 0;
! 133: p->ncsalloc = 0;
! 134: for (i = 0; i < NPAREN; i++) {
! 135: p->pbegin[i] = 0;
! 136: p->pend[i] = 0;
! 137: }
! 138: g->csetsize = NC;
! 139: g->sets = NULL;
! 140: g->setbits = NULL;
! 141: g->ncsets = 0;
! 142: g->cflags = cflags;
! 143: g->iflags = 0;
! 144: g->nbol = 0;
! 145: g->neol = 0;
! 146: g->must = NULL;
! 147: g->mlen = 0;
! 148: g->nsub = 0;
! 149: g->ncategories = 1; /* category 0 is "everything else" */
! 150: g->categories = &g->catspace[0];
! 151: (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
! 152: g->backrefs = 0;
! 153:
! 154: /* do it */
! 155: EMIT(OEND, 0);
! 156: g->firststate = THERE();
! 157: if (cflags®_EXTENDED)
! 158: p_ere(p, OUT);
! 159: else if (cflags®_NOSPEC)
! 160: p_str(p);
! 161: else
! 162: p_bre(p, OUT, OUT);
! 163: EMIT(OEND, 0);
! 164: g->laststate = THERE();
! 165:
! 166: /* tidy up loose ends and fill things in */
! 167: categorize(p, g);
! 168: stripsnug(p, g);
! 169: findmust(p, g);
! 170: g->nplus = pluscount(p, g);
! 171: g->magic = MAGIC2;
! 172: preg->re_nsub = g->nsub;
! 173: preg->re_g = g;
! 174: preg->re_magic = MAGIC1;
! 175: #ifndef REDEBUG
! 176: /* not debugging, so can't rely on the assert() in regexec() */
! 177: if (g->iflags&BAD)
! 178: SETERROR(REG_ASSERT);
! 179: #endif
! 180:
! 181: /* win or lose, we're done */
! 182: if (p->error != 0) /* lose */
! 183: regfree(preg);
! 184: return(p->error);
! 185: }
! 186:
! 187: /*
! 188: - p_ere - ERE parser top level, concatenation and alternation
! 189: == static void p_ere(register struct parse *p, int stop);
! 190: */
! 191: static void
! 192: p_ere(p, stop)
! 193: register struct parse *p;
! 194: int stop; /* character this ERE should end at */
! 195: {
! 196: register unsigned char c;
! 197: register sopno prevback = 0;
! 198: register sopno prevfwd = 0;
! 199: register sopno conc;
! 200: register int first = 1; /* is this the first alternative? */
! 201:
! 202: for (;;) {
! 203: /* do a bunch of concatenated expressions */
! 204: conc = HERE();
! 205: while (MORE() && (c = PEEK()) != '|' && c != stop)
! 206: p_ere_exp(p);
! 207: (void) REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
! 208:
! 209: if (!EAT('|'))
! 210: break; /* NOTE BREAK OUT */
! 211:
! 212: if (first) {
! 213: INSERT(OCH_, conc); /* offset is wrong */
! 214: prevfwd = conc;
! 215: prevback = conc;
! 216: first = 0;
! 217: }
! 218: ASTERN(OOR1, prevback);
! 219: prevback = THERE();
! 220: AHEAD(prevfwd); /* fix previous offset */
! 221: prevfwd = HERE();
! 222: EMIT(OOR2, 0); /* offset is very wrong */
! 223: }
! 224:
! 225: if (!first) { /* tail-end fixups */
! 226: AHEAD(prevfwd);
! 227: ASTERN(O_CH, prevback);
! 228: }
! 229:
! 230: assert(!MORE() || SEE(stop));
! 231: }
! 232:
! 233: /*
! 234: - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
! 235: == static void p_ere_exp(register struct parse *p);
! 236: */
! 237: static void
! 238: p_ere_exp(p)
! 239: register struct parse *p;
! 240: {
! 241: register unsigned char c;
! 242: register sopno pos;
! 243: register int count;
! 244: register int count2;
! 245: register sopno subno;
! 246: int wascaret = 0;
! 247:
! 248: assert(MORE()); /* caller should have ensured this */
! 249: c = GETNEXT();
! 250:
! 251: pos = HERE();
! 252: switch (c) {
! 253: case '(':
! 254: REQUIRE(MORE(), REG_EPAREN);
! 255: p->g->nsub++;
! 256: subno = p->g->nsub;
! 257: if (subno < NPAREN)
! 258: p->pbegin[subno] = HERE();
! 259: EMIT(OLPAREN, subno);
! 260: if (!SEE(')'))
! 261: p_ere(p, ')');
! 262: if (subno < NPAREN) {
! 263: p->pend[subno] = HERE();
! 264: assert(p->pend[subno] != 0);
! 265: }
! 266: EMIT(ORPAREN, subno);
! 267: MUSTEAT(')', REG_EPAREN);
! 268: break;
! 269: #ifndef POSIX_MISTAKE
! 270: case ')': /* happens only if no current unmatched ( */
! 271: /*
! 272: * You may ask, why the ifndef? Because I didn't notice
! 273: * this until slightly too late for 1003.2, and none of the
! 274: * other 1003.2 regular-expression reviewers noticed it at
! 275: * all. So an unmatched ) is legal POSIX, at least until
! 276: * we can get it fixed.
! 277: */
! 278: SETERROR(REG_EPAREN);
! 279: break;
! 280: #endif
! 281: case '^':
! 282: EMIT(OBOL, 0);
! 283: p->g->iflags |= USEBOL;
! 284: p->g->nbol++;
! 285: wascaret = 1;
! 286: break;
! 287: case '$':
! 288: EMIT(OEOL, 0);
! 289: p->g->iflags |= USEEOL;
! 290: p->g->neol++;
! 291: break;
! 292: case '|':
! 293: SETERROR(REG_EMPTY);
! 294: break;
! 295: case '*':
! 296: case '+':
! 297: case '?':
! 298: SETERROR(REG_BADRPT);
! 299: break;
! 300: case '.':
! 301: if (p->g->cflags®_NEWLINE)
! 302: nonnewline(p);
! 303: else
! 304: EMIT(OANY, 0);
! 305: break;
! 306: case '[':
! 307: p_bracket(p);
! 308: break;
! 309: case '\\':
! 310: REQUIRE(MORE(), REG_EESCAPE);
! 311: c = GETNEXT();
! 312: ordinary(p, c);
! 313: break;
! 314: case '{': /* okay as ordinary except if digit follows */
! 315: REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
! 316: /* FALLTHROUGH */
! 317: default:
! 318: ordinary(p, c);
! 319: break;
! 320: }
! 321:
! 322: if (!MORE())
! 323: return;
! 324: c = PEEK();
! 325: /* we call { a repetition if followed by a digit */
! 326: if (!( c == '*' || c == '+' || c == '?' ||
! 327: (c == '{' && MORE2() && isdigit(PEEK2())) ))
! 328: return; /* no repetition, we're done */
! 329: NEXT();
! 330:
! 331: REQUIRE(!wascaret, REG_BADRPT);
! 332: switch (c) {
! 333: case '*': /* implemented as +? */
! 334: /* this case does not require the (y|) trick, noKLUDGE */
! 335: INSERT(OPLUS_, pos);
! 336: ASTERN(O_PLUS, pos);
! 337: INSERT(OQUEST_, pos);
! 338: ASTERN(O_QUEST, pos);
! 339: break;
! 340: case '+':
! 341: INSERT(OPLUS_, pos);
! 342: ASTERN(O_PLUS, pos);
! 343: break;
! 344: case '?':
! 345: /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
! 346: INSERT(OCH_, pos); /* offset slightly wrong */
! 347: ASTERN(OOR1, pos); /* this one's right */
! 348: AHEAD(pos); /* fix the OCH_ */
! 349: EMIT(OOR2, 0); /* offset very wrong... */
! 350: AHEAD(THERE()); /* ...so fix it */
! 351: ASTERN(O_CH, THERETHERE());
! 352: break;
! 353: case '{':
! 354: count = p_count(p);
! 355: if (EAT(',')) {
! 356: if (isdigit(PEEK())) {
! 357: count2 = p_count(p);
! 358: REQUIRE(count <= count2, REG_BADBR);
! 359: } else /* single number with comma */
! 360: count2 = INFINITY;
! 361: } else /* just a single number */
! 362: count2 = count;
! 363: repeat(p, pos, count, count2);
! 364: if (!EAT('}')) { /* error heuristics */
! 365: while (MORE() && PEEK() != '}')
! 366: NEXT();
! 367: REQUIRE(MORE(), REG_EBRACE);
! 368: SETERROR(REG_BADBR);
! 369: }
! 370: break;
! 371: }
! 372:
! 373: if (!MORE())
! 374: return;
! 375: c = PEEK();
! 376: if (!( c == '*' || c == '+' || c == '?' ||
! 377: (c == '{' && MORE2() && isdigit(PEEK2())) ) )
! 378: return;
! 379: SETERROR(REG_BADRPT);
! 380: }
! 381:
! 382: /*
! 383: - p_str - string (no metacharacters) "parser"
! 384: == static void p_str(register struct parse *p);
! 385: */
! 386: static void
! 387: p_str(p)
! 388: register struct parse *p;
! 389: {
! 390: REQUIRE(MORE(), REG_EMPTY);
! 391: while (MORE())
! 392: ordinary(p, GETNEXT());
! 393: }
! 394:
! 395: /*
! 396: - p_bre - BRE parser top level, anchoring and concatenation
! 397: == static void p_bre(register struct parse *p, register int end1, \
! 398: == register int end2);
! 399: * Giving end1 as OUT essentially eliminates the end1/end2 check.
! 400: *
! 401: * This implementation is a bit of a kludge, in that a trailing $ is first
! 402: * taken as an ordinary character and then revised to be an anchor. The
! 403: * only undesirable side effect is that '$' gets included as a character
! 404: * category in such cases. This is fairly harmless; not worth fixing.
! 405: * The amount of lookahead needed to avoid this kludge is excessive.
! 406: */
! 407: static void
! 408: p_bre(p, end1, end2)
! 409: register struct parse *p;
! 410: register int end1; /* first terminating character */
! 411: register int end2; /* second terminating character */
! 412: {
! 413: register sopno start = HERE();
! 414: register int first = 1; /* first subexpression? */
! 415: register int wasdollar = 0;
! 416:
! 417: if (EAT('^')) {
! 418: EMIT(OBOL, 0);
! 419: p->g->iflags |= USEBOL;
! 420: p->g->nbol++;
! 421: }
! 422: while (MORE() && !SEETWO(end1, end2)) {
! 423: wasdollar = p_simp_re(p, first);
! 424: first = 0;
! 425: }
! 426: if (wasdollar) { /* oops, that was a trailing anchor */
! 427: DROP(1);
! 428: EMIT(OEOL, 0);
! 429: p->g->iflags |= USEEOL;
! 430: p->g->neol++;
! 431: }
! 432:
! 433: REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
! 434: }
! 435:
! 436: /*
! 437: - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
! 438: == static int p_simp_re(register struct parse *p, int starordinary);
! 439: */
! 440: static int /* was the simple RE an unbackslashed $? */
! 441: p_simp_re(p, starordinary)
! 442: register struct parse *p;
! 443: int starordinary; /* is a leading * an ordinary character? */
! 444: {
! 445: register int c;
! 446: register int count;
! 447: register int count2;
! 448: register sopno pos;
! 449: register int i;
! 450: register sopno subno;
! 451: # define BACKSL (1<<CHAR_BIT)
! 452:
! 453: pos = HERE(); /* repetion op, if any, covers from here */
! 454:
! 455: assert(MORE()); /* caller should have ensured this */
! 456: c = GETNEXT();
! 457: if (c == '\\') {
! 458: REQUIRE(MORE(), REG_EESCAPE);
! 459: c = BACKSL | (unsigned char)GETNEXT();
! 460: }
! 461: switch (c) {
! 462: case '.':
! 463: if (p->g->cflags®_NEWLINE)
! 464: nonnewline(p);
! 465: else
! 466: EMIT(OANY, 0);
! 467: break;
! 468: case '[':
! 469: p_bracket(p);
! 470: break;
! 471: case BACKSL|'{':
! 472: SETERROR(REG_BADRPT);
! 473: break;
! 474: case BACKSL|'(':
! 475: p->g->nsub++;
! 476: subno = p->g->nsub;
! 477: if (subno < NPAREN)
! 478: p->pbegin[subno] = HERE();
! 479: EMIT(OLPAREN, subno);
! 480: /* the MORE here is an error heuristic */
! 481: if (MORE() && !SEETWO('\\', ')'))
! 482: p_bre(p, '\\', ')');
! 483: if (subno < NPAREN) {
! 484: p->pend[subno] = HERE();
! 485: assert(p->pend[subno] != 0);
! 486: }
! 487: EMIT(ORPAREN, subno);
! 488: REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
! 489: break;
! 490: case BACKSL|')': /* should not get here -- must be user */
! 491: case BACKSL|'}':
! 492: SETERROR(REG_EPAREN);
! 493: break;
! 494: case BACKSL|'1':
! 495: case BACKSL|'2':
! 496: case BACKSL|'3':
! 497: case BACKSL|'4':
! 498: case BACKSL|'5':
! 499: case BACKSL|'6':
! 500: case BACKSL|'7':
! 501: case BACKSL|'8':
! 502: case BACKSL|'9':
! 503: i = (c&~BACKSL) - '0';
! 504: assert(i < NPAREN);
! 505: if (p->pend[i] != 0) {
! 506: assert(i <= p->g->nsub);
! 507: EMIT(OBACK_, i);
! 508: assert(p->pbegin[i] != 0);
! 509: assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
! 510: assert(OP(p->strip[p->pend[i]]) == ORPAREN);
! 511: (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
! 512: EMIT(O_BACK, i);
! 513: } else
! 514: SETERROR(REG_ESUBREG);
! 515: p->g->backrefs = 1;
! 516: break;
! 517: case '*':
! 518: REQUIRE(starordinary, REG_BADRPT);
! 519: /* FALLTHROUGH */
! 520: default:
! 521: ordinary(p, (unsigned char)c); /* takes off BACKSL, if any */
! 522: break;
! 523: }
! 524:
! 525: if (EAT('*')) { /* implemented as +? */
! 526: /* this case does not require the (y|) trick, noKLUDGE */
! 527: INSERT(OPLUS_, pos);
! 528: ASTERN(O_PLUS, pos);
! 529: INSERT(OQUEST_, pos);
! 530: ASTERN(O_QUEST, pos);
! 531: } else if (EATTWO('\\', '{')) {
! 532: count = p_count(p);
! 533: if (EAT(',')) {
! 534: if (MORE() && isdigit(PEEK())) {
! 535: count2 = p_count(p);
! 536: REQUIRE(count <= count2, REG_BADBR);
! 537: } else /* single number with comma */
! 538: count2 = INFINITY;
! 539: } else /* just a single number */
! 540: count2 = count;
! 541: repeat(p, pos, count, count2);
! 542: if (!EATTWO('\\', '}')) { /* error heuristics */
! 543: while (MORE() && !SEETWO('\\', '}'))
! 544: NEXT();
! 545: REQUIRE(MORE(), REG_EBRACE);
! 546: SETERROR(REG_BADBR);
! 547: }
! 548: } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
! 549: return(1);
! 550:
! 551: return(0);
! 552: }
! 553:
! 554: /*
! 555: - p_count - parse a repetition count
! 556: == static int p_count(register struct parse *p);
! 557: */
! 558: static int /* the value */
! 559: p_count(p)
! 560: register struct parse *p;
! 561: {
! 562: register int count = 0;
! 563: register int ndigits = 0;
! 564:
! 565: while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
! 566: count = count*10 + (GETNEXT() - '0');
! 567: ndigits++;
! 568: }
! 569:
! 570: REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
! 571: return(count);
! 572: }
! 573:
! 574: /*
! 575: - p_bracket - parse a bracketed character list
! 576: == static void p_bracket(register struct parse *p);
! 577: *
! 578: * Note a significant property of this code: if the allocset() did SETERROR,
! 579: * no set operations are done.
! 580: */
! 581: static void
! 582: p_bracket(p)
! 583: register struct parse *p;
! 584: {
! 585: register cset *cs = allocset(p);
! 586: register int invert = 0;
! 587:
! 588: /* Dept of Truly Sickening Special-Case Kludges */
! 589: if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
! 590: EMIT(OBOW, 0);
! 591: NEXTn(6);
! 592: return;
! 593: }
! 594: if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
! 595: EMIT(OEOW, 0);
! 596: NEXTn(6);
! 597: return;
! 598: }
! 599:
! 600: if (EAT('^'))
! 601: invert++; /* make note to invert set at end */
! 602: if (EAT(']'))
! 603: CHadd(cs, ']');
! 604: else if (EAT('-'))
! 605: CHadd(cs, '-');
! 606: while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
! 607: p_b_term(p, cs);
! 608: if (EAT('-'))
! 609: CHadd(cs, '-');
! 610: MUSTEAT(']', REG_EBRACK);
! 611:
! 612: if (p->error != 0) /* don't mess things up further */
! 613: return;
! 614:
! 615: if (p->g->cflags®_ICASE) {
! 616: register int i;
! 617: register int ci;
! 618:
! 619: for (i = p->g->csetsize - 1; i >= 0; i--)
! 620: if (CHIN(cs, i) && isalpha(i)) {
! 621: ci = othercase(i);
! 622: if (ci != i)
! 623: CHadd(cs, ci);
! 624: }
! 625: if (cs->multis != NULL)
! 626: mccase(p, cs);
! 627: }
! 628: if (invert) {
! 629: register int i;
! 630:
! 631: for (i = p->g->csetsize - 1; i >= 0; i--)
! 632: if (CHIN(cs, i))
! 633: CHsub(cs, i);
! 634: else
! 635: CHadd(cs, i);
! 636: if (p->g->cflags®_NEWLINE)
! 637: CHsub(cs, '\n');
! 638: if (cs->multis != NULL)
! 639: mcinvert(p, cs);
! 640: }
! 641:
! 642: assert(cs->multis == NULL); /* xxx */
! 643:
! 644: if (nch(p, cs) == 1) { /* optimize singleton sets */
! 645: ordinary(p, firstch(p, cs));
! 646: freeset(p, cs);
! 647: } else
! 648: EMIT(OANYOF, freezeset(p, cs));
! 649: }
! 650:
! 651: /*
! 652: - p_b_term - parse one term of a bracketed character list
! 653: == static void p_b_term(register struct parse *p, register cset *cs);
! 654: */
! 655: static void
! 656: p_b_term(p, cs)
! 657: register struct parse *p;
! 658: register cset *cs;
! 659: {
! 660: register unsigned char c;
! 661: register unsigned char start, finish;
! 662: register int i;
! 663:
! 664: /* classify what we've got */
! 665: switch ((MORE()) ? PEEK() : '\0') {
! 666: case '[':
! 667: c = (MORE2()) ? PEEK2() : '\0';
! 668: break;
! 669: case '-':
! 670: SETERROR(REG_ERANGE);
! 671: return; /* NOTE RETURN */
! 672: break;
! 673: default:
! 674: c = '\0';
! 675: break;
! 676: }
! 677:
! 678: switch (c) {
! 679: case ':': /* character class */
! 680: NEXT2();
! 681: REQUIRE(MORE(), REG_EBRACK);
! 682: c = PEEK();
! 683: REQUIRE(c != '-' && c != ']', REG_ECTYPE);
! 684: p_b_cclass(p, cs);
! 685: REQUIRE(MORE(), REG_EBRACK);
! 686: REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
! 687: break;
! 688: case '=': /* equivalence class */
! 689: NEXT2();
! 690: REQUIRE(MORE(), REG_EBRACK);
! 691: c = PEEK();
! 692: REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
! 693: p_b_eclass(p, cs);
! 694: REQUIRE(MORE(), REG_EBRACK);
! 695: REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
! 696: break;
! 697: default: /* symbol, ordinary character, or range */
! 698: /* xxx revision needed for multichar stuff */
! 699: start = p_b_symbol(p);
! 700: if (SEE('-') && MORE2() && PEEK2() != ']') {
! 701: /* range */
! 702: NEXT();
! 703: if (EAT('-'))
! 704: finish = '-';
! 705: else
! 706: finish = p_b_symbol(p);
! 707: } else
! 708: finish = start;
! 709: /* xxx what about signed chars here... */
! 710: REQUIRE(start <= finish, REG_ERANGE);
! 711: for (i = start; i <= finish; i++)
! 712: CHadd(cs, i);
! 713: break;
! 714: }
! 715: }
! 716:
! 717: /*
! 718: - p_b_cclass - parse a character-class name and deal with it
! 719: == static void p_b_cclass(register struct parse *p, register cset *cs);
! 720: */
! 721: static void
! 722: p_b_cclass(p, cs)
! 723: register struct parse *p;
! 724: register cset *cs;
! 725: {
! 726: register unsigned char *sp = p->next;
! 727: register const struct cclass *cp;
! 728: register size_t len;
! 729: register const unsigned char *u;
! 730: register unsigned char c;
! 731:
! 732: while (MORE() && isalpha(PEEK()))
! 733: NEXT();
! 734: len = p->next - sp;
! 735: for (cp = cclasses; cp->name != NULL; cp++)
! 736: if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
! 737: break;
! 738: if (cp->name == NULL) {
! 739: /* oops, didn't find it */
! 740: SETERROR(REG_ECTYPE);
! 741: return;
! 742: }
! 743:
! 744: u = cp->chars;
! 745: while ((c = *u++) != '\0')
! 746: CHadd(cs, c);
! 747: for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
! 748: MCadd(p, cs, u);
! 749: }
! 750:
! 751: /*
! 752: - p_b_eclass - parse an equivalence-class name and deal with it
! 753: == static void p_b_eclass(register struct parse *p, register cset *cs);
! 754: *
! 755: * This implementation is incomplete. xxx
! 756: */
! 757: static void
! 758: p_b_eclass(p, cs)
! 759: register struct parse *p;
! 760: register cset *cs;
! 761: {
! 762: register unsigned char c;
! 763:
! 764: c = p_b_coll_elem(p, '=');
! 765: CHadd(cs, c);
! 766: }
! 767:
! 768: /*
! 769: - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
! 770: == static char p_b_symbol(register struct parse *p);
! 771: */
! 772: static unsigned char /* value of symbol */
! 773: p_b_symbol(p)
! 774: register struct parse *p;
! 775: {
! 776: register unsigned char value;
! 777:
! 778: REQUIRE(MORE(), REG_EBRACK);
! 779: if (!EATTWO('[', '.'))
! 780: return(GETNEXT());
! 781:
! 782: /* collating symbol */
! 783: value = p_b_coll_elem(p, '.');
! 784: REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
! 785: return(value);
! 786: }
! 787:
! 788: /*
! 789: - p_b_coll_elem - parse a collating-element name and look it up
! 790: == static char p_b_coll_elem(register struct parse *p, int endc);
! 791: */
! 792: static unsigned char /* value of collating element */
! 793: p_b_coll_elem(p, endc)
! 794: register struct parse *p;
! 795: int endc; /* name ended by endc,']' */
! 796: {
! 797: register unsigned char *sp = p->next;
! 798: register const struct cname *cp;
! 799: register int len;
! 800:
! 801: while (MORE() && !SEETWO(endc, ']'))
! 802: NEXT();
! 803: if (!MORE()) {
! 804: SETERROR(REG_EBRACK);
! 805: return(0);
! 806: }
! 807: len = p->next - sp;
! 808: for (cp = cnames; cp->name != NULL; cp++)
! 809: if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
! 810: return(cp->code); /* known name */
! 811: if (len == 1)
! 812: return(*sp); /* single character */
! 813: SETERROR(REG_ECOLLATE); /* neither */
! 814: return(0);
! 815: }
! 816:
! 817: /*
! 818: - othercase - return the case counterpart of an alphabetic
! 819: == static char othercase(int ch);
! 820: */
! 821: static unsigned char /* if no counterpart, return ch */
! 822: othercase(ch)
! 823: int ch;
! 824: {
! 825: assert(isalpha(ch));
! 826: if (isupper(ch))
! 827: return(tolower(ch));
! 828: else if (islower(ch))
! 829: return(toupper(ch));
! 830: else /* peculiar, but could happen */
! 831: return(ch);
! 832: }
! 833:
! 834: /*
! 835: - bothcases - emit a dualcase version of a two-case character
! 836: == static void bothcases(register struct parse *p, int ch);
! 837: *
! 838: * Boy, is this implementation ever a kludge...
! 839: */
! 840: static void
! 841: bothcases(p, ch)
! 842: register struct parse *p;
! 843: int ch;
! 844: {
! 845: register unsigned char *oldnext = p->next;
! 846: register unsigned char *oldend = p->end;
! 847: unsigned char bracket[3];
! 848:
! 849: assert(othercase(ch) != ch); /* p_bracket() would recurse */
! 850: p->next = bracket;
! 851: p->end = bracket+2;
! 852: bracket[0] = ch;
! 853: bracket[1] = ']';
! 854: bracket[2] = '\0';
! 855: p_bracket(p);
! 856: assert(p->next == bracket+2);
! 857: p->next = oldnext;
! 858: p->end = oldend;
! 859: }
! 860:
! 861: /*
! 862: - ordinary - emit an ordinary character
! 863: == static void ordinary(register struct parse *p, register int ch);
! 864: */
! 865: static void
! 866: ordinary(p, ch)
! 867: register struct parse *p;
! 868: register int ch;
! 869: {
! 870: register cat_t *cap = p->g->categories;
! 871:
! 872: if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch)
! 873: bothcases(p, ch);
! 874: else {
! 875: EMIT(OCHAR, (unsigned char)ch);
! 876: if (cap[ch] == 0)
! 877: cap[ch] = p->g->ncategories++;
! 878: }
! 879: }
! 880:
! 881: /*
! 882: - nonnewline - emit REG_NEWLINE version of OANY
! 883: == static void nonnewline(register struct parse *p);
! 884: *
! 885: * Boy, is this implementation ever a kludge...
! 886: */
! 887: static void
! 888: nonnewline(p)
! 889: register struct parse *p;
! 890: {
! 891: register unsigned char *oldnext = p->next;
! 892: register unsigned char *oldend = p->end;
! 893: unsigned char bracket[4];
! 894:
! 895: p->next = bracket;
! 896: p->end = bracket+3;
! 897: bracket[0] = '^';
! 898: bracket[1] = '\n';
! 899: bracket[2] = ']';
! 900: bracket[3] = '\0';
! 901: p_bracket(p);
! 902: assert(p->next == bracket+3);
! 903: p->next = oldnext;
! 904: p->end = oldend;
! 905: }
! 906:
! 907: /*
! 908: - repeat - generate code for a bounded repetition, recursively if needed
! 909: == static void repeat(register struct parse *p, sopno start, int from, int to);
! 910: */
! 911: static void
! 912: repeat(p, start, from, to)
! 913: register struct parse *p;
! 914: sopno start; /* operand from here to end of strip */
! 915: int from; /* repeated from this number */
! 916: int to; /* to this number of times (maybe INFINITY) */
! 917: {
! 918: register sopno finish = HERE();
! 919: # define N 2
! 920: # define INF 3
! 921: # define REP(f, t) ((f)*8 + (t))
! 922: # define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
! 923: register sopno copy;
! 924:
! 925: if (p->error != 0) /* head off possible runaway recursion */
! 926: return;
! 927:
! 928: assert(from <= to);
! 929:
! 930: switch (REP(MAP(from), MAP(to))) {
! 931: case REP(0, 0): /* must be user doing this */
! 932: DROP(finish-start); /* drop the operand */
! 933: break;
! 934: case REP(0, 1): /* as x{1,1}? */
! 935: case REP(0, N): /* as x{1,n}? */
! 936: case REP(0, INF): /* as x{1,}? */
! 937: /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
! 938: INSERT(OCH_, start); /* offset is wrong... */
! 939: repeat(p, start+1, 1, to);
! 940: ASTERN(OOR1, start);
! 941: AHEAD(start); /* ... fix it */
! 942: EMIT(OOR2, 0);
! 943: AHEAD(THERE());
! 944: ASTERN(O_CH, THERETHERE());
! 945: break;
! 946: case REP(1, 1): /* trivial case */
! 947: /* done */
! 948: break;
! 949: case REP(1, N): /* as x?x{1,n-1} */
! 950: /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
! 951: INSERT(OCH_, start);
! 952: ASTERN(OOR1, start);
! 953: AHEAD(start);
! 954: EMIT(OOR2, 0); /* offset very wrong... */
! 955: AHEAD(THERE()); /* ...so fix it */
! 956: ASTERN(O_CH, THERETHERE());
! 957: copy = dupl(p, start+1, finish+1);
! 958: assert(copy == finish+4);
! 959: repeat(p, copy, 1, to-1);
! 960: break;
! 961: case REP(1, INF): /* as x+ */
! 962: INSERT(OPLUS_, start);
! 963: ASTERN(O_PLUS, start);
! 964: break;
! 965: case REP(N, N): /* as xx{m-1,n-1} */
! 966: copy = dupl(p, start, finish);
! 967: repeat(p, copy, from-1, to-1);
! 968: break;
! 969: case REP(N, INF): /* as xx{n-1,INF} */
! 970: copy = dupl(p, start, finish);
! 971: repeat(p, copy, from-1, to);
! 972: break;
! 973: default: /* "can't happen" */
! 974: SETERROR(REG_ASSERT); /* just in case */
! 975: break;
! 976: }
! 977: }
! 978:
! 979: /*
! 980: - seterr - set an error condition
! 981: == static int seterr(register struct parse *p, int e);
! 982: */
! 983: static int /* useless but makes type checking happy */
! 984: seterr(p, e)
! 985: register struct parse *p;
! 986: int e;
! 987: {
! 988: if (p->error == 0) /* keep earliest error condition */
! 989: p->error = e;
! 990: p->next = nuls; /* try to bring things to a halt */
! 991: p->end = nuls;
! 992: return(0); /* make the return value well-defined */
! 993: }
! 994:
! 995: /*
! 996: - allocset - allocate a set of characters for []
! 997: == static cset *allocset(register struct parse *p);
! 998: */
! 999: static cset *
! 1000: allocset(p)
! 1001: register struct parse *p;
! 1002: {
! 1003: register int no = p->g->ncsets++;
! 1004: register size_t nc;
! 1005: register size_t nbytes;
! 1006: register cset *cs;
! 1007: register size_t css = (size_t)p->g->csetsize;
! 1008: register int i;
! 1009:
! 1010: if (no >= p->ncsalloc) { /* need another column of space */
! 1011: p->ncsalloc += CHAR_BIT;
! 1012: nc = p->ncsalloc;
! 1013: assert(nc % CHAR_BIT == 0);
! 1014: nbytes = nc / CHAR_BIT * css;
! 1015: if (p->g->sets == NULL)
! 1016: p->g->sets = (cset *)malloc(nc * sizeof(cset));
! 1017: else
! 1018: p->g->sets = (cset *)realloc((unsigned char *)p->g->sets,
! 1019: nc * sizeof(cset));
! 1020: if (p->g->setbits == NULL)
! 1021: p->g->setbits = (uch *)malloc(nbytes);
! 1022: else {
! 1023: p->g->setbits = (uch *)realloc((unsigned char *)p->g->setbits,
! 1024: nbytes);
! 1025: /* xxx this isn't right if setbits is now NULL */
! 1026: for (i = 0; i < no; i++)
! 1027: p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
! 1028: }
! 1029: if (p->g->sets != NULL && p->g->setbits != NULL)
! 1030: (void) memset((unsigned char *)p->g->setbits + (nbytes - css),
! 1031: 0, css);
! 1032: else {
! 1033: no = 0;
! 1034: SETERROR(REG_ESPACE);
! 1035: /* caller's responsibility not to do set ops */
! 1036: }
! 1037: }
! 1038:
! 1039: assert(p->g->sets != NULL); /* xxx */
! 1040: cs = &p->g->sets[no];
! 1041: cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
! 1042: cs->mask = 1 << ((no) % CHAR_BIT);
! 1043: cs->hash = 0;
! 1044: cs->smultis = 0;
! 1045: cs->multis = NULL;
! 1046:
! 1047: return(cs);
! 1048: }
! 1049:
! 1050: /*
! 1051: - freeset - free a now-unused set
! 1052: == static void freeset(register struct parse *p, register cset *cs);
! 1053: */
! 1054: static void
! 1055: freeset(p, cs)
! 1056: register struct parse *p;
! 1057: register cset *cs;
! 1058: {
! 1059: register size_t i;
! 1060: register cset *top = &p->g->sets[p->g->ncsets];
! 1061: register size_t css = (size_t)p->g->csetsize;
! 1062:
! 1063: for (i = 0; i < css; i++)
! 1064: CHsub(cs, i);
! 1065: if (cs == top-1) /* recover only the easy case */
! 1066: p->g->ncsets--;
! 1067: }
! 1068:
! 1069: /*
! 1070: - freezeset - final processing on a set of characters
! 1071: == static int freezeset(register struct parse *p, register cset *cs);
! 1072: *
! 1073: * The main task here is merging identical sets. This is usually a waste
! 1074: * of time (although the hash code minimizes the overhead), but can win
! 1075: * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
! 1076: * is done using addition rather than xor -- all ASCII [aA] sets xor to
! 1077: * the same value!
! 1078: */
! 1079: static int /* set number */
! 1080: freezeset(p, cs)
! 1081: register struct parse *p;
! 1082: register cset *cs;
! 1083: {
! 1084: register uch h = cs->hash;
! 1085: register size_t i;
! 1086: register cset *top = &p->g->sets[p->g->ncsets];
! 1087: register cset *cs2;
! 1088: register size_t css = (size_t)p->g->csetsize;
! 1089:
! 1090: /* look for an earlier one which is the same */
! 1091: for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
! 1092: if (cs2->hash == h && cs2 != cs) {
! 1093: /* maybe */
! 1094: for (i = 0; i < css; i++)
! 1095: if (!!CHIN(cs2, i) != !!CHIN(cs, i))
! 1096: break; /* no */
! 1097: if (i == css)
! 1098: break; /* yes */
! 1099: }
! 1100:
! 1101: if (cs2 < top) { /* found one */
! 1102: freeset(p, cs);
! 1103: cs = cs2;
! 1104: }
! 1105:
! 1106: return((int)(cs - p->g->sets));
! 1107: }
! 1108:
! 1109: /*
! 1110: - firstch - return first character in a set (which must have at least one)
! 1111: == static int firstch(register struct parse *p, register cset *cs);
! 1112: */
! 1113: static int /* character; there is no "none" value */
! 1114: firstch(p, cs)
! 1115: register struct parse *p;
! 1116: register cset *cs;
! 1117: {
! 1118: register size_t i;
! 1119: register size_t css = (size_t)p->g->csetsize;
! 1120:
! 1121: for (i = 0; i < css; i++)
! 1122: if (CHIN(cs, i))
! 1123: return((unsigned char)i);
! 1124: assert(never);
! 1125: return(0); /* arbitrary */
! 1126: }
! 1127:
! 1128: /*
! 1129: - nch - number of characters in a set
! 1130: == static int nch(register struct parse *p, register cset *cs);
! 1131: */
! 1132: static int
! 1133: nch(p, cs)
! 1134: register struct parse *p;
! 1135: register cset *cs;
! 1136: {
! 1137: register size_t i;
! 1138: register size_t css = (size_t)p->g->csetsize;
! 1139: register int n = 0;
! 1140:
! 1141: for (i = 0; i < css; i++)
! 1142: if (CHIN(cs, i))
! 1143: n++;
! 1144: return(n);
! 1145: }
! 1146:
! 1147: /*
! 1148: - mcadd - add a collating element to a cset
! 1149: == static void mcadd(register struct parse *p, register cset *cs, \
! 1150: == register char *cp);
! 1151: */
! 1152: static void
! 1153: mcadd(p, cs, cp)
! 1154: register struct parse *p;
! 1155: register cset *cs;
! 1156: register const unsigned char *cp;
! 1157: {
! 1158: register size_t oldend = cs->smultis;
! 1159:
! 1160: cs->smultis += strlen(cp) + 1;
! 1161: if (cs->multis == NULL)
! 1162: cs->multis = malloc(cs->smultis);
! 1163: else
! 1164: cs->multis = realloc(cs->multis, cs->smultis);
! 1165: if (cs->multis == NULL) {
! 1166: SETERROR(REG_ESPACE);
! 1167: return;
! 1168: }
! 1169:
! 1170: (void) strcpy(cs->multis + oldend - 1, cp);
! 1171: cs->multis[cs->smultis - 1] = '\0';
! 1172: }
! 1173:
! 1174: #if 0
! 1175: /*
! 1176: - mcsub - subtract a collating element from a cset
! 1177: == static void mcsub(register cset *cs, register unsigned char *cp);
! 1178: */
! 1179: static void
! 1180: mcsub(cs, cp)
! 1181: register unsigned cset *cs;
! 1182: register unsigned char *cp;
! 1183: {
! 1184: register unsigned char *fp = mcfind(cs, cp);
! 1185: register size_t len = strlen(fp);
! 1186:
! 1187: assert(fp != NULL);
! 1188: (void) memmove(fp, fp + len + 1,
! 1189: cs->smultis - (fp + len + 1 - cs->multis));
! 1190: cs->smultis -= len;
! 1191:
! 1192: if (cs->smultis == 0) {
! 1193: free(cs->multis);
! 1194: cs->multis = NULL;
! 1195: return;
! 1196: }
! 1197:
! 1198: cs->multis = realloc(cs->multis, cs->smultis);
! 1199: assert(cs->multis != NULL);
! 1200: }
! 1201:
! 1202: /*
! 1203: - mcin - is a collating element in a cset?
! 1204: == static int mcin(register cset *cs, register unsigned char *cp);
! 1205: */
! 1206: static int
! 1207: mcin(cs, cp)
! 1208: register cset *cs;
! 1209: register unsigned char *cp;
! 1210: {
! 1211: return(mcfind(cs, cp) != NULL);
! 1212: }
! 1213:
! 1214:
! 1215: /*
! 1216: - mcfind - find a collating element in a cset
! 1217: == static unsigned char *mcfind(register cset *cs, register unsigned char *cp);
! 1218: */
! 1219: static unsigned char *
! 1220: mcfind(cs, cp)
! 1221: register cset *cs;
! 1222: register unsigned char *cp;
! 1223: {
! 1224: register unsigned char *p;
! 1225:
! 1226: if (cs->multis == NULL)
! 1227: return(NULL);
! 1228: for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
! 1229: if (strcmp(cp, p) == 0)
! 1230: return(p);
! 1231: return(NULL);
! 1232: }
! 1233: #endif
! 1234:
! 1235: /*
! 1236: - mcinvert - invert the list of collating elements in a cset
! 1237: == static void mcinvert(register struct parse *p, register cset *cs);
! 1238: *
! 1239: * This would have to know the set of possibilities. Implementation
! 1240: * is deferred.
! 1241: */
! 1242: static void
! 1243: mcinvert(p, cs)
! 1244: register struct parse *p;
! 1245: register cset *cs;
! 1246: {
! 1247: assert(cs->multis == NULL); /* xxx */
! 1248: }
! 1249:
! 1250: /*
! 1251: - mccase - add case counterparts of the list of collating elements in a cset
! 1252: == static void mccase(register struct parse *p, register cset *cs);
! 1253: *
! 1254: * This would have to know the set of possibilities. Implementation
! 1255: * is deferred.
! 1256: */
! 1257: static void
! 1258: mccase(p, cs)
! 1259: register struct parse *p;
! 1260: register cset *cs;
! 1261: {
! 1262: assert(cs->multis == NULL); /* xxx */
! 1263: }
! 1264:
! 1265: /*
! 1266: - isinsets - is this character in any sets?
! 1267: == static int isinsets(register struct re_guts *g, int c);
! 1268: */
! 1269: static int /* predicate */
! 1270: isinsets(g, c)
! 1271: register struct re_guts *g;
! 1272: int c;
! 1273: {
! 1274: register uch *col;
! 1275: register int i;
! 1276: register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
! 1277: register unsigned uc = (unsigned char)c;
! 1278:
! 1279: for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
! 1280: if (col[uc] != 0)
! 1281: return(1);
! 1282: return(0);
! 1283: }
! 1284:
! 1285: /*
! 1286: - samesets - are these two characters in exactly the same sets?
! 1287: == static int samesets(register struct re_guts *g, int c1, int c2);
! 1288: */
! 1289: static int /* predicate */
! 1290: samesets(g, c1, c2)
! 1291: register struct re_guts *g;
! 1292: int c1;
! 1293: int c2;
! 1294: {
! 1295: register uch *col;
! 1296: register int i;
! 1297: register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
! 1298: register unsigned uc1 = (unsigned char)c1;
! 1299: register unsigned uc2 = (unsigned char)c2;
! 1300:
! 1301: for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
! 1302: if (col[uc1] != col[uc2])
! 1303: return(0);
! 1304: return(1);
! 1305: }
! 1306:
! 1307: /*
! 1308: - categorize - sort out character categories
! 1309: == static void categorize(struct parse *p, register struct re_guts *g);
! 1310: */
! 1311: static void
! 1312: categorize(p, g)
! 1313: struct parse *p;
! 1314: register struct re_guts *g;
! 1315: {
! 1316: register cat_t *cats = g->categories;
! 1317: register int c;
! 1318: register int c2;
! 1319: register cat_t cat;
! 1320:
! 1321: /* avoid making error situations worse */
! 1322: if (p->error != 0)
! 1323: return;
! 1324:
! 1325: for (c = 0; c <= UCHAR_MAX; c++)
! 1326: if (cats[c] == 0 && isinsets(g, c)) {
! 1327: cat = g->ncategories++;
! 1328: cats[c] = cat;
! 1329: for (c2 = c+1; c2 <= UCHAR_MAX; c2++)
! 1330: if (cats[c2] == 0 && samesets(g, c, c2))
! 1331: cats[c2] = cat;
! 1332: }
! 1333: }
! 1334:
! 1335: /*
! 1336: - dupl - emit a duplicate of a bunch of sops
! 1337: == static sopno dupl(register struct parse *p, sopno start, sopno finish);
! 1338: */
! 1339: static sopno /* start of duplicate */
! 1340: dupl(p, start, finish)
! 1341: register struct parse *p;
! 1342: sopno start; /* from here */
! 1343: sopno finish; /* to this less one */
! 1344: {
! 1345: register sopno ret = HERE();
! 1346: register sopno len = finish - start;
! 1347:
! 1348: assert(finish >= start);
! 1349: if (len == 0)
! 1350: return(ret);
! 1351: enlarge(p, p->ssize + len); /* this many unexpected additions */
! 1352: assert(p->ssize >= p->slen + len);
! 1353: (void) memcpy((char *)(p->strip + p->slen),
! 1354: (char *)(p->strip + start), (size_t)len*sizeof(sop));
! 1355: p->slen += len;
! 1356: return(ret);
! 1357: }
! 1358:
! 1359: /*
! 1360: - doemit - emit a strip operator
! 1361: == static void doemit(register struct parse *p, sop op, size_t opnd);
! 1362: *
! 1363: * It might seem better to implement this as a macro with a function as
! 1364: * hard-case backup, but it's just too big and messy unless there are
! 1365: * some changes to the data structures. Maybe later.
! 1366: */
! 1367: static void
! 1368: doemit(p, op, opnd)
! 1369: register struct parse *p;
! 1370: sop op;
! 1371: size_t opnd;
! 1372: {
! 1373: /* avoid making error situations worse */
! 1374: if (p->error != 0)
! 1375: return;
! 1376:
! 1377: /* deal with oversize operands ("can't happen", more or less) */
! 1378: assert(opnd < 1<<OPSHIFT);
! 1379:
! 1380: /* deal with undersized strip */
! 1381: if (p->slen >= p->ssize)
! 1382: enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
! 1383: assert(p->slen < p->ssize);
! 1384:
! 1385: /* finally, it's all reduced to the easy case */
! 1386: p->strip[p->slen++] = SOP(op, opnd);
! 1387: }
! 1388:
! 1389: /*
! 1390: - doinsert - insert a sop into the strip
! 1391: == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
! 1392: */
! 1393: static void
! 1394: doinsert(p, op, opnd, pos)
! 1395: register struct parse *p;
! 1396: sop op;
! 1397: size_t opnd;
! 1398: sopno pos;
! 1399: {
! 1400: register sopno sn;
! 1401: register sop s;
! 1402: register int i;
! 1403:
! 1404: /* avoid making error situations worse */
! 1405: if (p->error != 0)
! 1406: return;
! 1407:
! 1408: sn = HERE();
! 1409: EMIT(op, opnd); /* do checks, ensure space */
! 1410: assert(HERE() == sn+1);
! 1411: s = p->strip[sn];
! 1412:
! 1413: /* adjust paren pointers */
! 1414: assert(pos > 0);
! 1415: for (i = 1; i < NPAREN; i++) {
! 1416: if (p->pbegin[i] >= pos) {
! 1417: p->pbegin[i]++;
! 1418: }
! 1419: if (p->pend[i] >= pos) {
! 1420: p->pend[i]++;
! 1421: }
! 1422: }
! 1423:
! 1424: memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
! 1425: (HERE()-pos-1)*sizeof(sop));
! 1426: p->strip[pos] = s;
! 1427: }
! 1428:
! 1429: /*
! 1430: - dofwd - complete a forward reference
! 1431: == static void dofwd(register struct parse *p, sopno pos, sop value);
! 1432: */
! 1433: static void
! 1434: dofwd(p, pos, value)
! 1435: register struct parse *p;
! 1436: register sopno pos;
! 1437: sop value;
! 1438: {
! 1439: /* avoid making error situations worse */
! 1440: if (p->error != 0)
! 1441: return;
! 1442:
! 1443: assert(value < 1<<OPSHIFT);
! 1444: p->strip[pos] = OP(p->strip[pos]) | value;
! 1445: }
! 1446:
! 1447: /*
! 1448: - enlarge - enlarge the strip
! 1449: == static void enlarge(register struct parse *p, sopno size);
! 1450: */
! 1451: static void
! 1452: enlarge(p, size)
! 1453: register struct parse *p;
! 1454: register sopno size;
! 1455: {
! 1456: register sop *sp;
! 1457:
! 1458: if (p->ssize >= size)
! 1459: return;
! 1460:
! 1461: sp = (sop *)realloc(p->strip, size*sizeof(sop));
! 1462: if (sp == NULL) {
! 1463: SETERROR(REG_ESPACE);
! 1464: return;
! 1465: }
! 1466: p->strip = sp;
! 1467: p->ssize = size;
! 1468: }
! 1469:
! 1470: /*
! 1471: - stripsnug - compact the strip
! 1472: == static void stripsnug(register struct parse *p, register struct re_guts *g);
! 1473: */
! 1474: static void
! 1475: stripsnug(p, g)
! 1476: register struct parse *p;
! 1477: register struct re_guts *g;
! 1478: {
! 1479: g->nstates = p->slen;
! 1480: g->strip = (sop *)realloc((unsigned char *)p->strip, p->slen * sizeof(sop));
! 1481: if (g->strip == NULL) {
! 1482: SETERROR(REG_ESPACE);
! 1483: g->strip = p->strip;
! 1484: }
! 1485: }
! 1486:
! 1487: /*
! 1488: - findmust - fill in must and mlen with longest mandatory literal string
! 1489: == static void findmust(register struct parse *p, register struct re_guts *g);
! 1490: *
! 1491: * This algorithm could do fancy things like analyzing the operands of |
! 1492: * for common subsequences. Someday. This code is simple and finds most
! 1493: * of the interesting cases.
! 1494: *
! 1495: * Note that must and mlen got initialized during setup.
! 1496: */
! 1497: static void
! 1498: findmust(p, g)
! 1499: struct parse *p;
! 1500: register struct re_guts *g;
! 1501: {
! 1502: register sop *scan;
! 1503: sop *start = NULL;
! 1504: register sop *newstart = NULL;
! 1505: register sopno newlen;
! 1506: register sop s;
! 1507: register unsigned char *cp;
! 1508: register sopno i;
! 1509:
! 1510: /* avoid making error situations worse */
! 1511: if (p->error != 0)
! 1512: return;
! 1513:
! 1514: /* find the longest OCHAR sequence in strip */
! 1515: newlen = 0;
! 1516: scan = g->strip + 1;
! 1517: do {
! 1518: s = *scan++;
! 1519: switch (OP(s)) {
! 1520: case OCHAR: /* sequence member */
! 1521: if (newlen == 0) /* new sequence */
! 1522: newstart = scan - 1;
! 1523: newlen++;
! 1524: break;
! 1525: case OPLUS_: /* things that don't break one */
! 1526: case OLPAREN:
! 1527: case ORPAREN:
! 1528: break;
! 1529: case OQUEST_: /* things that must be skipped */
! 1530: case OCH_:
! 1531: scan--;
! 1532: do {
! 1533: scan += OPND(s);
! 1534: s = *scan;
! 1535: /* assert() interferes w debug printouts */
! 1536: if (OP(s) != O_QUEST && OP(s) != O_CH &&
! 1537: OP(s) != OOR2) {
! 1538: g->iflags |= BAD;
! 1539: return;
! 1540: }
! 1541: } while (OP(s) != O_QUEST && OP(s) != O_CH);
! 1542: /* fallthrough */
! 1543: default: /* things that break a sequence */
! 1544: if (newlen > g->mlen) { /* ends one */
! 1545: start = newstart;
! 1546: g->mlen = newlen;
! 1547: }
! 1548: newlen = 0;
! 1549: break;
! 1550: }
! 1551: } while (OP(s) != OEND);
! 1552:
! 1553: if (g->mlen == 0) /* there isn't one */
! 1554: return;
! 1555:
! 1556: if (!start) {
! 1557: g->mlen = 0;
! 1558: return;
! 1559: }
! 1560:
! 1561: /* turn it into a character string */
! 1562: g->must = malloc((size_t)g->mlen + 1);
! 1563: if (g->must == NULL) { /* argh; just forget it */
! 1564: g->mlen = 0;
! 1565: return;
! 1566: }
! 1567: cp = g->must;
! 1568: scan = start;
! 1569: for (i = g->mlen; i > 0; i--) {
! 1570: while (OP(s = *scan++) != OCHAR)
! 1571: continue;
! 1572: assert(cp < g->must + g->mlen);
! 1573: *cp++ = (unsigned char)OPND(s);
! 1574: }
! 1575: assert(cp == g->must + g->mlen);
! 1576: *cp++ = '\0'; /* just on general principles */
! 1577: }
! 1578:
! 1579: /*
! 1580: - pluscount - count + nesting
! 1581: == static sopno pluscount(register struct parse *p, register struct re_guts *g);
! 1582: */
! 1583: static sopno /* nesting depth */
! 1584: pluscount(p, g)
! 1585: struct parse *p;
! 1586: register struct re_guts *g;
! 1587: {
! 1588: register sop *scan;
! 1589: register sop s;
! 1590: register sopno plusnest = 0;
! 1591: register sopno maxnest = 0;
! 1592:
! 1593: if (p->error != 0)
! 1594: return(0); /* there may not be an OEND */
! 1595:
! 1596: scan = g->strip + 1;
! 1597: do {
! 1598: s = *scan++;
! 1599: switch (OP(s)) {
! 1600: case OPLUS_:
! 1601: plusnest++;
! 1602: break;
! 1603: case O_PLUS:
! 1604: if (plusnest > maxnest)
! 1605: maxnest = plusnest;
! 1606: plusnest--;
! 1607: break;
! 1608: }
! 1609: } while (OP(s) != OEND);
! 1610: if (plusnest != 0)
! 1611: g->iflags |= BAD;
! 1612: return(maxnest);
! 1613: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>