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