Home | History | Annotate | Line # | Download | only in dist
      1 /****************************************************************
      2 Copyright (C) Lucent Technologies 1997
      3 All Rights Reserved
      4 
      5 Permission to use, copy, modify, and distribute this software and
      6 its documentation for any purpose and without fee is hereby
      7 granted, provided that the above copyright notice appear in all
      8 copies and that both that the copyright notice and this
      9 permission notice and warranty disclaimer appear in supporting
     10 documentation, and that the name Lucent Technologies or any of
     11 its entities not be used in advertising or publicity pertaining
     12 to distribution of the software without specific, written prior
     13 permission.
     14 
     15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
     18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     22 THIS SOFTWARE.
     23 ****************************************************************/
     24 
     25 /* lasciate ogne speranza, voi ch'intrate. */
     26 
     27 #if HAVE_NBTOOL_CONFIG_H
     28 #include "nbtool_config.h"
     29 #endif
     30 
     31 #define	DEBUG
     32 
     33 #include <ctype.h>
     34 #include <limits.h>
     35 #include <stdio.h>
     36 #include <string.h>
     37 #include <stdlib.h>
     38 #include "awk.h"
     39 #include "awkgram.h"
     40 
     41 #define MAXLIN 22
     42 
     43 #define type(v)		(v)->nobj	/* badly overloaded here */
     44 #define info(v)		(v)->ntype	/* badly overloaded here */
     45 #define left(v)		(v)->narg[0]
     46 #define right(v)	(v)->narg[1]
     47 #define parent(v)	(v)->nnext
     48 
     49 #define LEAF	case CCL: case NCCL: case CHAR: case DOT: case FINAL: case ALL:
     50 #define ELEAF	case EMPTYRE:		/* empty string in regexp */
     51 #define UNARY	case STAR: case PLUS: case QUEST:
     52 
     53 /* encoding in tree Nodes:
     54 	leaf (CCL, NCCL, CHAR, DOT, FINAL, ALL, EMPTYRE):
     55 		left is index, right contains value or pointer to value
     56 	unary (STAR, PLUS, QUEST): left is child, right is null
     57 	binary (CAT, OR): left and right are children
     58 	parent contains pointer to parent
     59 */
     60 
     61 
     62 int	*setvec;
     63 int	*tmpset;
     64 int	maxsetvec = 0;
     65 
     66 int	rtok;		/* next token in current re */
     67 int	rlxval;
     68 static const uschar	*rlxstr;
     69 static const uschar	*prestr;	/* current position in current re */
     70 static const uschar	*lastre;	/* origin of last re */
     71 static const uschar	*lastatom;	/* origin of last Atom */
     72 static const uschar	*starttok;
     73 static const uschar 	*basestr;	/* starts with original, replaced during
     74 				   repetition processing */
     75 static const uschar 	*firstbasestr;
     76 
     77 static	int setcnt;
     78 static	int poscnt;
     79 
     80 const char	*patbeg;
     81 int	patlen;
     82 
     83 #define	NFA	128	/* cache this many dynamic fa's */
     84 fa	*fatab[NFA];
     85 int	nfatab	= 0;	/* entries in fatab */
     86 
     87 /* utf-8 mechanism:
     88 
     89    For most of Awk, utf-8 strings just "work", since they look like
     90    null-terminated sequences of 8-bit bytes.
     91 
     92    Functions like length(), index(), and substr() have to operate
     93    in units of utf-8 characters.  The u8_* functions in run.c
     94    handle this.
     95 
     96    Regular expressions are more complicated, since the basic
     97    mechanism of the goto table used 8-bit byte indices into the
     98    gototab entries to compute the next state.  Unicode is a lot
     99    bigger, so the gototab entries are now structs with a character
    100    and a next state. These are sorted by code point and binary
    101    searched.
    102 
    103    Throughout the RE mechanism in b.c, utf-8 characters are
    104    converted to their utf-32 value.  This mostly shows up in
    105    cclenter, which expands character class ranges like a-z and now
    106    alpha-omega.  The size of a gototab array is still about 256.
    107    This should be dynamic, but for now things work ok for a single
    108    code page of Unicode, which is the most likely case.
    109 
    110    The code changes are localized in run.c and b.c.  I have added a
    111    handful of functions to somewhat better hide the implementation,
    112    but a lot more could be done.
    113 
    114  */
    115 
    116 static int entry_cmp(const void *l, const void *r);
    117 static int get_gototab(fa*, int, int);
    118 static int set_gototab(fa*, int, int, int);
    119 static void clear_gototab(fa*, int);
    120 
    121 static int *
    122 intalloc(size_t n, const char *f)
    123 {
    124 	int *p = (int *) calloc(n, sizeof(int));
    125 	if (p == NULL)
    126 		overflo(f);
    127 	return p;
    128 }
    129 
    130 static void
    131 resizesetvec(const char *f)
    132 {
    133 	if (maxsetvec == 0)
    134 		maxsetvec = MAXLIN;
    135 	else
    136 		maxsetvec *= 4;
    137 	setvec = (int *) realloc(setvec, maxsetvec * sizeof(*setvec));
    138 	tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(*tmpset));
    139 	if (setvec == NULL || tmpset == NULL)
    140 		overflo(f);
    141 }
    142 
    143 static void
    144 resize_state(fa *f, int state)
    145 {
    146 	gtt *p;
    147 	uschar *p2;
    148 	int **p3;
    149 	int i, new_count;
    150 
    151 	if (++state < f->state_count)
    152 		return;
    153 
    154 	new_count = state + 10; /* needs to be tuned */
    155 
    156 	p = (gtt *) realloc(f->gototab, new_count * sizeof(gtt));
    157 	if (p == NULL)
    158 		goto out;
    159 	f->gototab = p;
    160 
    161 	p2 = (uschar *) realloc(f->out, new_count * sizeof(f->out[0]));
    162 	if (p2 == NULL)
    163 		goto out;
    164 	f->out = p2;
    165 
    166 	p3 = (int **) realloc(f->posns, new_count * sizeof(f->posns[0]));
    167 	if (p3 == NULL)
    168 		goto out;
    169 	f->posns = p3;
    170 
    171 	for (i = f->state_count; i < new_count; ++i) {
    172 		f->gototab[i].entries = (gtte *) calloc(NCHARS, sizeof(gtte));
    173 		if (f->gototab[i].entries == NULL)
    174 			goto out;
    175 		f->gototab[i].allocated = NCHARS;
    176 		f->gototab[i].inuse = 0;
    177 		f->out[i] = 0;
    178 		f->posns[i] = NULL;
    179 	}
    180 	f->state_count = new_count;
    181 	return;
    182 out:
    183 	overflo(__func__);
    184 }
    185 
    186 fa *makedfa(const char *s, bool anchor)	/* returns dfa for reg expr s */
    187 {
    188 	int i, use, nuse;
    189 	fa *pfa;
    190 	static int now = 1;
    191 
    192 	if (setvec == NULL) {	/* first time through any RE */
    193 		resizesetvec(__func__);
    194 	}
    195 
    196 	if (compile_time != RUNNING)	/* a constant for sure */
    197 		return mkdfa(s, anchor);
    198 	for (i = 0; i < nfatab; i++)	/* is it there already? */
    199 		if (fatab[i]->anchor == anchor
    200 		  && strcmp((const char *) fatab[i]->restr, s) == 0) {
    201 			fatab[i]->use = now++;
    202 			return fatab[i];
    203 		}
    204 	pfa = mkdfa(s, anchor);
    205 	if (nfatab < NFA) {	/* room for another */
    206 		fatab[nfatab] = pfa;
    207 		fatab[nfatab]->use = now++;
    208 		nfatab++;
    209 		return pfa;
    210 	}
    211 	use = fatab[0]->use;	/* replace least-recently used */
    212 	nuse = 0;
    213 	for (i = 1; i < nfatab; i++)
    214 		if (fatab[i]->use < use) {
    215 			use = fatab[i]->use;
    216 			nuse = i;
    217 		}
    218 	freefa(fatab[nuse]);
    219 	fatab[nuse] = pfa;
    220 	pfa->use = now++;
    221 	return pfa;
    222 }
    223 
    224 fa *mkdfa(const char *s, bool anchor)	/* does the real work of making a dfa */
    225 				/* anchor = true for anchored matches, else false */
    226 {
    227 	Node *p, *p1;
    228 	fa *f;
    229 
    230 	firstbasestr = (const uschar *) s;
    231 	basestr = firstbasestr;
    232 	p = reparse(s);
    233 	p1 = op2(CAT, op2(STAR, op2(ALL, NIL, NIL), NIL), p);
    234 		/* put ALL STAR in front of reg.  exp. */
    235 	p1 = op2(CAT, p1, op2(FINAL, NIL, NIL));
    236 		/* put FINAL after reg.  exp. */
    237 
    238 	poscnt = 0;
    239 	penter(p1);	/* enter parent pointers and leaf indices */
    240 	if ((f = (fa *) calloc(1, sizeof(fa) + poscnt * sizeof(rrow))) == NULL)
    241 		overflo(__func__);
    242 	f->accept = poscnt-1;	/* penter has computed number of positions in re */
    243 	cfoll(f, p1);	/* set up follow sets */
    244 	freetr(p1);
    245 	resize_state(f, 1);
    246 	f->posns[0] = intalloc(*(f->re[0].lfollow), __func__);
    247 	f->posns[1] = intalloc(1, __func__);
    248 	*f->posns[1] = 0;
    249 	f->initstat = makeinit(f, anchor);
    250 	f->anchor = anchor;
    251 	f->restr = (uschar *) tostring(s);
    252 	if (firstbasestr != basestr) {
    253 		if (basestr)
    254 			xfree(basestr);
    255 	}
    256 	return f;
    257 }
    258 
    259 int makeinit(fa *f, bool anchor)
    260 {
    261 	int i, k;
    262 
    263 	f->curstat = 2;
    264 	f->out[2] = 0;
    265 	k = *(f->re[0].lfollow);
    266 	xfree(f->posns[2]);
    267 	f->posns[2] = intalloc(k + 1,  __func__);
    268 	for (i = 0; i <= k; i++) {
    269 		(f->posns[2])[i] = (f->re[0].lfollow)[i];
    270 	}
    271 	if ((f->posns[2])[1] == f->accept)
    272 		f->out[2] = 1;
    273 	clear_gototab(f, 2);
    274 	f->curstat = cgoto(f, 2, HAT);
    275 	if (anchor) {
    276 		*f->posns[2] = k-1;	/* leave out position 0 */
    277 		for (i = 0; i < k; i++) {
    278 			(f->posns[0])[i] = (f->posns[2])[i];
    279 		}
    280 
    281 		f->out[0] = f->out[2];
    282 		if (f->curstat != 2)
    283 			--(*f->posns[f->curstat]);
    284 	}
    285 	return f->curstat;
    286 }
    287 
    288 void penter(Node *p)	/* set up parent pointers and leaf indices */
    289 {
    290 	switch (type(p)) {
    291 	ELEAF
    292 	LEAF
    293 		info(p) = poscnt;
    294 		poscnt++;
    295 		break;
    296 	UNARY
    297 		penter(left(p));
    298 		parent(left(p)) = p;
    299 		break;
    300 	case CAT:
    301 	case OR:
    302 		penter(left(p));
    303 		penter(right(p));
    304 		parent(left(p)) = p;
    305 		parent(right(p)) = p;
    306 		break;
    307 	case ZERO:
    308 		break;
    309 	default:	/* can't happen */
    310 		FATAL("can't happen: unknown type %d in penter", type(p));
    311 		break;
    312 	}
    313 }
    314 
    315 void freetr(Node *p)	/* free parse tree */
    316 {
    317 	switch (type(p)) {
    318 	ELEAF
    319 	LEAF
    320 		xfree(p);
    321 		break;
    322 	UNARY
    323 	case ZERO:
    324 		freetr(left(p));
    325 		xfree(p);
    326 		break;
    327 	case CAT:
    328 	case OR:
    329 		freetr(left(p));
    330 		freetr(right(p));
    331 		xfree(p);
    332 		break;
    333 	default:	/* can't happen */
    334 		FATAL("can't happen: unknown type %d in freetr", type(p));
    335 		break;
    336 	}
    337 }
    338 
    339 /* in the parsing of regular expressions, metacharacters like . have */
    340 /* to be seen literally;  \056 is not a metacharacter. */
    341 
    342 static int hexstr(const uschar **pp, int max)	/* find and eval hex string at pp, return new p */
    343 {			/* only pick up one 8-bit byte (2 chars) */
    344 	const uschar *p;
    345 	int n = 0;
    346 	int i;
    347 
    348 	for (i = 0, p = *pp; i < max && isxdigit(*p); i++, p++) {
    349 		if (isdigit((int) *p))
    350 			n = 16 * n + *p - '0';
    351 		else if (*p >= 'a' && *p <= 'f')
    352 			n = 16 * n + *p - 'a' + 10;
    353 		else if (*p >= 'A' && *p <= 'F')
    354 			n = 16 * n + *p - 'A' + 10;
    355 	}
    356 	*pp = p;
    357 	return n;
    358 }
    359 
    360 
    361 
    362 #define isoctdigit(c) ((c) >= '0' && (c) <= '7')	/* multiple use of arg */
    363 
    364 int quoted(const uschar **pp)	/* pick up next thing after a \\ */
    365 			/* and increment *pp */
    366 {
    367 	const uschar *p = *pp;
    368 	int c;
    369 
    370 /* BUG: should advance by utf-8 char even if makes no sense */
    371 
    372 	switch ((c = *p++)) {
    373 	case 't':
    374 		c = '\t';
    375 		break;
    376 	case 'n':
    377 		c = '\n';
    378 		break;
    379 	case 'f':
    380 		c = '\f';
    381 		break;
    382 	case 'r':
    383 		c = '\r';
    384 		break;
    385 	case 'b':
    386 		c = '\b';
    387 		break;
    388 	case 'v':
    389 		c = '\v';
    390 		break;
    391 	case 'a':
    392 		c = '\a';
    393 		break;
    394 	case '\\':
    395 		c = '\\';
    396 		break;
    397 	case 'x': /* 2 hex digits follow */
    398 		c = hexstr(&p, 2); /* this adds a null if number is invalid */
    399 		break;
    400 	case 'u': /* unicode char number up to 8 hex digits */
    401 		c = hexstr(&p, 8);
    402 		break;
    403 	default:
    404 		if (isoctdigit(c)) { /* \d \dd \ddd */
    405 			int n = c - '0';
    406 			if (isoctdigit(*p)) {
    407 				n = 8 * n + *p++ - '0';
    408 				if (isoctdigit(*p))
    409 					n = 8 * n + *p++ - '0';
    410 			}
    411 			c = n;
    412 		}
    413 	}
    414 
    415 	*pp = p;
    416 	return c;
    417 }
    418 
    419 int *cclenter(const char *argp)	/* add a character class */
    420 {
    421 	int i, c, c2;
    422 	int n;
    423 	const uschar *p = (const uschar *) argp;
    424 	int *bp, *retp;
    425 	static int *buf = NULL;
    426 	static int bufsz = 100;
    427 
    428 	if (buf == NULL && (buf = (int *) calloc(bufsz, sizeof(int))) == NULL)
    429 		FATAL("out of space for character class [%.10s...] 1", p);
    430 	bp = buf;
    431 	for (i = 0; *p != 0; ) {
    432 		n = u8_rune(&c, (const char *) p);
    433 		p += n;
    434 		if (c == '\\') {
    435 			c = quoted(&p);
    436 		} else if (c == '-' && i > 0 && bp[-1] != 0) {
    437 			if (*p != 0) {
    438 				c = bp[-1];
    439 				/* c2 = *p++; */
    440 				n = u8_rune(&c2, (const char *) p);
    441 				p += n;
    442 				if (c2 == '\\')
    443 					c2 = quoted(&p); /* BUG: sets p, has to be u8 size */
    444 				if (c > c2) {	/* empty; ignore */
    445 					bp--;
    446 					i--;
    447 					continue;
    448 				}
    449 				while (c < c2) {
    450 					if (i >= bufsz) {
    451 						bufsz *= 2;
    452 						buf = (int *) realloc(buf, bufsz * sizeof(int));
    453 						if (buf == NULL)
    454 							FATAL("out of space for character class [%.10s...] 2", p);
    455 						bp = buf + i;
    456 					}
    457 					*bp++ = ++c;
    458 					i++;
    459 				}
    460 				continue;
    461 			}
    462 		}
    463 		if (i >= bufsz) {
    464 			bufsz *= 2;
    465 			buf = (int *) realloc(buf, bufsz * sizeof(int));
    466 			if (buf == NULL)
    467 				FATAL("out of space for character class [%.10s...] 2", p);
    468 			bp = buf + i;
    469 		}
    470 		*bp++ = c;
    471 		i++;
    472 	}
    473 	*bp = 0;
    474 	/* DPRINTF("cclenter: in = |%s|, out = |%s|\n", op, buf); BUG: can't print array of int */
    475 	/* xfree(op);  BUG: what are we freeing here? */
    476 	retp = (int *) calloc(bp-buf+1, sizeof(int));
    477 	for (i = 0; i < bp-buf+1; i++)
    478 		retp[i] = buf[i];
    479 	return retp;
    480 }
    481 
    482 void overflo(const char *s)
    483 {
    484 	FATAL("regular expression too big: out of space in %.30s...", s);
    485 }
    486 
    487 void cfoll(fa *f, Node *v)	/* enter follow set of each leaf of vertex v into lfollow[leaf] */
    488 {
    489 	int i;
    490 	int *p;
    491 
    492 	switch (type(v)) {
    493 	ELEAF
    494 	LEAF
    495 		f->re[info(v)].ltype = type(v);
    496 		f->re[info(v)].lval.np = right(v);
    497 		while (f->accept >= maxsetvec) {	/* guessing here! */
    498 			resizesetvec(__func__);
    499 		}
    500 		for (i = 0; i <= f->accept; i++)
    501 			setvec[i] = 0;
    502 		setcnt = 0;
    503 		follow(v);	/* computes setvec and setcnt */
    504 		p = intalloc(setcnt + 1, __func__);
    505 		f->re[info(v)].lfollow = p;
    506 		*p = setcnt;
    507 		for (i = f->accept; i >= 0; i--)
    508 			if (setvec[i] == 1)
    509 				*++p = i;
    510 		break;
    511 	UNARY
    512 		cfoll(f,left(v));
    513 		break;
    514 	case CAT:
    515 	case OR:
    516 		cfoll(f,left(v));
    517 		cfoll(f,right(v));
    518 		break;
    519 	case ZERO:
    520 		break;
    521 	default:	/* can't happen */
    522 		FATAL("can't happen: unknown type %d in cfoll", type(v));
    523 	}
    524 }
    525 
    526 int first(Node *p)	/* collects initially active leaves of p into setvec */
    527 			/* returns 0 if p matches empty string */
    528 {
    529 	int b, lp;
    530 
    531 	switch (type(p)) {
    532 	ELEAF
    533 	LEAF
    534 		lp = info(p);	/* look for high-water mark of subscripts */
    535 		while (setcnt >= maxsetvec || lp >= maxsetvec) {	/* guessing here! */
    536 			resizesetvec(__func__);
    537 		}
    538 		if (type(p) == EMPTYRE) {
    539 			setvec[lp] = 0;
    540 			return(0);
    541 		}
    542 		if (setvec[lp] != 1) {
    543 			setvec[lp] = 1;
    544 			setcnt++;
    545 		}
    546 		if (type(p) == CCL && (*(int *) right(p)) == 0)
    547 			return(0);		/* empty CCL */
    548 		return(1);
    549 	case PLUS:
    550 		if (first(left(p)) == 0)
    551 			return(0);
    552 		return(1);
    553 	case STAR:
    554 	case QUEST:
    555 		first(left(p));
    556 		return(0);
    557 	case CAT:
    558 		if (first(left(p)) == 0 && first(right(p)) == 0) return(0);
    559 		return(1);
    560 	case OR:
    561 		b = first(right(p));
    562 		if (first(left(p)) == 0 || b == 0) return(0);
    563 		return(1);
    564 	case ZERO:
    565 		return 0;
    566 	}
    567 	FATAL("can't happen: unknown type %d in first", type(p));	/* can't happen */
    568 	return(-1);
    569 }
    570 
    571 void follow(Node *v)	/* collects leaves that can follow v into setvec */
    572 {
    573 	Node *p;
    574 
    575 	if (type(v) == FINAL)
    576 		return;
    577 	p = parent(v);
    578 	switch (type(p)) {
    579 	case STAR:
    580 	case PLUS:
    581 		first(v);
    582 		follow(p);
    583 		return;
    584 
    585 	case OR:
    586 	case QUEST:
    587 		follow(p);
    588 		return;
    589 
    590 	case CAT:
    591 		if (v == left(p)) {	/* v is left child of p */
    592 			if (first(right(p)) == 0) {
    593 				follow(p);
    594 				return;
    595 			}
    596 		} else		/* v is right child */
    597 			follow(p);
    598 		return;
    599 	}
    600 }
    601 
    602 int member(int c, int *sarg)	/* is c in s? */
    603 {
    604 	int *s = (int *) sarg;
    605 
    606 	while (*s)
    607 		if (c == *s++)
    608 			return(1);
    609 	return(0);
    610 }
    611 
    612 static void resize_gototab(fa *f, int state)
    613 {
    614 	size_t new_size = f->gototab[state].allocated * 2;
    615 	gtte *p = (gtte *) realloc(f->gototab[state].entries, new_size * sizeof(gtte));
    616 	if (p == NULL)
    617 		overflo(__func__);
    618 
    619 	// need to initialize the new memory to zero
    620 	size_t orig_size = f->gototab[state].allocated;		// 2nd half of new mem is this size
    621 	memset(p + orig_size, 0, orig_size * sizeof(gtte));	// clean it out
    622 
    623 	f->gototab[state].allocated = new_size;			// update gototab info
    624 	f->gototab[state].entries = p;
    625 }
    626 
    627 static int get_gototab(fa *f, int state, int ch) /* hide gototab implementation */
    628 {
    629 	gtte key;
    630 	gtte *item;
    631 
    632 	key.ch = ch;
    633 	key.state = 0;	/* irrelevant */
    634 	item = (gtte *) bsearch(& key, f->gototab[state].entries,
    635 			f->gototab[state].inuse, sizeof(gtte),
    636 			entry_cmp);
    637 
    638 	if (item == NULL)
    639 		return 0;
    640 	else
    641 		return item->state;
    642 }
    643 
    644 static int entry_cmp(const void *l, const void *r)
    645 {
    646 	const gtte *left, *right;
    647 
    648 	left = (const gtte *) l;
    649 	right = (const gtte *) r;
    650 
    651 	return left->ch - right->ch;
    652 }
    653 
    654 static int set_gototab(fa *f, int state, int ch, int val) /* hide gototab implementation */
    655 {
    656 	if (f->gototab[state].inuse == 0) {
    657 		f->gototab[state].entries[0].ch = ch;
    658 		f->gototab[state].entries[0].state = val;
    659 		f->gototab[state].inuse++;
    660 		return val;
    661 	} else if ((unsigned)ch > f->gototab[state].entries[f->gototab[state].inuse-1].ch) {
    662 		// not seen yet, insert and return
    663 		gtt *tab = & f->gototab[state];
    664 		if (tab->inuse + 1 >= tab->allocated)
    665 			resize_gototab(f, state);
    666 
    667 		f->gototab[state].entries[f->gototab[state].inuse].ch = ch;
    668 		f->gototab[state].entries[f->gototab[state].inuse].state = val;
    669 		f->gototab[state].inuse++;
    670 		return val;
    671 	} else {
    672 		// maybe we have it, maybe we don't
    673 		gtte key;
    674 		gtte *item;
    675 
    676 		key.ch = ch;
    677 		key.state = 0;	/* irrelevant */
    678 		item = (gtte *) bsearch(& key, f->gototab[state].entries,
    679 				f->gototab[state].inuse, sizeof(gtte),
    680 				entry_cmp);
    681 
    682 		if (item != NULL) {
    683 			// we have it, update state and return
    684 			item->state = val;
    685 			return item->state;
    686 		}
    687 		// otherwise, fall through to insert and reallocate.
    688 	}
    689 
    690 	gtt *tab = & f->gototab[state];
    691 	if (tab->inuse + 1 >= tab->allocated)
    692 		resize_gototab(f, state);
    693 	f->gototab[state].entries[tab->inuse].ch = ch;
    694 	f->gototab[state].entries[tab->inuse].state = val;
    695 	++tab->inuse;
    696 
    697 	qsort(f->gototab[state].entries,
    698 		f->gototab[state].inuse, sizeof(gtte), entry_cmp);
    699 
    700 	return val; /* not used anywhere at the moment */
    701 }
    702 
    703 static void clear_gototab(fa *f, int state)
    704 {
    705 	memset(f->gototab[state].entries, 0,
    706 		f->gototab[state].allocated * sizeof(gtte));
    707 	f->gototab[state].inuse = 0;
    708 }
    709 
    710 int match(fa *f, const char *p0)	/* shortest match ? */
    711 {
    712 	int s, ns;
    713 	int n;
    714 	int rune;
    715 	const uschar *p = (const uschar *) p0;
    716 
    717 	/* return pmatch(f, p0); does it matter whether longest or shortest? */
    718 
    719 	s = f->initstat;
    720 	assert (s < f->state_count);
    721 
    722 	if (f->out[s])
    723 		return(1);
    724 	do {
    725 		/* assert(*p < NCHARS); */
    726 		n = u8_rune(&rune, (const char *) p);
    727 		if ((ns = get_gototab(f, s, rune)) != 0)
    728 			s = ns;
    729 		else
    730 			s = cgoto(f, s, rune);
    731 		if (f->out[s])
    732 			return(1);
    733 		if (*p == 0)
    734 			break;
    735 		p += n;
    736 	} while (1);  /* was *p++ != 0 */
    737 	return(0);
    738 }
    739 
    740 int pmatch(fa *f, const char *p0)	/* longest match, for sub */
    741 {
    742 	int s, ns;
    743 	int n;
    744 	int rune;
    745 	const uschar *p = (const uschar *) p0;
    746 	const uschar *q;
    747 
    748 	s = f->initstat;
    749 	assert(s < f->state_count);
    750 
    751 	patbeg = (const char *)p;
    752 	patlen = -1;
    753 	do {
    754 		q = p;
    755 		do {
    756 			if (f->out[s])		/* final state */
    757 				patlen = q-p;
    758 			/* assert(*q < NCHARS); */
    759 			n = u8_rune(&rune, (const char *) q);
    760 			if ((ns = get_gototab(f, s, rune)) != 0)
    761 				s = ns;
    762 			else
    763 				s = cgoto(f, s, rune);
    764 
    765 			assert(s < f->state_count);
    766 
    767 			if (s == 1) {	/* no transition */
    768 				if (patlen >= 0) {
    769 					patbeg = (const char *) p;
    770 					return(1);
    771 				}
    772 				else
    773 					goto nextin;	/* no match */
    774 			}
    775 			if (*q == 0)
    776 				break;
    777 			q += n;
    778 		} while (1);
    779 		q++;  /* was *q++ */
    780 		if (f->out[s])
    781 			patlen = q-p-1;	/* don't count $ */
    782 		if (patlen >= 0) {
    783 			patbeg = (const char *) p;
    784 			return(1);
    785 		}
    786 	nextin:
    787 		s = 2;
    788 		if (*p == 0)
    789 			break;
    790 		n = u8_rune(&rune, (const char *) p);
    791 		p += n;
    792 	} while (1); /* was *p++ */
    793 	return (0);
    794 }
    795 
    796 int nematch(fa *f, const char *p0)	/* non-empty match, for sub */
    797 {
    798 	int s, ns;
    799         int n;
    800         int rune;
    801 	const uschar *p = (const uschar *) p0;
    802 	const uschar *q;
    803 
    804 	s = f->initstat;
    805 	assert(s < f->state_count);
    806 
    807 	patbeg = (const char *)p;
    808 	patlen = -1;
    809 	while (*p) {
    810 		q = p;
    811 		do {
    812 			if (f->out[s])		/* final state */
    813 				patlen = q-p;
    814 			/* assert(*q < NCHARS); */
    815 			n = u8_rune(&rune, (const char *) q);
    816 			if ((ns = get_gototab(f, s, rune)) != 0)
    817 				s = ns;
    818 			else
    819 				s = cgoto(f, s, rune);
    820 			if (s == 1) {	/* no transition */
    821 				if (patlen > 0) {
    822 					patbeg = (const char *) p;
    823 					return(1);
    824 				} else
    825 					goto nnextin;	/* no nonempty match */
    826 			}
    827 			if (*q == 0)
    828 				break;
    829 			q += n;
    830 		} while (1);
    831 		q++;
    832 		if (f->out[s])
    833 			patlen = q-p-1;	/* don't count $ */
    834 		if (patlen > 0 ) {
    835 			patbeg = (const char *) p;
    836 			return(1);
    837 		}
    838 	nnextin:
    839 		s = 2;
    840 		p++;
    841 	}
    842 	return (0);
    843 }
    844 
    845 
    846 /*
    847  * NAME
    848  *     fnematch
    849  *
    850  * DESCRIPTION
    851  *     A stream-fed version of nematch which transfers characters to a
    852  *     null-terminated buffer. All characters up to and including the last
    853  *     character of the matching text or EOF are placed in the buffer. If
    854  *     a match is found, patbeg and patlen are set appropriately.
    855  *
    856  * RETURN VALUES
    857  *     false    No match found.
    858  *     true     Match found.
    859  */
    860 
    861 bool fnematch(fa *pfa, FILE *f, char **pbuf, int *pbufsize, int quantum)
    862 {
    863 	char *i, *j, *k, *buf = *pbuf;
    864 	int bufsize = *pbufsize;
    865 	int c, n, ns, s;
    866 
    867 	s = pfa->initstat;
    868 	patlen = 0;
    869 
    870 	/*
    871 	 * buf <= i <= j <= k <= buf+bufsize
    872 	 *
    873 	 * i: origin of active substring
    874 	 * j: current character
    875 	 * k: destination of the next getc
    876 	 */
    877 
    878 	i = j = k = buf;
    879 
    880 	do {
    881 		/*
    882 		 * Call u8_rune with at least awk_mb_cur_max ahead in
    883 		 * the buffer until EOF interferes.
    884 		 */
    885 		if (k - j < (int)awk_mb_cur_max) {
    886 			if (k + awk_mb_cur_max > buf + bufsize) {
    887 				char *obuf = buf;
    888 				adjbuf((char **) &buf, &bufsize,
    889 				    bufsize + awk_mb_cur_max,
    890 				    quantum, 0, "fnematch");
    891 
    892 				/* buf resized, maybe moved. update pointers */
    893 				*pbufsize = bufsize;
    894 				if (obuf != buf) {
    895 					i = buf + (i - obuf);
    896 					j = buf + (j - obuf);
    897 					k = buf + (k - obuf);
    898 					*pbuf = buf;
    899 					if (patlen)
    900 						patbeg = buf + (patbeg - obuf);
    901 				}
    902 			}
    903 			for (n = awk_mb_cur_max ; n > 0; n--) {
    904 				*k++ = (c = getc(f)) != EOF ? c : 0;
    905 				if (c == EOF) {
    906 					if (ferror(f))
    907 						FATAL("fnematch: getc error");
    908 					break;
    909 				}
    910 			}
    911 		}
    912 
    913 		j += u8_rune(&c, j);
    914 
    915 		if ((ns = get_gototab(pfa, s, c)) != 0)
    916 			s = ns;
    917 		else
    918 			s = cgoto(pfa, s, c);
    919 
    920 		if (pfa->out[s]) {	/* final state */
    921 			patbeg = i;
    922 			patlen = j - i;
    923 			if (c == 0)	/* don't count $ */
    924 				patlen--;
    925 		}
    926 
    927 		if (c && s != 1)
    928 			continue;  /* origin i still viable, next j */
    929 		if (patlen)
    930 			break;     /* best match found */
    931 
    932 		/* no match at origin i, next i and start over */
    933 		i += u8_rune(&c, i);
    934 		if (c == 0)
    935 			break;    /* no match */
    936 		j = i;
    937 		s = 2;
    938 	} while (1);
    939 
    940 	if (patlen) {
    941 		/*
    942 		 * Under no circumstances is the last character fed to
    943 		 * the automaton part of the match. It is EOF's nullbyte,
    944 		 * or it sent the automaton into a state with no further
    945 		 * transitions available (s==1), or both. Room for a
    946 		 * terminating nullbyte is guaranteed.
    947 		 *
    948 		 * ungetc any chars after the end of matching text
    949 		 * (except for EOF's nullbyte, if present) and null
    950 		 * terminate the buffer.
    951 		 */
    952 		do
    953 			if (*--k && ungetc(*k, f) == EOF)
    954 				FATAL("unable to ungetc '%c'", *k);
    955 		while (k > patbeg + patlen);
    956 		*k = '\0';
    957 		return true;
    958 	}
    959 	else
    960 		return false;
    961 }
    962 
    963 Node *reparse(const char *p)	/* parses regular expression pointed to by p */
    964 {			/* uses relex() to scan regular expression */
    965 	Node *np;
    966 
    967 	DPRINTF("reparse <%s>\n", p);
    968 	lastre = prestr = (const uschar *) p;	/* prestr points to string to be parsed */
    969 	rtok = relex();
    970 	/* GNU compatibility: an empty regexp matches anything */
    971 	if (rtok == '\0') {
    972 		/* FATAL("empty regular expression"); previous */
    973 		return(op2(EMPTYRE, NIL, NIL));
    974 	}
    975 	np = regexp();
    976 	if (rtok != '\0')
    977 		FATAL("syntax error in regular expression %s at %s", lastre, prestr);
    978 	return(np);
    979 }
    980 
    981 Node *regexp(void)	/* top-level parse of reg expr */
    982 {
    983 	return (alt(concat(primary())));
    984 }
    985 
    986 Node *primary(void)
    987 {
    988 	Node *np;
    989 	int savelastatom;
    990 
    991 	switch (rtok) {
    992 	case CHAR:
    993 		lastatom = starttok;
    994 		np = op2(CHAR, NIL, itonp(rlxval));
    995 		rtok = relex();
    996 		return (unary(np));
    997 	case ALL:
    998 		rtok = relex();
    999 		return (unary(op2(ALL, NIL, NIL)));
   1000 	case EMPTYRE:
   1001 		rtok = relex();
   1002 		return (unary(op2(EMPTYRE, NIL, NIL)));
   1003 	case DOT:
   1004 		lastatom = starttok;
   1005 		rtok = relex();
   1006 		return (unary(op2(DOT, NIL, NIL)));
   1007 	case CCL:
   1008 		np = op2(CCL, NIL, (Node*) cclenter((const char *) rlxstr));
   1009 		lastatom = starttok;
   1010 		rtok = relex();
   1011 		return (unary(np));
   1012 	case NCCL:
   1013 		np = op2(NCCL, NIL, (Node *) cclenter((const char *) rlxstr));
   1014 		lastatom = starttok;
   1015 		rtok = relex();
   1016 		return (unary(np));
   1017 	case '^':
   1018 		rtok = relex();
   1019 		return (unary(op2(CHAR, NIL, itonp(HAT))));
   1020 	case '$':
   1021 		rtok = relex();
   1022 		return (unary(op2(CHAR, NIL, NIL)));
   1023 	case '(':
   1024 		lastatom = starttok;
   1025 		savelastatom = starttok - basestr; /* Retain over recursion */
   1026 		rtok = relex();
   1027 		if (rtok == ')') {	/* special pleading for () */
   1028 			rtok = relex();
   1029 			return unary(op2(CCL, NIL, (Node *) cclenter("")));
   1030 		}
   1031 		np = regexp();
   1032 		if (rtok == ')') {
   1033 			lastatom = basestr + savelastatom; /* Restore */
   1034 			rtok = relex();
   1035 			return (unary(np));
   1036 		}
   1037 		else
   1038 			FATAL("syntax error in regular expression %s at %s", lastre, prestr);
   1039 	default:
   1040 		FATAL("illegal primary in regular expression %s at %s", lastre, prestr);
   1041 	}
   1042 	return 0;	/*NOTREACHED*/
   1043 }
   1044 
   1045 Node *concat(Node *np)
   1046 {
   1047 	switch (rtok) {
   1048 	case CHAR: case DOT: case ALL: case CCL: case NCCL: case '$': case '(':
   1049 		return (concat(op2(CAT, np, primary())));
   1050 	case EMPTYRE:
   1051 		rtok = relex();
   1052 		return (concat(op2(CAT, op2(CCL, NIL, (Node *) cclenter("")),
   1053 				primary())));
   1054 	}
   1055 	return (np);
   1056 }
   1057 
   1058 Node *alt(Node *np)
   1059 {
   1060 	if (rtok == OR) {
   1061 		rtok = relex();
   1062 		return (alt(op2(OR, np, concat(primary()))));
   1063 	}
   1064 	return (np);
   1065 }
   1066 
   1067 Node *unary(Node *np)
   1068 {
   1069 	switch (rtok) {
   1070 	case STAR:
   1071 		rtok = relex();
   1072 		return (unary(op2(STAR, np, NIL)));
   1073 	case PLUS:
   1074 		rtok = relex();
   1075 		return (unary(op2(PLUS, np, NIL)));
   1076 	case QUEST:
   1077 		rtok = relex();
   1078 		return (unary(op2(QUEST, np, NIL)));
   1079 	case ZERO:
   1080 		rtok = relex();
   1081 		return (unary(op2(ZERO, np, NIL)));
   1082 	default:
   1083 		return (np);
   1084 	}
   1085 }
   1086 
   1087 /*
   1088  * Character class definitions conformant to the POSIX locale as
   1089  * defined in IEEE P1003.1 draft 7 of June 2001, assuming the source
   1090  * and operating character sets are both ASCII (ISO646) or supersets
   1091  * thereof.
   1092  *
   1093  * Note that to avoid overflowing the temporary buffer used in
   1094  * relex(), the expanded character class (prior to range expansion)
   1095  * must be less than twice the size of their full name.
   1096  */
   1097 
   1098 /* Because isblank doesn't show up in any of the header files on any
   1099  * system i use, it's defined here.  if some other locale has a richer
   1100  * definition of "blank", define HAS_ISBLANK and provide your own
   1101  * version.
   1102  * the parentheses here are an attempt to find a path through the maze
   1103  * of macro definition and/or function and/or version provided.  thanks
   1104  * to nelson beebe for the suggestion; let's see if it works everywhere.
   1105  */
   1106 
   1107 /* #define HAS_ISBLANK */
   1108 #ifndef HAS_ISBLANK
   1109 
   1110 int (xisblank)(int c)
   1111 {
   1112 	return c==' ' || c=='\t';
   1113 }
   1114 
   1115 #endif
   1116 
   1117 static const struct charclass {
   1118 	const char *cc_name;
   1119 	int cc_namelen;
   1120 	int (*cc_func)(int);
   1121 } charclasses[] = {
   1122 	{ "alnum",	5,	isalnum },
   1123 	{ "alpha",	5,	isalpha },
   1124 #ifndef HAS_ISBLANK
   1125 	{ "blank",	5,	xisblank },
   1126 #else
   1127 	{ "blank",	5,	isblank },
   1128 #endif
   1129 	{ "cntrl",	5,	iscntrl },
   1130 	{ "digit",	5,	isdigit },
   1131 	{ "graph",	5,	isgraph },
   1132 	{ "lower",	5,	islower },
   1133 	{ "print",	5,	isprint },
   1134 	{ "punct",	5,	ispunct },
   1135 	{ "space",	5,	isspace },
   1136 	{ "upper",	5,	isupper },
   1137 	{ "xdigit",	6,	isxdigit },
   1138 	{ NULL,		0,	NULL },
   1139 };
   1140 
   1141 #define REPEAT_SIMPLE		0
   1142 #define REPEAT_PLUS_APPENDED	1
   1143 #define REPEAT_WITH_Q		2
   1144 #define REPEAT_ZERO		3
   1145 
   1146 static int
   1147 replace_repeat(const uschar *reptok, int reptoklen, const uschar *atom,
   1148 	       int atomlen, int firstnum, int secondnum, int special_case)
   1149 {
   1150 	int i, j;
   1151 	uschar *buf = 0;
   1152 	int ret = 1;
   1153 	int init_q = (firstnum == 0);		/* first added char will be ? */
   1154 	int n_q_reps = secondnum-firstnum;	/* m>n, so reduce until {1,m-n} left  */
   1155 	int prefix_length = reptok - basestr;	/* prefix includes first rep	*/
   1156 	int suffix_length = strlen((const char *) reptok) - reptoklen;	/* string after rep specifier	*/
   1157 	int size = prefix_length +  suffix_length;
   1158 
   1159 	if (firstnum > 1) {	/* add room for reps 2 through firstnum */
   1160 		size += atomlen*(firstnum-1);
   1161 	}
   1162 
   1163 	/* Adjust size of buffer for special cases */
   1164 	if (special_case == REPEAT_PLUS_APPENDED) {
   1165 		size++;		/* for the final + */
   1166 	} else if (special_case == REPEAT_WITH_Q) {
   1167 		size += init_q + (atomlen+1)* (n_q_reps-init_q);
   1168 	} else if (special_case == REPEAT_ZERO) {
   1169 		size += 2;	/* just a null ERE: () */
   1170 	}
   1171 	if ((buf = (uschar *) malloc(size + 1)) == NULL)
   1172 		FATAL("out of space in reg expr %.10s..", lastre);
   1173 	memcpy(buf, basestr, prefix_length);	/* copy prefix	*/
   1174 	j = prefix_length;
   1175 	if (special_case == REPEAT_ZERO) {
   1176 		j -= atomlen;
   1177 		buf[j++] = '(';
   1178 		buf[j++] = ')';
   1179 	}
   1180 	for (i = 1; i < firstnum; i++) {	/* copy x reps 	*/
   1181 		memcpy(&buf[j], atom, atomlen);
   1182 		j += atomlen;
   1183 	}
   1184 	if (special_case == REPEAT_PLUS_APPENDED) {
   1185 		buf[j++] = '+';
   1186 	} else if (special_case == REPEAT_WITH_Q) {
   1187 		if (init_q)
   1188 			buf[j++] = '?';
   1189 		for (i = init_q; i < n_q_reps; i++) {	/* copy x? reps */
   1190 			memcpy(&buf[j], atom, atomlen);
   1191 			j += atomlen;
   1192 			buf[j++] = '?';
   1193 		}
   1194 	}
   1195 	memcpy(&buf[j], reptok+reptoklen, suffix_length);
   1196 	j += suffix_length;
   1197 	buf[j] = '\0';
   1198 	/* free old basestr */
   1199 	if (firstbasestr != basestr) {
   1200 		if (basestr)
   1201 			xfree(basestr);
   1202 	}
   1203 	basestr = buf;
   1204 	prestr  = buf + prefix_length;
   1205 	if (special_case == REPEAT_ZERO) {
   1206 		prestr  -= atomlen;
   1207 		ret++;
   1208 	}
   1209 	return ret;
   1210 }
   1211 
   1212 static int repeat(const uschar *reptok, int reptoklen, const uschar *atom,
   1213 		  int atomlen, int firstnum, int secondnum)
   1214 {
   1215 	if (atom == NULL)
   1216 		return 0;
   1217 
   1218 	/*
   1219 	   In general, the repetition specifier or "bound" is replaced here
   1220 	   by an equivalent ERE string, repeating the immediately previous atom
   1221 	   and appending ? and + as needed. Note that the first copy of the
   1222 	   atom is left in place, except in the special_case of a zero-repeat
   1223 	   (i.e., {0}).
   1224 	 */
   1225 	if (secondnum < 0) {	/* means {n,} -> repeat n-1 times followed by PLUS */
   1226 		if (firstnum < 2) {
   1227 			/* 0 or 1: should be handled before you get here */
   1228 			FATAL("internal error");
   1229 		} else {
   1230 			return replace_repeat(reptok, reptoklen, atom, atomlen,
   1231 				firstnum, secondnum, REPEAT_PLUS_APPENDED);
   1232 		}
   1233 	} else if (firstnum == secondnum) {	/* {n} or {n,n} -> simply repeat n-1 times */
   1234 		if (firstnum == 0) {	/* {0} or {0,0} */
   1235 			/* This case is unusual because the resulting
   1236 			   replacement string might actually be SMALLER than
   1237 			   the original ERE */
   1238 			return replace_repeat(reptok, reptoklen, atom, atomlen,
   1239 					firstnum, secondnum, REPEAT_ZERO);
   1240 		} else {		/* (firstnum >= 1) */
   1241 			return replace_repeat(reptok, reptoklen, atom, atomlen,
   1242 					firstnum, secondnum, REPEAT_SIMPLE);
   1243 		}
   1244 	} else if (firstnum < secondnum) {	/* {n,m} -> repeat n-1 times then alternate  */
   1245 		/*  x{n,m}  =>  xx...x{1, m-n+1}  =>  xx...x?x?x?..x?	*/
   1246 		return replace_repeat(reptok, reptoklen, atom, atomlen,
   1247 					firstnum, secondnum, REPEAT_WITH_Q);
   1248 	} else {	/* Error - shouldn't be here (n>m) */
   1249 		FATAL("internal error");
   1250 	}
   1251 	return 0;
   1252 }
   1253 
   1254 int relex(void)		/* lexical analyzer for reparse */
   1255 {
   1256 	int c, n;
   1257 	int cflag;
   1258 	static uschar *buf = NULL;
   1259 	static int bufsz = 100;
   1260 	uschar *bp;
   1261 	const struct charclass *cc;
   1262 	int i;
   1263 	int num, m;
   1264 	bool commafound, digitfound;
   1265 	const uschar *startreptok;
   1266 	static int parens = 0;
   1267 
   1268 rescan:
   1269 	starttok = prestr;
   1270 
   1271 	if ((n = u8_rune(&rlxval, (const char *) prestr)) > 1) {
   1272 		prestr += n;
   1273 		starttok = prestr;
   1274 		return CHAR;
   1275 	}
   1276 
   1277 	switch (c = *prestr++) {
   1278 	case '|': return OR;
   1279 	case '*': return STAR;
   1280 	case '+': return PLUS;
   1281 	case '?': return QUEST;
   1282 	case '.': return DOT;
   1283 	case '\0': prestr--; return '\0';
   1284 	case '^':
   1285 	case '$':
   1286 		return c;
   1287 	case '(':
   1288 		parens++;
   1289 		return c;
   1290 	case ')':
   1291 		if (parens) {
   1292 			parens--;
   1293 			return c;
   1294 		}
   1295 		/* unmatched close parenthesis; per POSIX, treat as literal */
   1296 		rlxval = c;
   1297 		return CHAR;
   1298 	case '\\':
   1299 		rlxval = quoted(&prestr);
   1300 		return CHAR;
   1301 	default:
   1302 		rlxval = c;
   1303 		return CHAR;
   1304 	case '[':
   1305 		if (buf == NULL && (buf = (uschar *) malloc(bufsz)) == NULL)
   1306 			FATAL("out of space in reg expr %.10s..", lastre);
   1307 		bp = buf;
   1308 		if (*prestr == '^') {
   1309 			cflag = 1;
   1310 			prestr++;
   1311 		}
   1312 		else
   1313 			cflag = 0;
   1314 		n = 5 * strlen((const char *) prestr)+1; /* BUG: was 2.  what value? */
   1315 		if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, "relex1"))
   1316 			FATAL("out of space for reg expr %.10s...", lastre);
   1317 		for (; ; ) {
   1318 			if ((n = u8_rune(&rlxval, (const char *) prestr)) > 1) {
   1319 				for (i = 0; i < n; i++)
   1320 					*bp++ = *prestr++;
   1321 				continue;
   1322 			}
   1323 			if ((c = *prestr++) == '\\') {
   1324 				*bp++ = '\\';
   1325 				if ((c = *prestr++) == '\0')
   1326 					FATAL("nonterminated character class %.20s...", lastre);
   1327 				*bp++ = c;
   1328 			/* } else if (c == '\n') { */
   1329 			/* 	FATAL("newline in character class %.20s...", lastre); */
   1330 			} else if (c == '[' && *prestr == ':') {
   1331 				/* POSIX char class names, Dag-Erling Smorgrav, des (at) ofug.org */
   1332 				for (cc = charclasses; cc->cc_name; cc++)
   1333 					if (strncmp((const char *) prestr + 1, (const char *) cc->cc_name, cc->cc_namelen) == 0)
   1334 						break;
   1335 				if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' &&
   1336 				    prestr[2 + cc->cc_namelen] == ']') {
   1337 					prestr += cc->cc_namelen + 3;
   1338 					/*
   1339 					 * BUG: We begin at 1, instead of 0, since we
   1340 					 * would otherwise prematurely terminate the
   1341 					 * string for classes like [[:cntrl:]]. This
   1342 					 * means that we can't match the NUL character,
   1343 					 * not without first adapting the entire
   1344 					 * program to track each string's length.
   1345 					 */
   1346 					for (i = 1; i <= UCHAR_MAX; i++) {
   1347 						if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "relex2"))
   1348 						    FATAL("out of space for reg expr %.10s...", lastre);
   1349 						if (cc->cc_func(i)) {
   1350 							/* escape backslash */
   1351 							if (i == '\\') {
   1352 								*bp++ = '\\';
   1353 								n++;
   1354 							}
   1355 
   1356 							*bp++ = i;
   1357 							n++;
   1358 						}
   1359 					}
   1360 				} else
   1361 					*bp++ = c;
   1362 			} else if (c == '[' && *prestr == '.') {
   1363 				char collate_char;
   1364 				prestr++;
   1365 				collate_char = *prestr++;
   1366 				if (*prestr == '.' && prestr[1] == ']') {
   1367 					prestr += 2;
   1368 					/* Found it: map via locale TBD: for
   1369 					   now, simply return this char.  This
   1370 					   is sufficient to pass conformance
   1371 					   test awk.ex 156
   1372 					 */
   1373 					if (*prestr == ']') {
   1374 						prestr++;
   1375 						rlxval = collate_char;
   1376 						return CHAR;
   1377 					}
   1378 				}
   1379 			} else if (c == '[' && *prestr == '=') {
   1380 				char equiv_char;
   1381 				prestr++;
   1382 				equiv_char = *prestr++;
   1383 				if (*prestr == '=' && prestr[1] == ']') {
   1384 					prestr += 2;
   1385 					/* Found it: map via locale TBD: for now
   1386 					   simply return this char. This is
   1387 					   sufficient to pass conformance test
   1388 					   awk.ex 156
   1389 					 */
   1390 					if (*prestr == ']') {
   1391 						prestr++;
   1392 						rlxval = equiv_char;
   1393 						return CHAR;
   1394 					}
   1395 				}
   1396 			} else if (c == '\0') {
   1397 				FATAL("nonterminated character class %.20s", lastre);
   1398 			} else if (bp == buf) {	/* 1st char is special */
   1399 				*bp++ = c;
   1400 			} else if (c == ']') {
   1401 				*bp++ = 0;
   1402 				rlxstr = (uschar *) tostring((char *) buf);
   1403 				if (cflag == 0)
   1404 					return CCL;
   1405 				else
   1406 					return NCCL;
   1407 			} else
   1408 				*bp++ = c;
   1409 		}
   1410 		break;
   1411 	case '{':
   1412 		if (isdigit((int) *(prestr))) {
   1413 			num = 0;	/* Process as a repetition */
   1414 			n = -1; m = -1;
   1415 			commafound = false;
   1416 			digitfound = false;
   1417 			startreptok = prestr-1;
   1418 			/* Remember start of previous atom here ? */
   1419 		} else {        	/* just a { char, not a repetition */
   1420 			rlxval = c;
   1421 			return CHAR;
   1422                 }
   1423 		for (; ; ) {
   1424 			if ((c = *prestr++) == '}') {
   1425 				if (commafound) {
   1426 					if (digitfound) { /* {n,m} */
   1427 						m = num;
   1428 						if (m < n)
   1429 							FATAL("illegal repetition expression: class %.20s",
   1430 								lastre);
   1431 						if (n == 0 && m == 1) {
   1432 							return QUEST;
   1433 						}
   1434 					} else {	/* {n,} */
   1435 						if (n == 0)
   1436 							return STAR;
   1437 						else if (n == 1)
   1438 							return PLUS;
   1439 					}
   1440 				} else {
   1441 					if (digitfound) { /* {n} same as {n,n} */
   1442 						n = num;
   1443 						m = num;
   1444 					} else {	/* {} */
   1445 						FATAL("illegal repetition expression: class %.20s",
   1446 							lastre);
   1447 					}
   1448 				}
   1449 				if (repeat(starttok, prestr-starttok, lastatom,
   1450 					   startreptok - lastatom, n, m) > 0) {
   1451 					if (n == 0 && m == 0) {
   1452 						return ZERO;
   1453 					}
   1454 					/* must rescan input for next token */
   1455 					goto rescan;
   1456 				}
   1457 				/* Failed to replace: eat up {...} characters
   1458 				   and treat like just PLUS */
   1459 				return PLUS;
   1460 			} else if (c == '\0') {
   1461 				FATAL("nonterminated character class %.20s",
   1462 					lastre);
   1463 			} else if (isdigit(c)) {
   1464 				num = 10 * num + c - '0';
   1465 				if (num > 255)
   1466 					FATAL("repetition count %.20s too large",
   1467 						lastre);
   1468 				digitfound = true;
   1469 			} else if (c == ',') {
   1470 				if (commafound)
   1471 					FATAL("illegal repetition expression: class %.20s",
   1472 						lastre);
   1473 				/* looking for {n,} or {n,m} */
   1474 				commafound = true;
   1475 				n = num;
   1476 				digitfound = false; /* reset */
   1477 				num = 0;
   1478 			} else {
   1479 				FATAL("illegal repetition expression: class %.20s",
   1480 					lastre);
   1481 			}
   1482 		}
   1483 		break;
   1484 	}
   1485 }
   1486 
   1487 int cgoto(fa *f, int s, int c)
   1488 {
   1489 	int *p, *q;
   1490 	int i, j, k;
   1491 
   1492 	/* assert(c == HAT || c < NCHARS);  BUG: seg fault if disable test */
   1493 	while (f->accept >= maxsetvec) {	/* guessing here! */
   1494 		resizesetvec(__func__);
   1495 	}
   1496 	for (i = 0; i <= f->accept; i++)
   1497 		setvec[i] = 0;
   1498 	setcnt = 0;
   1499 	resize_state(f, s);
   1500 	/* compute positions of gototab[s,c] into setvec */
   1501 	p = f->posns[s];
   1502 	for (i = 1; i <= *p; i++) {
   1503 		if ((k = f->re[p[i]].ltype) != FINAL) {
   1504 			if ((k == CHAR && c == ptoi(f->re[p[i]].lval.np))
   1505 			 || (k == DOT && c != 0 && c != HAT)
   1506 			 || (k == ALL && c != 0)
   1507 			 || (k == EMPTYRE && c != 0)
   1508 			 || (k == CCL && member(c, (int *) f->re[p[i]].lval.rp))
   1509 			 || (k == NCCL && !member(c, (int *) f->re[p[i]].lval.rp) && c != 0 && c != HAT)) {
   1510 				q = f->re[p[i]].lfollow;
   1511 				for (j = 1; j <= *q; j++) {
   1512 					if (q[j] >= maxsetvec) {
   1513 						resizesetvec(__func__);
   1514 					}
   1515 					if (setvec[q[j]] == 0) {
   1516 						setcnt++;
   1517 						setvec[q[j]] = 1;
   1518 					}
   1519 				}
   1520 			}
   1521 		}
   1522 	}
   1523 	/* determine if setvec is a previous state */
   1524 	tmpset[0] = setcnt;
   1525 	j = 1;
   1526 	for (i = f->accept; i >= 0; i--)
   1527 		if (setvec[i]) {
   1528 			tmpset[j++] = i;
   1529 		}
   1530 	resize_state(f, f->curstat > s ? f->curstat : s);
   1531 	/* tmpset == previous state? */
   1532 	for (i = 1; i <= f->curstat; i++) {
   1533 		p = f->posns[i];
   1534 		if ((k = tmpset[0]) != p[0])
   1535 			goto different;
   1536 		for (j = 1; j <= k; j++)
   1537 			if (tmpset[j] != p[j])
   1538 				goto different;
   1539 		/* setvec is state i */
   1540 		if (c != HAT)
   1541 			set_gototab(f, s, c, i);
   1542 		return i;
   1543 	  different:;
   1544 	}
   1545 
   1546 	/* add tmpset to current set of states */
   1547 	++(f->curstat);
   1548 	resize_state(f, f->curstat);
   1549 	clear_gototab(f, f->curstat);
   1550 	xfree(f->posns[f->curstat]);
   1551 	p = intalloc(setcnt + 1, __func__);
   1552 
   1553 	f->posns[f->curstat] = p;
   1554 	if (c != HAT)
   1555 		set_gototab(f, s, c, f->curstat);
   1556 	for (i = 0; i <= setcnt; i++)
   1557 		p[i] = tmpset[i];
   1558 	if (setvec[f->accept])
   1559 		f->out[f->curstat] = 1;
   1560 	else
   1561 		f->out[f->curstat] = 0;
   1562 	return f->curstat;
   1563 }
   1564 
   1565 
   1566 void freefa(fa *f)	/* free a finite automaton */
   1567 {
   1568 	int i;
   1569 
   1570 	if (f == NULL)
   1571 		return;
   1572 	for (i = 0; i < f->state_count; i++)
   1573 		xfree(f->gototab[i].entries);
   1574 	xfree(f->gototab);
   1575 	for (i = 0; i <= f->curstat; i++)
   1576 		xfree(f->posns[i]);
   1577 	for (i = 0; i <= f->accept; i++) {
   1578 		xfree(f->re[i].lfollow);
   1579 		if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL)
   1580 			xfree(f->re[i].lval.np);
   1581 	}
   1582 	xfree(f->restr);
   1583 	xfree(f->out);
   1584 	xfree(f->posns);
   1585 	xfree(f->gototab);
   1586 	xfree(f);
   1587 }
   1588