xref: /original-bsd/old/regexp/regexp.c (revision 1470fd7b)
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