1*1470fd7bSroot #include <ctype.h>
2*1470fd7bSroot
3*1470fd7bSroot typedef int boolean;
4*1470fd7bSroot #define TRUE 1
5*1470fd7bSroot #define FALSE 0
6*1470fd7bSroot #define NIL 0
7*1470fd7bSroot
8*1470fd7bSroot boolean l_onecase; /* true if upper and lower equivalent */
9*1470fd7bSroot
10*1470fd7bSroot #define makelower(c) (isupper((c)) ? tolower((c)) : (c))
11*1470fd7bSroot
12*1470fd7bSroot /* STRNCMP - like strncmp except that we convert the
13*1470fd7bSroot * first string to lower case before comparing
14*1470fd7bSroot * if l_onecase is set.
15*1470fd7bSroot */
16*1470fd7bSroot
STRNCMP(s1,s2,len)17*1470fd7bSroot STRNCMP(s1, s2, len)
18*1470fd7bSroot register char *s1,*s2;
19*1470fd7bSroot register int len;
20*1470fd7bSroot {
21*1470fd7bSroot if (l_onecase) {
22*1470fd7bSroot do
23*1470fd7bSroot if (*s2 - makelower(*s1))
24*1470fd7bSroot return (*s2 - makelower(*s1));
25*1470fd7bSroot else {
26*1470fd7bSroot s2++;
27*1470fd7bSroot s1++;
28*1470fd7bSroot }
29*1470fd7bSroot while (--len);
30*1470fd7bSroot } else {
31*1470fd7bSroot do
32*1470fd7bSroot if (*s2 - *s1)
33*1470fd7bSroot return (*s2 - *s1);
34*1470fd7bSroot else {
35*1470fd7bSroot s2++;
36*1470fd7bSroot s1++;
37*1470fd7bSroot }
38*1470fd7bSroot while (--len);
39*1470fd7bSroot }
40*1470fd7bSroot return(0);
41*1470fd7bSroot }
42*1470fd7bSroot
43*1470fd7bSroot /* The following routine converts an irregular expression to
44*1470fd7bSroot * internal format.
45*1470fd7bSroot *
46*1470fd7bSroot * Either meta symbols (\a \d or \p) or character strings or
47*1470fd7bSroot * operations ( alternation or perenthesizing ) can be
48*1470fd7bSroot * specified. Each starts with a descriptor byte. The descriptor
49*1470fd7bSroot * byte has STR set for strings, META set for meta symbols
50*1470fd7bSroot * and OPER set for operations.
51*1470fd7bSroot * The descriptor byte can also have the OPT bit set if the object
52*1470fd7bSroot * defined is optional. Also ALT can be set to indicate an alternation.
53*1470fd7bSroot *
54*1470fd7bSroot * For metasymbols the byte following the descriptor byte identities
55*1470fd7bSroot * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For
56*1470fd7bSroot * strings the byte after the descriptor is a character count for
57*1470fd7bSroot * the string:
58*1470fd7bSroot *
59*1470fd7bSroot * meta symbols := descriptor
60*1470fd7bSroot * symbol
61*1470fd7bSroot *
62*1470fd7bSroot * strings := descriptor
63*1470fd7bSroot * character count
64*1470fd7bSroot * the string
65*1470fd7bSroot *
66*1470fd7bSroot * operatins := descriptor
67*1470fd7bSroot * symbol
68*1470fd7bSroot * character count
69*1470fd7bSroot */
70*1470fd7bSroot
71*1470fd7bSroot /*
72*1470fd7bSroot * handy macros for accessing parts of match blocks
73*1470fd7bSroot */
74*1470fd7bSroot #define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */
75*1470fd7bSroot #define MNEXT(A) (A+2) /* character following a metasymbol block */
76*1470fd7bSroot
77*1470fd7bSroot #define OSYM(A) (*(A+1)) /* symbol in an operation block */
78*1470fd7bSroot #define OCNT(A) (*(A+2)) /* character count */
79*1470fd7bSroot #define ONEXT(A) (A+3) /* next character after the operation */
80*1470fd7bSroot #define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */
81*1470fd7bSroot
82*1470fd7bSroot #define SCNT(A) (*(A+1)) /* byte count of a string */
83*1470fd7bSroot #define SSTR(A) (A+2) /* address of the string */
84*1470fd7bSroot #define SNEXT(A) (A+2+*(A+1)) /* character following the string */
85*1470fd7bSroot
86*1470fd7bSroot /*
87*1470fd7bSroot * bit flags in the descriptor
88*1470fd7bSroot */
89*1470fd7bSroot #define OPT 1
90*1470fd7bSroot #define STR 2
91*1470fd7bSroot #define META 4
92*1470fd7bSroot #define ALT 8
93*1470fd7bSroot #define OPER 16
94*1470fd7bSroot
95*1470fd7bSroot char *ure; /* pointer current position in unconverted exp */
96*1470fd7bSroot char *ccre; /* pointer to current position in converted exp*/
97*1470fd7bSroot char *malloc();
98*1470fd7bSroot
99*1470fd7bSroot char *
convexp(re)100*1470fd7bSroot convexp(re)
101*1470fd7bSroot char *re; /* unconverted irregular expression */
102*1470fd7bSroot {
103*1470fd7bSroot register char *cre; /* pointer to converted regular expression */
104*1470fd7bSroot
105*1470fd7bSroot /* allocate room for the converted expression */
106*1470fd7bSroot if (re == NIL)
107*1470fd7bSroot return (NIL);
108*1470fd7bSroot if (*re == '\0')
109*1470fd7bSroot return (NIL);
110*1470fd7bSroot cre = malloc (4 * strlen(re) + 3);
111*1470fd7bSroot ccre = cre;
112*1470fd7bSroot ure = re;
113*1470fd7bSroot
114*1470fd7bSroot /* start the conversion with a \a */
115*1470fd7bSroot *cre = META | OPT;
116*1470fd7bSroot MSYM(cre) = 'a';
117*1470fd7bSroot ccre = MNEXT(cre);
118*1470fd7bSroot
119*1470fd7bSroot /* start the conversion (its recursive) */
120*1470fd7bSroot expconv ();
121*1470fd7bSroot *ccre = 0;
122*1470fd7bSroot return (cre);
123*1470fd7bSroot }
124*1470fd7bSroot
expconv()125*1470fd7bSroot expconv()
126*1470fd7bSroot {
127*1470fd7bSroot register char *cs; /* pointer to current symbol in converted exp */
128*1470fd7bSroot register char c; /* character being processed */
129*1470fd7bSroot register char *acs; /* pinter to last alternate */
130*1470fd7bSroot register int temp;
131*1470fd7bSroot
132*1470fd7bSroot /* let the conversion begin */
133*1470fd7bSroot acs = NIL;
134*1470fd7bSroot while (*ure != NIL) {
135*1470fd7bSroot switch (c = *ure++) {
136*1470fd7bSroot
137*1470fd7bSroot case '\\':
138*1470fd7bSroot switch (c = *ure++) {
139*1470fd7bSroot
140*1470fd7bSroot /* escaped characters are just characters */
141*1470fd7bSroot default:
142*1470fd7bSroot if ((*cs & STR) == 0) {
143*1470fd7bSroot cs = ccre;
144*1470fd7bSroot *cs = STR;
145*1470fd7bSroot SCNT(cs) = 1;
146*1470fd7bSroot ccre += 2;
147*1470fd7bSroot } else
148*1470fd7bSroot SCNT(cs)++;
149*1470fd7bSroot *ccre++ = c;
150*1470fd7bSroot break;
151*1470fd7bSroot
152*1470fd7bSroot /* normal(?) metacharacters */
153*1470fd7bSroot case 'a':
154*1470fd7bSroot case 'd':
155*1470fd7bSroot case 'e':
156*1470fd7bSroot case 'p':
157*1470fd7bSroot if (acs != NIL && acs != cs) {
158*1470fd7bSroot do {
159*1470fd7bSroot temp = OCNT(acs);
160*1470fd7bSroot OCNT(acs) = ccre - acs;
161*1470fd7bSroot acs -= temp;
162*1470fd7bSroot } while (temp != 0);
163*1470fd7bSroot acs = NIL;
164*1470fd7bSroot }
165*1470fd7bSroot cs = ccre;
166*1470fd7bSroot *cs = META;
167*1470fd7bSroot MSYM(cs) = c;
168*1470fd7bSroot ccre = MNEXT(cs);
169*1470fd7bSroot break;
170*1470fd7bSroot }
171*1470fd7bSroot break;
172*1470fd7bSroot
173*1470fd7bSroot /* just put the symbol in */
174*1470fd7bSroot case '^':
175*1470fd7bSroot case '$':
176*1470fd7bSroot if (acs != NIL && acs != cs) {
177*1470fd7bSroot do {
178*1470fd7bSroot temp = OCNT(acs);
179*1470fd7bSroot OCNT(acs) = ccre - acs;
180*1470fd7bSroot acs -= temp;
181*1470fd7bSroot } while (temp != 0);
182*1470fd7bSroot acs = NIL;
183*1470fd7bSroot }
184*1470fd7bSroot cs = ccre;
185*1470fd7bSroot *cs = META;
186*1470fd7bSroot MSYM(cs) = c;
187*1470fd7bSroot ccre = MNEXT(cs);
188*1470fd7bSroot break;
189*1470fd7bSroot
190*1470fd7bSroot /* mark the last match sequence as optional */
191*1470fd7bSroot case '?':
192*1470fd7bSroot *cs = *cs | OPT;
193*1470fd7bSroot break;
194*1470fd7bSroot
195*1470fd7bSroot /* recurse and define a subexpression */
196*1470fd7bSroot case '(':
197*1470fd7bSroot if (acs != NIL && acs != cs) {
198*1470fd7bSroot do {
199*1470fd7bSroot temp = OCNT(acs);
200*1470fd7bSroot OCNT(acs) = ccre - acs;
201*1470fd7bSroot acs -= temp;
202*1470fd7bSroot } while (temp != 0);
203*1470fd7bSroot acs = NIL;
204*1470fd7bSroot }
205*1470fd7bSroot cs = ccre;
206*1470fd7bSroot *cs = OPER;
207*1470fd7bSroot OSYM(cs) = '(';
208*1470fd7bSroot ccre = ONEXT(cs);
209*1470fd7bSroot expconv ();
210*1470fd7bSroot OCNT(cs) = ccre - cs; /* offset to next symbol */
211*1470fd7bSroot break;
212*1470fd7bSroot
213*1470fd7bSroot /* return from a recursion */
214*1470fd7bSroot case ')':
215*1470fd7bSroot if (acs != NIL) {
216*1470fd7bSroot do {
217*1470fd7bSroot temp = OCNT(acs);
218*1470fd7bSroot OCNT(acs) = ccre - acs;
219*1470fd7bSroot acs -= temp;
220*1470fd7bSroot } while (temp != 0);
221*1470fd7bSroot acs = NIL;
222*1470fd7bSroot }
223*1470fd7bSroot cs = ccre;
224*1470fd7bSroot *cs = META;
225*1470fd7bSroot MSYM(cs) = c;
226*1470fd7bSroot ccre = MNEXT(cs);
227*1470fd7bSroot return;
228*1470fd7bSroot
229*1470fd7bSroot /* mark the last match sequence as having an alternate */
230*1470fd7bSroot /* the third byte will contain an offset to jump over the */
231*1470fd7bSroot /* alternate match in case the first did not fail */
232*1470fd7bSroot case '|':
233*1470fd7bSroot if (acs != NIL && acs != cs)
234*1470fd7bSroot OCNT(ccre) = ccre - acs; /* make a back pointer */
235*1470fd7bSroot else
236*1470fd7bSroot OCNT(ccre) = 0;
237*1470fd7bSroot *cs |= ALT;
238*1470fd7bSroot cs = ccre;
239*1470fd7bSroot *cs = OPER;
240*1470fd7bSroot OSYM(cs) = '|';
241*1470fd7bSroot ccre = ONEXT(cs);
242*1470fd7bSroot acs = cs; /* remember that the pointer is to be filles */
243*1470fd7bSroot break;
244*1470fd7bSroot
245*1470fd7bSroot /* if its not a metasymbol just build a scharacter string */
246*1470fd7bSroot default:
247*1470fd7bSroot if ((*cs & STR) == 0) {
248*1470fd7bSroot cs = ccre;
249*1470fd7bSroot *cs = STR;
250*1470fd7bSroot SCNT(cs) = 1;
251*1470fd7bSroot ccre = SSTR(cs);
252*1470fd7bSroot } else
253*1470fd7bSroot SCNT(cs)++;
254*1470fd7bSroot *ccre++ = c;
255*1470fd7bSroot break;
256*1470fd7bSroot }
257*1470fd7bSroot }
258*1470fd7bSroot if (acs != NIL) {
259*1470fd7bSroot do {
260*1470fd7bSroot temp = OCNT(acs);
261*1470fd7bSroot OCNT(acs) = ccre - acs;
262*1470fd7bSroot acs -= temp;
263*1470fd7bSroot } while (temp != 0);
264*1470fd7bSroot acs = NIL;
265*1470fd7bSroot }
266*1470fd7bSroot return;
267*1470fd7bSroot }
268*1470fd7bSroot /* end of convertre */
269*1470fd7bSroot
270*1470fd7bSroot
271*1470fd7bSroot /*
272*1470fd7bSroot * The following routine recognises an irregular expresion
273*1470fd7bSroot * with the following special characters:
274*1470fd7bSroot *
275*1470fd7bSroot * \? - means last match was optional
276*1470fd7bSroot * \a - matches any number of characters
277*1470fd7bSroot * \d - matches any number of spaces and tabs
278*1470fd7bSroot * \p - matches any number of alphanumeric
279*1470fd7bSroot * characters. The
280*1470fd7bSroot * characters matched will be copied into
281*1470fd7bSroot * the area pointed to by 'name'.
282*1470fd7bSroot * \| - alternation
283*1470fd7bSroot * \( \) - grouping used mostly for alternation and
284*1470fd7bSroot * optionality
285*1470fd7bSroot *
286*1470fd7bSroot * The irregular expression must be translated to internal form
287*1470fd7bSroot * prior to calling this routine
288*1470fd7bSroot *
289*1470fd7bSroot * The value returned is the pointer to the first non \a
290*1470fd7bSroot * character matched.
291*1470fd7bSroot */
292*1470fd7bSroot
293*1470fd7bSroot boolean _escaped; /* true if we are currently _escaped */
294*1470fd7bSroot char *_start; /* start of string */
295*1470fd7bSroot
296*1470fd7bSroot char *
expmatch(s,re,mstring)297*1470fd7bSroot expmatch (s, re, mstring)
298*1470fd7bSroot register char *s; /* string to check for a match in */
299*1470fd7bSroot register char *re; /* a converted irregular expression */
300*1470fd7bSroot register char *mstring; /* where to put whatever matches a \p */
301*1470fd7bSroot {
302*1470fd7bSroot register char *cs; /* the current symbol */
303*1470fd7bSroot register char *ptr,*s1; /* temporary pointer */
304*1470fd7bSroot boolean matched; /* a temporary boolean */
305*1470fd7bSroot
306*1470fd7bSroot /* initial conditions */
307*1470fd7bSroot if (re == NIL)
308*1470fd7bSroot return (NIL);
309*1470fd7bSroot cs = re;
310*1470fd7bSroot matched = FALSE;
311*1470fd7bSroot
312*1470fd7bSroot /* loop till expression string is exhausted (or at least pretty tired) */
313*1470fd7bSroot while (*cs) {
314*1470fd7bSroot switch (*cs & (OPER | STR | META)) {
315*1470fd7bSroot
316*1470fd7bSroot /* try to match a string */
317*1470fd7bSroot case STR:
318*1470fd7bSroot matched = !STRNCMP (s, SSTR(cs), SCNT(cs));
319*1470fd7bSroot if (matched) {
320*1470fd7bSroot
321*1470fd7bSroot /* hoorah it matches */
322*1470fd7bSroot s += SCNT(cs);
323*1470fd7bSroot cs = SNEXT(cs);
324*1470fd7bSroot } else if (*cs & ALT) {
325*1470fd7bSroot
326*1470fd7bSroot /* alternation, skip to next expression */
327*1470fd7bSroot cs = SNEXT(cs);
328*1470fd7bSroot } else if (*cs & OPT) {
329*1470fd7bSroot
330*1470fd7bSroot /* the match is optional */
331*1470fd7bSroot cs = SNEXT(cs);
332*1470fd7bSroot matched = 1; /* indicate a successful match */
333*1470fd7bSroot } else {
334*1470fd7bSroot
335*1470fd7bSroot /* no match, error return */
336*1470fd7bSroot return (NIL);
337*1470fd7bSroot }
338*1470fd7bSroot break;
339*1470fd7bSroot
340*1470fd7bSroot /* an operator, do something fancy */
341*1470fd7bSroot case OPER:
342*1470fd7bSroot switch (OSYM(cs)) {
343*1470fd7bSroot
344*1470fd7bSroot /* this is an alternation */
345*1470fd7bSroot case '|':
346*1470fd7bSroot if (matched)
347*1470fd7bSroot
348*1470fd7bSroot /* last thing in the alternation was a match, skip ahead */
349*1470fd7bSroot cs = OPTR(cs);
350*1470fd7bSroot else
351*1470fd7bSroot
352*1470fd7bSroot /* no match, keep trying */
353*1470fd7bSroot cs = ONEXT(cs);
354*1470fd7bSroot break;
355*1470fd7bSroot
356*1470fd7bSroot /* this is a grouping, recurse */
357*1470fd7bSroot case '(':
358*1470fd7bSroot ptr = expmatch (s, ONEXT(cs), mstring);
359*1470fd7bSroot if (ptr != NIL) {
360*1470fd7bSroot
361*1470fd7bSroot /* the subexpression matched */
362*1470fd7bSroot matched = 1;
363*1470fd7bSroot s = ptr;
364*1470fd7bSroot } else if (*cs & ALT) {
365*1470fd7bSroot
366*1470fd7bSroot /* alternation, skip to next expression */
367*1470fd7bSroot matched = 0;
368*1470fd7bSroot } else if (*cs & OPT) {
369*1470fd7bSroot
370*1470fd7bSroot /* the match is optional */
371*1470fd7bSroot matched = 1; /* indicate a successful match */
372*1470fd7bSroot } else {
373*1470fd7bSroot
374*1470fd7bSroot /* no match, error return */
375*1470fd7bSroot return (NIL);
376*1470fd7bSroot }
377*1470fd7bSroot cs = OPTR(cs);
378*1470fd7bSroot break;
379*1470fd7bSroot }
380*1470fd7bSroot break;
381*1470fd7bSroot
382*1470fd7bSroot /* try to match a metasymbol */
383*1470fd7bSroot case META:
384*1470fd7bSroot switch (MSYM(cs)) {
385*1470fd7bSroot
386*1470fd7bSroot /* try to match anything and remember what was matched */
387*1470fd7bSroot case 'p':
388*1470fd7bSroot /*
389*1470fd7bSroot * This is really the same as trying the match the
390*1470fd7bSroot * remaining parts of the expression to any subset
391*1470fd7bSroot * of the string.
392*1470fd7bSroot */
393*1470fd7bSroot s1 = s;
394*1470fd7bSroot do {
395*1470fd7bSroot ptr = expmatch (s1, MNEXT(cs), mstring);
396*1470fd7bSroot if (ptr != NIL && s1 != s) {
397*1470fd7bSroot
398*1470fd7bSroot /* we have a match, remember the match */
399*1470fd7bSroot strncpy (mstring, s, s1 - s);
400*1470fd7bSroot mstring[s1 - s] = '\0';
401*1470fd7bSroot return (ptr);
402*1470fd7bSroot } else if (ptr != NIL && (*cs & OPT)) {
403*1470fd7bSroot
404*1470fd7bSroot /* it was aoptional so no match is ok */
405*1470fd7bSroot return (ptr);
406*1470fd7bSroot } else if (ptr != NIL) {
407*1470fd7bSroot
408*1470fd7bSroot /* not optional and we still matched */
409*1470fd7bSroot return (NIL);
410*1470fd7bSroot }
411*1470fd7bSroot if (!isalnum(*s1) && *s1 != '_')
412*1470fd7bSroot return (NIL);
413*1470fd7bSroot if (*s1 == '\\')
414*1470fd7bSroot _escaped = _escaped ? FALSE : TRUE;
415*1470fd7bSroot else
416*1470fd7bSroot _escaped = FALSE;
417*1470fd7bSroot } while (*s1++);
418*1470fd7bSroot return (NIL);
419*1470fd7bSroot
420*1470fd7bSroot /* try to match anything */
421*1470fd7bSroot case 'a':
422*1470fd7bSroot /*
423*1470fd7bSroot * This is really the same as trying the match the
424*1470fd7bSroot * remaining parts of the expression to any subset
425*1470fd7bSroot * of the string.
426*1470fd7bSroot */
427*1470fd7bSroot s1 = s;
428*1470fd7bSroot do {
429*1470fd7bSroot ptr = expmatch (s1, MNEXT(cs), mstring);
430*1470fd7bSroot if (ptr != NIL && s1 != s) {
431*1470fd7bSroot
432*1470fd7bSroot /* we have a match */
433*1470fd7bSroot return (ptr);
434*1470fd7bSroot } else if (ptr != NIL && (*cs & OPT)) {
435*1470fd7bSroot
436*1470fd7bSroot /* it was aoptional so no match is ok */
437*1470fd7bSroot return (ptr);
438*1470fd7bSroot } else if (ptr != NIL) {
439*1470fd7bSroot
440*1470fd7bSroot /* not optional and we still matched */
441*1470fd7bSroot return (NIL);
442*1470fd7bSroot }
443*1470fd7bSroot if (*s1 == '\\')
444*1470fd7bSroot _escaped = _escaped ? FALSE : TRUE;
445*1470fd7bSroot else
446*1470fd7bSroot _escaped = FALSE;
447*1470fd7bSroot } while (*s1++);
448*1470fd7bSroot return (NIL);
449*1470fd7bSroot
450*1470fd7bSroot /* fail if we are currently _escaped */
451*1470fd7bSroot case 'e':
452*1470fd7bSroot if (_escaped)
453*1470fd7bSroot return(NIL);
454*1470fd7bSroot cs = MNEXT(cs);
455*1470fd7bSroot break;
456*1470fd7bSroot
457*1470fd7bSroot /* match any number of tabs and spaces */
458*1470fd7bSroot case 'd':
459*1470fd7bSroot ptr = s;
460*1470fd7bSroot while (*s == ' ' || *s == '\t')
461*1470fd7bSroot s++;
462*1470fd7bSroot if (s != ptr || s == _start) {
463*1470fd7bSroot
464*1470fd7bSroot /* match, be happy */
465*1470fd7bSroot matched = 1;
466*1470fd7bSroot cs = MNEXT(cs);
467*1470fd7bSroot } else if (*s == '\n' || *s == '\0') {
468*1470fd7bSroot
469*1470fd7bSroot /* match, be happy */
470*1470fd7bSroot matched = 1;
471*1470fd7bSroot cs = MNEXT(cs);
472*1470fd7bSroot } else if (*cs & ALT) {
473*1470fd7bSroot
474*1470fd7bSroot /* try the next part */
475*1470fd7bSroot matched = 0;
476*1470fd7bSroot cs = MNEXT(cs);
477*1470fd7bSroot } else if (*cs & OPT) {
478*1470fd7bSroot
479*1470fd7bSroot /* doesn't matter */
480*1470fd7bSroot matched = 1;
481*1470fd7bSroot cs = MNEXT(cs);
482*1470fd7bSroot } else
483*1470fd7bSroot
484*1470fd7bSroot /* no match, error return */
485*1470fd7bSroot return (NIL);
486*1470fd7bSroot break;
487*1470fd7bSroot
488*1470fd7bSroot /* check for end of line */
489*1470fd7bSroot case '$':
490*1470fd7bSroot if (*s == '\0' || *s == '\n') {
491*1470fd7bSroot
492*1470fd7bSroot /* match, be happy */
493*1470fd7bSroot s++;
494*1470fd7bSroot matched = 1;
495*1470fd7bSroot cs = MNEXT(cs);
496*1470fd7bSroot } else if (*cs & ALT) {
497*1470fd7bSroot
498*1470fd7bSroot /* try the next part */
499*1470fd7bSroot matched = 0;
500*1470fd7bSroot cs = MNEXT(cs);
501*1470fd7bSroot } else if (*cs & OPT) {
502*1470fd7bSroot
503*1470fd7bSroot /* doesn't matter */
504*1470fd7bSroot matched = 1;
505*1470fd7bSroot cs = MNEXT(cs);
506*1470fd7bSroot } else
507*1470fd7bSroot
508*1470fd7bSroot /* no match, error return */
509*1470fd7bSroot return (NIL);
510*1470fd7bSroot break;
511*1470fd7bSroot
512*1470fd7bSroot /* check for start of line */
513*1470fd7bSroot case '^':
514*1470fd7bSroot if (s == _start) {
515*1470fd7bSroot
516*1470fd7bSroot /* match, be happy */
517*1470fd7bSroot matched = 1;
518*1470fd7bSroot cs = MNEXT(cs);
519*1470fd7bSroot } else if (*cs & ALT) {
520*1470fd7bSroot
521*1470fd7bSroot /* try the next part */
522*1470fd7bSroot matched = 0;
523*1470fd7bSroot cs = MNEXT(cs);
524*1470fd7bSroot } else if (*cs & OPT) {
525*1470fd7bSroot
526*1470fd7bSroot /* doesn't matter */
527*1470fd7bSroot matched = 1;
528*1470fd7bSroot cs = MNEXT(cs);
529*1470fd7bSroot } else
530*1470fd7bSroot
531*1470fd7bSroot /* no match, error return */
532*1470fd7bSroot return (NIL);
533*1470fd7bSroot break;
534*1470fd7bSroot
535*1470fd7bSroot /* end of a subexpression, return success */
536*1470fd7bSroot case ')':
537*1470fd7bSroot return (s);
538*1470fd7bSroot }
539*1470fd7bSroot break;
540*1470fd7bSroot }
541*1470fd7bSroot }
542*1470fd7bSroot return (s);
543*1470fd7bSroot }
544