xref: /csrg-svn/usr.bin/vgrind/regexp.c (revision 56144)
122063Sdist /*
236167Sbostic  * Copyright (c) 1980 The Regents of the University of California.
336167Sbostic  * All rights reserved.
436167Sbostic  *
5*56144Selan  * Redistribution and use in source and binary forms, with or without
6*56144Selan  * modification, are permitted provided that the following conditions
7*56144Selan  * are met:
8*56144Selan  * 1. Redistributions of source code must retain the above copyright
9*56144Selan  *    notice, this list of conditions and the following disclaimer.
10*56144Selan  * 2. Redistributions in binary form must reproduce the above copyright
11*56144Selan  *    notice, this list of conditions and the following disclaimer in the
12*56144Selan  *    documentation and/or other materials provided with the distribution.
13*56144Selan  * 3. All advertising materials mentioning features or use of this software
14*56144Selan  *    must display the following acknowledgement:
15*56144Selan  *	This product includes software developed by the University of
16*56144Selan  *	California, Berkeley and its contributors.
17*56144Selan  * 4. Neither the name of the University nor the names of its contributors
18*56144Selan  *    may be used to endorse or promote products derived from this software
19*56144Selan  *    without specific prior written permission.
20*56144Selan  *
21*56144Selan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*56144Selan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*56144Selan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*56144Selan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*56144Selan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*56144Selan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*56144Selan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*56144Selan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*56144Selan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*56144Selan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*56144Selan  * SUCH DAMAGE.
3222063Sdist  */
338659Smckusick 
3422063Sdist #ifndef lint
35*56144Selan static char sccsid[] = "@(#)regexp.c	5.4 (Berkeley) 8/3/92";
3636167Sbostic #endif /* not lint */
3722063Sdist 
388659Smckusick #include <ctype.h>
39*56144Selan #include <stdlib.h>
40*56144Selan #include <string.h>
41*56144Selan #include "extern.h"
428659Smckusick 
438659Smckusick #define FALSE	0
44*56144Selan #define TRUE	!(FALSE)
458659Smckusick #define NIL	0
468659Smckusick 
47*56144Selan static void	expconv __P((void));
488659Smckusick 
49*56144Selan boolean	 _escaped;	/* true if we are currently _escaped */
50*56144Selan char	*_start;	/* start of string */
51*56144Selan boolean	 l_onecase;	/* true if upper and lower equivalent */
52*56144Selan 
538659Smckusick #define makelower(c) (isupper((c)) ? tolower((c)) : (c))
548659Smckusick 
558659Smckusick /*  STRNCMP -	like strncmp except that we convert the
568659Smckusick  *	 	first string to lower case before comparing
578659Smckusick  *		if l_onecase is set.
588659Smckusick  */
598659Smckusick 
60*56144Selan int
618659Smckusick STRNCMP(s1, s2, len)
628659Smckusick 	register char *s1,*s2;
638659Smckusick 	register int len;
648659Smckusick {
658659Smckusick 	if (l_onecase) {
668659Smckusick 	    do
678659Smckusick 		if (*s2 - makelower(*s1))
688659Smckusick 			return (*s2 - makelower(*s1));
698659Smckusick 		else {
708659Smckusick 			s2++;
718659Smckusick 			s1++;
728659Smckusick 		}
738659Smckusick 	    while (--len);
748659Smckusick 	} else {
758659Smckusick 	    do
768659Smckusick 		if (*s2 - *s1)
778659Smckusick 			return (*s2 - *s1);
788659Smckusick 		else {
798659Smckusick 			s2++;
808659Smckusick 			s1++;
818659Smckusick 		}
828659Smckusick 	    while (--len);
838659Smckusick 	}
848659Smckusick 	return(0);
858659Smckusick }
868659Smckusick 
878659Smckusick /*	The following routine converts an irregular expression to
888659Smckusick  *	internal format.
898659Smckusick  *
908659Smckusick  *	Either meta symbols (\a \d or \p) or character strings or
918659Smckusick  *	operations ( alternation or perenthesizing ) can be
928659Smckusick  *	specified.  Each starts with a descriptor byte.  The descriptor
938659Smckusick  *	byte has STR set for strings, META set for meta symbols
948659Smckusick  *	and OPER set for operations.
958659Smckusick  *	The descriptor byte can also have the OPT bit set if the object
968659Smckusick  *	defined is optional.  Also ALT can be set to indicate an alternation.
978659Smckusick  *
988659Smckusick  *	For metasymbols the byte following the descriptor byte identities
998659Smckusick  *	the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '(').  For
1008659Smckusick  *	strings the byte after the descriptor is a character count for
1018659Smckusick  *	the string:
1028659Smckusick  *
1038659Smckusick  *		meta symbols := descriptor
1048659Smckusick  *				symbol
1058659Smckusick  *
1068659Smckusick  *		strings :=	descriptor
1078659Smckusick  *				character count
1088659Smckusick  *				the string
1098659Smckusick  *
1108659Smckusick  *		operatins :=	descriptor
1118659Smckusick  *				symbol
1128659Smckusick  *				character count
1138659Smckusick  */
1148659Smckusick 
1158659Smckusick /*
1168659Smckusick  *  handy macros for accessing parts of match blocks
1178659Smckusick  */
1188659Smckusick #define MSYM(A) (*(A+1))	/* symbol in a meta symbol block */
1198659Smckusick #define MNEXT(A) (A+2)		/* character following a metasymbol block */
1208659Smckusick 
1218659Smckusick #define OSYM(A) (*(A+1))	/* symbol in an operation block */
1228659Smckusick #define OCNT(A) (*(A+2))	/* character count */
1238659Smckusick #define ONEXT(A) (A+3)		/* next character after the operation */
1248659Smckusick #define OPTR(A) (A+*(A+2))	/* place pointed to by the operator */
1258659Smckusick 
1268659Smckusick #define SCNT(A) (*(A+1))	/* byte count of a string */
1278659Smckusick #define SSTR(A) (A+2)		/* address of the string */
1288659Smckusick #define SNEXT(A) (A+2+*(A+1))	/* character following the string */
1298659Smckusick 
1308659Smckusick /*
1318659Smckusick  *  bit flags in the descriptor
1328659Smckusick  */
1338659Smckusick #define OPT 1
1348659Smckusick #define STR 2
1358659Smckusick #define META 4
1368659Smckusick #define ALT 8
1378659Smckusick #define OPER 16
1388659Smckusick 
139*56144Selan static char *ccre;	/* pointer to current position in converted exp*/
140*56144Selan static char *ure;	/* pointer current position in unconverted exp */
1418659Smckusick 
1428659Smckusick char *
1438659Smckusick convexp(re)
1448659Smckusick     char *re;		/* unconverted irregular expression */
1458659Smckusick {
1468659Smckusick     register char *cre;		/* pointer to converted regular expression */
1478659Smckusick 
1488659Smckusick     /* allocate room for the converted expression */
1498659Smckusick     if (re == NIL)
1508659Smckusick 	return (NIL);
1518659Smckusick     if (*re == '\0')
1528659Smckusick 	return (NIL);
1538659Smckusick     cre = malloc (4 * strlen(re) + 3);
1548659Smckusick     ccre = cre;
1558659Smckusick     ure = re;
1568659Smckusick 
1578659Smckusick     /* start the conversion with a \a */
1588659Smckusick     *cre = META | OPT;
1598659Smckusick     MSYM(cre) = 'a';
1608659Smckusick     ccre = MNEXT(cre);
1618659Smckusick 
1628659Smckusick     /* start the conversion (its recursive) */
1638659Smckusick     expconv ();
1648659Smckusick     *ccre = 0;
1658659Smckusick     return (cre);
1668659Smckusick }
1678659Smckusick 
168*56144Selan static void
1698659Smckusick expconv()
1708659Smckusick {
1718659Smckusick     register char *cs;		/* pointer to current symbol in converted exp */
1728659Smckusick     register char c;		/* character being processed */
1738659Smckusick     register char *acs;		/* pinter to last alternate */
1748659Smckusick     register int temp;
1758659Smckusick 
1768659Smckusick     /* let the conversion begin */
1778659Smckusick     acs = NIL;
17817500Sralph     cs = NIL;
1798659Smckusick     while (*ure != NIL) {
1808659Smckusick 	switch (c = *ure++) {
1818659Smckusick 
1828659Smckusick 	case '\\':
1838659Smckusick 	    switch (c = *ure++) {
1848659Smckusick 
1858659Smckusick 	    /* escaped characters are just characters */
1868659Smckusick 	    default:
18717500Sralph 		if (cs == NIL || (*cs & STR) == 0) {
1888659Smckusick 		    cs = ccre;
1898659Smckusick 		    *cs = STR;
1908659Smckusick 		    SCNT(cs) = 1;
1918659Smckusick 		    ccre += 2;
1928659Smckusick 		} else
1938659Smckusick 		    SCNT(cs)++;
1948659Smckusick 		*ccre++ = c;
1958659Smckusick 		break;
1968659Smckusick 
1978659Smckusick 	    /* normal(?) metacharacters */
1988659Smckusick 	    case 'a':
1998659Smckusick 	    case 'd':
2008659Smckusick 	    case 'e':
2018659Smckusick 	    case 'p':
2028659Smckusick 		if (acs != NIL && acs != cs) {
2038659Smckusick 		    do {
2048659Smckusick 			temp = OCNT(acs);
2058659Smckusick 			OCNT(acs) = ccre - acs;
2068659Smckusick 			acs -= temp;
2078659Smckusick 		    } while (temp != 0);
2088659Smckusick 		    acs = NIL;
2098659Smckusick 		}
2108659Smckusick 		cs = ccre;
2118659Smckusick 		*cs = META;
2128659Smckusick 		MSYM(cs) = c;
2138659Smckusick 		ccre = MNEXT(cs);
2148659Smckusick 		break;
2158659Smckusick 	    }
2168659Smckusick 	    break;
2178659Smckusick 
2188659Smckusick 	/* just put the symbol in */
2198659Smckusick 	case '^':
2208659Smckusick 	case '$':
2218659Smckusick 	    if (acs != NIL && acs != cs) {
2228659Smckusick 		do {
2238659Smckusick 		    temp = OCNT(acs);
2248659Smckusick 		    OCNT(acs) = ccre - acs;
2258659Smckusick 		    acs -= temp;
2268659Smckusick 		} while (temp != 0);
2278659Smckusick 		acs = NIL;
2288659Smckusick 	    }
2298659Smckusick 	    cs = ccre;
2308659Smckusick 	    *cs = META;
2318659Smckusick 	    MSYM(cs) = c;
2328659Smckusick 	    ccre = MNEXT(cs);
2338659Smckusick 	    break;
2348659Smckusick 
2358659Smckusick 	/* mark the last match sequence as optional */
2368659Smckusick 	case '?':
23717500Sralph 	    if (cs)
23817500Sralph 	    	*cs = *cs | OPT;
2398659Smckusick 	    break;
2408659Smckusick 
2418659Smckusick 	/* recurse and define a subexpression */
2428659Smckusick 	case '(':
2438659Smckusick 	    if (acs != NIL && acs != cs) {
2448659Smckusick 		do {
2458659Smckusick 		    temp = OCNT(acs);
2468659Smckusick 		    OCNT(acs) = ccre - acs;
2478659Smckusick 		    acs -= temp;
2488659Smckusick 		} while (temp != 0);
2498659Smckusick 		acs = NIL;
2508659Smckusick 	    }
2518659Smckusick 	    cs = ccre;
2528659Smckusick 	    *cs = OPER;
2538659Smckusick 	    OSYM(cs) = '(';
2548659Smckusick 	    ccre = ONEXT(cs);
2558659Smckusick 	    expconv ();
2568659Smckusick 	    OCNT(cs) = ccre - cs;		/* offset to next symbol */
2578659Smckusick 	    break;
2588659Smckusick 
259*56144Selan 	/* reurn from a recursion */
2608659Smckusick 	case ')':
2618659Smckusick 	    if (acs != NIL) {
2628659Smckusick 		do {
2638659Smckusick 		    temp = OCNT(acs);
2648659Smckusick 		    OCNT(acs) = ccre - acs;
2658659Smckusick 		    acs -= temp;
2668659Smckusick 		} while (temp != 0);
2678659Smckusick 		acs = NIL;
2688659Smckusick 	    }
2698659Smckusick 	    cs = ccre;
2708659Smckusick 	    *cs = META;
2718659Smckusick 	    MSYM(cs) = c;
2728659Smckusick 	    ccre = MNEXT(cs);
2738659Smckusick 	    return;
2748659Smckusick 
2758659Smckusick 	/* mark the last match sequence as having an alternate */
2768659Smckusick 	/* the third byte will contain an offset to jump over the */
2778659Smckusick 	/* alternate match in case the first did not fail */
2788659Smckusick 	case '|':
2798659Smckusick 	    if (acs != NIL && acs != cs)
2808659Smckusick 		OCNT(ccre) = ccre - acs;	/* make a back pointer */
2818659Smckusick 	    else
2828659Smckusick 		OCNT(ccre) = 0;
2838659Smckusick 	    *cs |= ALT;
2848659Smckusick 	    cs = ccre;
2858659Smckusick 	    *cs = OPER;
2868659Smckusick 	    OSYM(cs) = '|';
2878659Smckusick 	    ccre = ONEXT(cs);
2888659Smckusick 	    acs = cs;	/* remember that the pointer is to be filles */
2898659Smckusick 	    break;
2908659Smckusick 
2918659Smckusick 	/* if its not a metasymbol just build a scharacter string */
2928659Smckusick 	default:
29317500Sralph 	    if (cs == NIL || (*cs & STR) == 0) {
2948659Smckusick 		cs = ccre;
2958659Smckusick 		*cs = STR;
2968659Smckusick 		SCNT(cs) = 1;
2978659Smckusick 		ccre = SSTR(cs);
2988659Smckusick 	    } else
2998659Smckusick 		SCNT(cs)++;
3008659Smckusick 	    *ccre++ = c;
3018659Smckusick 	    break;
3028659Smckusick 	}
3038659Smckusick     }
3048659Smckusick     if (acs != NIL) {
3058659Smckusick 	do {
3068659Smckusick 	    temp = OCNT(acs);
3078659Smckusick 	    OCNT(acs) = ccre - acs;
3088659Smckusick 	    acs -= temp;
3098659Smckusick 	} while (temp != 0);
3108659Smckusick 	acs = NIL;
3118659Smckusick     }
3128659Smckusick     return;
3138659Smckusick }
3148659Smckusick /* end of convertre */
3158659Smckusick 
3168659Smckusick 
3178659Smckusick /*
3188659Smckusick  *	The following routine recognises an irregular expresion
3198659Smckusick  *	with the following special characters:
3208659Smckusick  *
3218659Smckusick  *		\?	-	means last match was optional
3228659Smckusick  *		\a	-	matches any number of characters
3238659Smckusick  *		\d	-	matches any number of spaces and tabs
3248659Smckusick  *		\p	-	matches any number of alphanumeric
3258659Smckusick  *				characters. The
3268659Smckusick  *				characters matched will be copied into
3278659Smckusick  *				the area pointed to by 'name'.
3288659Smckusick  *		\|	-	alternation
3298659Smckusick  *		\( \)	-	grouping used mostly for alternation and
3308659Smckusick  *				optionality
3318659Smckusick  *
3328659Smckusick  *	The irregular expression must be translated to internal form
3338659Smckusick  *	prior to calling this routine
3348659Smckusick  *
3358659Smckusick  *	The value returned is the pointer to the first non \a
3368659Smckusick  *	character matched.
3378659Smckusick  */
3388659Smckusick 
3398659Smckusick char *
3408659Smckusick expmatch (s, re, mstring)
3418659Smckusick     register char *s;		/* string to check for a match in */
3428659Smckusick     register char *re;		/* a converted irregular expression */
3438659Smckusick     register char *mstring;	/* where to put whatever matches a \p */
3448659Smckusick {
3458659Smckusick     register char *cs;		/* the current symbol */
3468659Smckusick     register char *ptr,*s1;	/* temporary pointer */
3478659Smckusick     boolean matched;		/* a temporary boolean */
3488659Smckusick 
3498659Smckusick     /* initial conditions */
3508659Smckusick     if (re == NIL)
3518659Smckusick 	return (NIL);
3528659Smckusick     cs = re;
3538659Smckusick     matched = FALSE;
3548659Smckusick 
3558659Smckusick     /* loop till expression string is exhausted (or at least pretty tired) */
3568659Smckusick     while (*cs) {
3578659Smckusick 	switch (*cs & (OPER | STR | META)) {
3588659Smckusick 
3598659Smckusick 	/* try to match a string */
3608659Smckusick 	case STR:
3618659Smckusick 	    matched = !STRNCMP (s, SSTR(cs), SCNT(cs));
3628659Smckusick 	    if (matched) {
3638659Smckusick 
3648659Smckusick 		/* hoorah it matches */
3658659Smckusick 		s += SCNT(cs);
3668659Smckusick 		cs = SNEXT(cs);
3678659Smckusick 	    } else if (*cs & ALT) {
3688659Smckusick 
3698659Smckusick 		/* alternation, skip to next expression */
3708659Smckusick 		cs = SNEXT(cs);
3718659Smckusick 	    } else if (*cs & OPT) {
3728659Smckusick 
3738659Smckusick 		/* the match is optional */
3748659Smckusick 		cs = SNEXT(cs);
3758659Smckusick 		matched = 1;		/* indicate a successful match */
3768659Smckusick 	    } else {
3778659Smckusick 
3788659Smckusick 		/* no match, error return */
3798659Smckusick 		return (NIL);
3808659Smckusick 	    }
3818659Smckusick 	    break;
3828659Smckusick 
3838659Smckusick 	/* an operator, do something fancy */
3848659Smckusick 	case OPER:
3858659Smckusick 	    switch (OSYM(cs)) {
3868659Smckusick 
3878659Smckusick 	    /* this is an alternation */
3888659Smckusick 	    case '|':
3898659Smckusick 		if (matched)
3908659Smckusick 
3918659Smckusick 		    /* last thing in the alternation was a match, skip ahead */
3928659Smckusick 		    cs = OPTR(cs);
3938659Smckusick 		else
3948659Smckusick 
3958659Smckusick 		    /* no match, keep trying */
3968659Smckusick 		    cs = ONEXT(cs);
3978659Smckusick 		break;
3988659Smckusick 
3998659Smckusick 	    /* this is a grouping, recurse */
4008659Smckusick 	    case '(':
4018659Smckusick 		ptr = expmatch (s, ONEXT(cs), mstring);
4028659Smckusick 		if (ptr != NIL) {
4038659Smckusick 
4048659Smckusick 		    /* the subexpression matched */
4058659Smckusick 		    matched = 1;
4068659Smckusick 		    s = ptr;
4078659Smckusick 		} else if (*cs & ALT) {
4088659Smckusick 
4098659Smckusick 		    /* alternation, skip to next expression */
4108659Smckusick 		    matched = 0;
4118659Smckusick 		} else if (*cs & OPT) {
4128659Smckusick 
4138659Smckusick 		    /* the match is optional */
4148659Smckusick 		    matched = 1;	/* indicate a successful match */
4158659Smckusick 		} else {
4168659Smckusick 
4178659Smckusick 		    /* no match, error return */
4188659Smckusick 		    return (NIL);
4198659Smckusick 		}
4208659Smckusick 		cs = OPTR(cs);
4218659Smckusick 		break;
4228659Smckusick 	    }
4238659Smckusick 	    break;
4248659Smckusick 
4258659Smckusick 	/* try to match a metasymbol */
4268659Smckusick 	case META:
4278659Smckusick 	    switch (MSYM(cs)) {
4288659Smckusick 
4298659Smckusick 	    /* try to match anything and remember what was matched */
4308659Smckusick 	    case 'p':
4318659Smckusick 		/*
4328659Smckusick 		 *  This is really the same as trying the match the
4338659Smckusick 		 *  remaining parts of the expression to any subset
4348659Smckusick 		 *  of the string.
4358659Smckusick 		 */
4368659Smckusick 		s1 = s;
4378659Smckusick 		do {
4388659Smckusick 		    ptr = expmatch (s1, MNEXT(cs), mstring);
4398659Smckusick 		    if (ptr != NIL && s1 != s) {
4408659Smckusick 
4418659Smckusick 			/* we have a match, remember the match */
4428659Smckusick 			strncpy (mstring, s, s1 - s);
4438659Smckusick 			mstring[s1 - s] = '\0';
4448659Smckusick 			return (ptr);
4458659Smckusick 		    } else if (ptr != NIL && (*cs & OPT)) {
4468659Smckusick 
4478659Smckusick 			/* it was aoptional so no match is ok */
4488659Smckusick 			return (ptr);
4498659Smckusick 		    } else if (ptr != NIL) {
4508659Smckusick 
4518659Smckusick 			/* not optional and we still matched */
4528659Smckusick 			return (NIL);
4538659Smckusick 		    }
4548659Smckusick 		    if (!isalnum(*s1) && *s1 != '_')
4558659Smckusick 			return (NIL);
4568659Smckusick 		    if (*s1 == '\\')
4578659Smckusick 			_escaped = _escaped ? FALSE : TRUE;
4588659Smckusick 		    else
4598659Smckusick 			_escaped = FALSE;
4608659Smckusick 		} while (*s1++);
4618659Smckusick 		return (NIL);
4628659Smckusick 
4638659Smckusick 	    /* try to match anything */
4648659Smckusick 	    case 'a':
4658659Smckusick 		/*
4668659Smckusick 		 *  This is really the same as trying the match the
4678659Smckusick 		 *  remaining parts of the expression to any subset
4688659Smckusick 		 *  of the string.
4698659Smckusick 		 */
4708659Smckusick 		s1 = s;
4718659Smckusick 		do {
4728659Smckusick 		    ptr = expmatch (s1, MNEXT(cs), mstring);
4738659Smckusick 		    if (ptr != NIL && s1 != s) {
4748659Smckusick 
4758659Smckusick 			/* we have a match */
4768659Smckusick 			return (ptr);
4778659Smckusick 		    } else if (ptr != NIL && (*cs & OPT)) {
4788659Smckusick 
4798659Smckusick 			/* it was aoptional so no match is ok */
4808659Smckusick 			return (ptr);
4818659Smckusick 		    } else if (ptr != NIL) {
4828659Smckusick 
4838659Smckusick 			/* not optional and we still matched */
4848659Smckusick 			return (NIL);
4858659Smckusick 		    }
4868659Smckusick 		    if (*s1 == '\\')
4878659Smckusick 			_escaped = _escaped ? FALSE : TRUE;
4888659Smckusick 		    else
4898659Smckusick 			_escaped = FALSE;
4908659Smckusick 		} while (*s1++);
4918659Smckusick 		return (NIL);
4928659Smckusick 
4938659Smckusick 	    /* fail if we are currently _escaped */
4948659Smckusick 	    case 'e':
4958659Smckusick 		if (_escaped)
4968659Smckusick 		    return(NIL);
4978659Smckusick 		cs = MNEXT(cs);
4988659Smckusick 		break;
4998659Smckusick 
5008659Smckusick 	    /* match any number of tabs and spaces */
5018659Smckusick 	    case 'd':
5028659Smckusick 		ptr = s;
5038659Smckusick 		while (*s == ' ' || *s == '\t')
5048659Smckusick 		    s++;
5058659Smckusick 		if (s != ptr || s == _start) {
5068659Smckusick 
5078659Smckusick 		    /* match, be happy */
5088659Smckusick 		    matched = 1;
5098659Smckusick 		    cs = MNEXT(cs);
5108659Smckusick 		} else if (*s == '\n' || *s == '\0') {
5118659Smckusick 
5128659Smckusick 		    /* match, be happy */
5138659Smckusick 		    matched = 1;
5148659Smckusick 		    cs = MNEXT(cs);
5158659Smckusick 		} else if (*cs & ALT) {
5168659Smckusick 
5178659Smckusick 		    /* try the next part */
5188659Smckusick 		    matched = 0;
5198659Smckusick 		    cs = MNEXT(cs);
5208659Smckusick 		} else if (*cs & OPT) {
5218659Smckusick 
5228659Smckusick 		    /* doesn't matter */
5238659Smckusick 		    matched = 1;
5248659Smckusick 		    cs = MNEXT(cs);
5258659Smckusick 		} else
5268659Smckusick 
5278659Smckusick 		    /* no match, error return */
5288659Smckusick 		    return (NIL);
5298659Smckusick 		break;
5308659Smckusick 
5318659Smckusick 	    /* check for end of line */
5328659Smckusick 	    case '$':
5338659Smckusick 		if (*s == '\0' || *s == '\n') {
5348659Smckusick 
5358659Smckusick 		    /* match, be happy */
5368659Smckusick 		    s++;
5378659Smckusick 		    matched = 1;
5388659Smckusick 		    cs = MNEXT(cs);
5398659Smckusick 		} else if (*cs & ALT) {
5408659Smckusick 
5418659Smckusick 		    /* try the next part */
5428659Smckusick 		    matched = 0;
5438659Smckusick 		    cs = MNEXT(cs);
5448659Smckusick 		} else if (*cs & OPT) {
5458659Smckusick 
5468659Smckusick 		    /* doesn't matter */
5478659Smckusick 		    matched = 1;
5488659Smckusick 		    cs = MNEXT(cs);
5498659Smckusick 		} else
5508659Smckusick 
5518659Smckusick 		    /* no match, error return */
5528659Smckusick 		    return (NIL);
5538659Smckusick 		break;
5548659Smckusick 
5558659Smckusick 	    /* check for start of line */
5568659Smckusick 	    case '^':
5578659Smckusick 		if (s == _start) {
5588659Smckusick 
5598659Smckusick 		    /* match, be happy */
5608659Smckusick 		    matched = 1;
5618659Smckusick 		    cs = MNEXT(cs);
5628659Smckusick 		} else if (*cs & ALT) {
5638659Smckusick 
5648659Smckusick 		    /* try the next part */
5658659Smckusick 		    matched = 0;
5668659Smckusick 		    cs = MNEXT(cs);
5678659Smckusick 		} else if (*cs & OPT) {
5688659Smckusick 
5698659Smckusick 		    /* doesn't matter */
5708659Smckusick 		    matched = 1;
5718659Smckusick 		    cs = MNEXT(cs);
5728659Smckusick 		} else
5738659Smckusick 
5748659Smckusick 		    /* no match, error return */
5758659Smckusick 		    return (NIL);
5768659Smckusick 		break;
5778659Smckusick 
5788659Smckusick 	    /* end of a subexpression, return success */
5798659Smckusick 	    case ')':
5808659Smckusick 		return (s);
5818659Smckusick 	    }
5828659Smckusick 	    break;
5838659Smckusick 	}
5848659Smckusick     }
5858659Smckusick     return (s);
5868659Smckusick }
587