regexp.c revision 87693
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes *
61590Srgrimes * Redistribution and use in source and binary forms, with or without
71590Srgrimes * modification, are permitted provided that the following conditions
81590Srgrimes * are met:
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice, this list of conditions and the following disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes * 3. All advertising materials mentioning features or use of this software
151590Srgrimes *    must display the following acknowledgement:
161590Srgrimes *	This product includes software developed by the University of
171590Srgrimes *	California, Berkeley and its contributors.
181590Srgrimes * 4. Neither the name of the University nor the names of its contributors
191590Srgrimes *    may be used to endorse or promote products derived from this software
201590Srgrimes *    without specific prior written permission.
211590Srgrimes *
221590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321590Srgrimes * SUCH DAMAGE.
331590Srgrimes */
341590Srgrimes
3587693Smarkm#include <sys/cdefs.h>
3687693Smarkm
3787693Smarkm__FBSDID("$FreeBSD: head/usr.bin/vgrind/regexp.c 87693 2001-12-11 23:10:26Z markm $");
3887693Smarkm
391590Srgrimes#ifndef lint
4087693Smarkmstatic const char copyright[] =
411590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
421590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4387693Smarkm#endif
441590Srgrimes
451590Srgrimes#ifndef lint
4687693Smarkmstatic const char sccsid[] = "@(#)regexp.c	8.1 (Berkeley) 6/6/93";
4787693Smarkm#endif
481590Srgrimes
491590Srgrimes#include <ctype.h>
501590Srgrimes#include <stdlib.h>
511590Srgrimes#include <string.h>
5287693Smarkm
531590Srgrimes#include "extern.h"
541590Srgrimes
551590Srgrimes#define FALSE	0
561590Srgrimes#define TRUE	!(FALSE)
571590Srgrimes#define NIL	0
581590Srgrimes
591590Srgrimesstatic void	expconv __P((void));
601590Srgrimes
611590Srgrimesboolean	 _escaped;	/* true if we are currently _escaped */
6236053Sjbchar	*s_start;	/* start of string */
631590Srgrimesboolean	 l_onecase;	/* true if upper and lower equivalent */
641590Srgrimes
651590Srgrimes#define makelower(c) (isupper((c)) ? tolower((c)) : (c))
661590Srgrimes
671590Srgrimes/*  STRNCMP -	like strncmp except that we convert the
681590Srgrimes *	 	first string to lower case before comparing
691590Srgrimes *		if l_onecase is set.
701590Srgrimes */
711590Srgrimes
721590Srgrimesint
731590SrgrimesSTRNCMP(s1, s2, len)
741590Srgrimes	register char *s1,*s2;
751590Srgrimes	register int len;
761590Srgrimes{
771590Srgrimes	if (l_onecase) {
781590Srgrimes	    do
791590Srgrimes		if (*s2 - makelower(*s1))
801590Srgrimes			return (*s2 - makelower(*s1));
811590Srgrimes		else {
821590Srgrimes			s2++;
831590Srgrimes			s1++;
841590Srgrimes		}
851590Srgrimes	    while (--len);
861590Srgrimes	} else {
871590Srgrimes	    do
881590Srgrimes		if (*s2 - *s1)
891590Srgrimes			return (*s2 - *s1);
901590Srgrimes		else {
911590Srgrimes			s2++;
921590Srgrimes			s1++;
931590Srgrimes		}
941590Srgrimes	    while (--len);
951590Srgrimes	}
961590Srgrimes	return(0);
971590Srgrimes}
981590Srgrimes
991590Srgrimes/*	The following routine converts an irregular expression to
1001590Srgrimes *	internal format.
1011590Srgrimes *
1021590Srgrimes *	Either meta symbols (\a \d or \p) or character strings or
1031590Srgrimes *	operations ( alternation or perenthesizing ) can be
1041590Srgrimes *	specified.  Each starts with a descriptor byte.  The descriptor
1051590Srgrimes *	byte has STR set for strings, META set for meta symbols
1061590Srgrimes *	and OPER set for operations.
1071590Srgrimes *	The descriptor byte can also have the OPT bit set if the object
1081590Srgrimes *	defined is optional.  Also ALT can be set to indicate an alternation.
1091590Srgrimes *
1101590Srgrimes *	For metasymbols the byte following the descriptor byte identities
1111590Srgrimes *	the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '(').  For
1121590Srgrimes *	strings the byte after the descriptor is a character count for
1131590Srgrimes *	the string:
1141590Srgrimes *
1151590Srgrimes *		meta symbols := descriptor
1161590Srgrimes *				symbol
1171590Srgrimes *
1181590Srgrimes *		strings :=	descriptor
1191590Srgrimes *				character count
1201590Srgrimes *				the string
1211590Srgrimes *
1221590Srgrimes *		operatins :=	descriptor
1231590Srgrimes *				symbol
1241590Srgrimes *				character count
1251590Srgrimes */
1261590Srgrimes
1271590Srgrimes/*
1281590Srgrimes *  handy macros for accessing parts of match blocks
1291590Srgrimes */
1301590Srgrimes#define MSYM(A) (*(A+1))	/* symbol in a meta symbol block */
1311590Srgrimes#define MNEXT(A) (A+2)		/* character following a metasymbol block */
1321590Srgrimes
1331590Srgrimes#define OSYM(A) (*(A+1))	/* symbol in an operation block */
1341590Srgrimes#define OCNT(A) (*(A+2))	/* character count */
1351590Srgrimes#define ONEXT(A) (A+3)		/* next character after the operation */
1361590Srgrimes#define OPTR(A) (A+*(A+2))	/* place pointed to by the operator */
1371590Srgrimes
1381590Srgrimes#define SCNT(A) (*(A+1))	/* byte count of a string */
1391590Srgrimes#define SSTR(A) (A+2)		/* address of the string */
1401590Srgrimes#define SNEXT(A) (A+2+*(A+1))	/* character following the string */
1411590Srgrimes
1421590Srgrimes/*
1438874Srgrimes *  bit flags in the descriptor
1441590Srgrimes */
1451590Srgrimes#define OPT 1
1461590Srgrimes#define STR 2
1471590Srgrimes#define META 4
1481590Srgrimes#define ALT 8
1491590Srgrimes#define OPER 16
1501590Srgrimes
1511590Srgrimesstatic char *ccre;	/* pointer to current position in converted exp*/
1521590Srgrimesstatic char *ure;	/* pointer current position in unconverted exp */
1531590Srgrimes
1541590Srgrimeschar *
1551590Srgrimesconvexp(re)
1561590Srgrimes    char *re;		/* unconverted irregular expression */
1571590Srgrimes{
1581590Srgrimes    register char *cre;		/* pointer to converted regular expression */
1591590Srgrimes
1601590Srgrimes    /* allocate room for the converted expression */
1611590Srgrimes    if (re == NIL)
1621590Srgrimes	return (NIL);
1631590Srgrimes    if (*re == '\0')
1641590Srgrimes	return (NIL);
1651590Srgrimes    cre = malloc (4 * strlen(re) + 3);
1661590Srgrimes    ccre = cre;
1671590Srgrimes    ure = re;
1681590Srgrimes
1691590Srgrimes    /* start the conversion with a \a */
1701590Srgrimes    *cre = META | OPT;
1711590Srgrimes    MSYM(cre) = 'a';
1721590Srgrimes    ccre = MNEXT(cre);
1731590Srgrimes
1741590Srgrimes    /* start the conversion (its recursive) */
1751590Srgrimes    expconv ();
1761590Srgrimes    *ccre = 0;
1771590Srgrimes    return (cre);
1781590Srgrimes}
1791590Srgrimes
1801590Srgrimesstatic void
1811590Srgrimesexpconv()
1821590Srgrimes{
1831590Srgrimes    register char *cs;		/* pointer to current symbol in converted exp */
1841590Srgrimes    register char c;		/* character being processed */
1851590Srgrimes    register char *acs;		/* pinter to last alternate */
1861590Srgrimes    register int temp;
1871590Srgrimes
1881590Srgrimes    /* let the conversion begin */
1891590Srgrimes    acs = NIL;
1901590Srgrimes    cs = NIL;
1911590Srgrimes    while (*ure != NIL) {
1921590Srgrimes	switch (c = *ure++) {
1931590Srgrimes
1941590Srgrimes	case '\\':
1951590Srgrimes	    switch (c = *ure++) {
1961590Srgrimes
1971590Srgrimes	    /* escaped characters are just characters */
1981590Srgrimes	    default:
1991590Srgrimes		if (cs == NIL || (*cs & STR) == 0) {
2001590Srgrimes		    cs = ccre;
2011590Srgrimes		    *cs = STR;
2021590Srgrimes		    SCNT(cs) = 1;
2031590Srgrimes		    ccre += 2;
2048874Srgrimes		} else
2051590Srgrimes		    SCNT(cs)++;
2061590Srgrimes		*ccre++ = c;
2071590Srgrimes		break;
2081590Srgrimes
2091590Srgrimes	    /* normal(?) metacharacters */
2101590Srgrimes	    case 'a':
2111590Srgrimes	    case 'd':
2121590Srgrimes	    case 'e':
2131590Srgrimes	    case 'p':
2141590Srgrimes		if (acs != NIL && acs != cs) {
2151590Srgrimes		    do {
2161590Srgrimes			temp = OCNT(acs);
2178874Srgrimes			OCNT(acs) = ccre - acs;
2181590Srgrimes			acs -= temp;
2191590Srgrimes		    } while (temp != 0);
2201590Srgrimes		    acs = NIL;
2211590Srgrimes		}
2221590Srgrimes		cs = ccre;
2231590Srgrimes		*cs = META;
2241590Srgrimes		MSYM(cs) = c;
2251590Srgrimes		ccre = MNEXT(cs);
2261590Srgrimes		break;
2271590Srgrimes	    }
2281590Srgrimes	    break;
2298874Srgrimes
2301590Srgrimes	/* just put the symbol in */
2311590Srgrimes	case '^':
2321590Srgrimes	case '$':
2331590Srgrimes	    if (acs != NIL && acs != cs) {
2341590Srgrimes		do {
2351590Srgrimes		    temp = OCNT(acs);
2361590Srgrimes		    OCNT(acs) = ccre - acs;
2371590Srgrimes		    acs -= temp;
2381590Srgrimes		} while (temp != 0);
2391590Srgrimes		acs = NIL;
2401590Srgrimes	    }
2411590Srgrimes	    cs = ccre;
2421590Srgrimes	    *cs = META;
2431590Srgrimes	    MSYM(cs) = c;
2441590Srgrimes	    ccre = MNEXT(cs);
2451590Srgrimes	    break;
2461590Srgrimes
2471590Srgrimes	/* mark the last match sequence as optional */
2481590Srgrimes	case '?':
2491590Srgrimes	    if (cs)
2501590Srgrimes	    	*cs = *cs | OPT;
2511590Srgrimes	    break;
2521590Srgrimes
2531590Srgrimes	/* recurse and define a subexpression */
2541590Srgrimes	case '(':
2551590Srgrimes	    if (acs != NIL && acs != cs) {
2561590Srgrimes		do {
2571590Srgrimes		    temp = OCNT(acs);
2581590Srgrimes		    OCNT(acs) = ccre - acs;
2591590Srgrimes		    acs -= temp;
2601590Srgrimes		} while (temp != 0);
2611590Srgrimes		acs = NIL;
2621590Srgrimes	    }
2631590Srgrimes	    cs = ccre;
2641590Srgrimes	    *cs = OPER;
2651590Srgrimes	    OSYM(cs) = '(';
2661590Srgrimes	    ccre = ONEXT(cs);
2671590Srgrimes	    expconv ();
2681590Srgrimes	    OCNT(cs) = ccre - cs;		/* offset to next symbol */
2691590Srgrimes	    break;
2701590Srgrimes
27119012Sjoerg	/* return from a recursion */
2721590Srgrimes	case ')':
2731590Srgrimes	    if (acs != NIL) {
2741590Srgrimes		do {
2751590Srgrimes		    temp = OCNT(acs);
2761590Srgrimes		    OCNT(acs) = ccre - acs;
2771590Srgrimes		    acs -= temp;
2781590Srgrimes		} while (temp != 0);
2791590Srgrimes		acs = NIL;
2801590Srgrimes	    }
2811590Srgrimes	    cs = ccre;
2821590Srgrimes	    *cs = META;
2831590Srgrimes	    MSYM(cs) = c;
2841590Srgrimes	    ccre = MNEXT(cs);
2851590Srgrimes	    return;
2861590Srgrimes
2871590Srgrimes	/* mark the last match sequence as having an alternate */
2881590Srgrimes	/* the third byte will contain an offset to jump over the */
2891590Srgrimes	/* alternate match in case the first did not fail */
2901590Srgrimes	case '|':
2911590Srgrimes	    if (acs != NIL && acs != cs)
2921590Srgrimes		OCNT(ccre) = ccre - acs;	/* make a back pointer */
2931590Srgrimes	    else
2941590Srgrimes		OCNT(ccre) = 0;
2951590Srgrimes	    *cs |= ALT;
2961590Srgrimes	    cs = ccre;
2971590Srgrimes	    *cs = OPER;
2981590Srgrimes	    OSYM(cs) = '|';
2991590Srgrimes	    ccre = ONEXT(cs);
3001590Srgrimes	    acs = cs;	/* remember that the pointer is to be filles */
3011590Srgrimes	    break;
3021590Srgrimes
3031590Srgrimes	/* if its not a metasymbol just build a scharacter string */
3041590Srgrimes	default:
3051590Srgrimes	    if (cs == NIL || (*cs & STR) == 0) {
3061590Srgrimes		cs = ccre;
3071590Srgrimes		*cs = STR;
3081590Srgrimes		SCNT(cs) = 1;
3091590Srgrimes		ccre = SSTR(cs);
3101590Srgrimes	    } else
3111590Srgrimes		SCNT(cs)++;
3121590Srgrimes	    *ccre++ = c;
3131590Srgrimes	    break;
3141590Srgrimes	}
3151590Srgrimes    }
3161590Srgrimes    if (acs != NIL) {
3171590Srgrimes	do {
3181590Srgrimes	    temp = OCNT(acs);
3191590Srgrimes	    OCNT(acs) = ccre - acs;
3201590Srgrimes	    acs -= temp;
3211590Srgrimes	} while (temp != 0);
3221590Srgrimes	acs = NIL;
3231590Srgrimes    }
3241590Srgrimes    return;
3251590Srgrimes}
3261590Srgrimes/* end of convertre */
3271590Srgrimes
3281590Srgrimes
3291590Srgrimes/*
3301590Srgrimes *	The following routine recognises an irregular expresion
3311590Srgrimes *	with the following special characters:
3321590Srgrimes *
3331590Srgrimes *		\?	-	means last match was optional
3341590Srgrimes *		\a	-	matches any number of characters
3351590Srgrimes *		\d	-	matches any number of spaces and tabs
3361590Srgrimes *		\p	-	matches any number of alphanumeric
3371590Srgrimes *				characters. The
3381590Srgrimes *				characters matched will be copied into
3391590Srgrimes *				the area pointed to by 'name'.
3401590Srgrimes *		\|	-	alternation
3411590Srgrimes *		\( \)	-	grouping used mostly for alternation and
3421590Srgrimes *				optionality
3431590Srgrimes *
3441590Srgrimes *	The irregular expression must be translated to internal form
3451590Srgrimes *	prior to calling this routine
3461590Srgrimes *
3478874Srgrimes *	The value returned is the pointer to the first non \a
3481590Srgrimes *	character matched.
3491590Srgrimes */
3501590Srgrimes
3511590Srgrimeschar *
3521590Srgrimesexpmatch (s, re, mstring)
3531590Srgrimes    register char *s;		/* string to check for a match in */
3541590Srgrimes    register char *re;		/* a converted irregular expression */
3551590Srgrimes    register char *mstring;	/* where to put whatever matches a \p */
3561590Srgrimes{
3571590Srgrimes    register char *cs;		/* the current symbol */
3581590Srgrimes    register char *ptr,*s1;	/* temporary pointer */
3591590Srgrimes    boolean matched;		/* a temporary boolean */
3601590Srgrimes
3611590Srgrimes    /* initial conditions */
3621590Srgrimes    if (re == NIL)
3631590Srgrimes	return (NIL);
3641590Srgrimes    cs = re;
3651590Srgrimes    matched = FALSE;
3661590Srgrimes
3671590Srgrimes    /* loop till expression string is exhausted (or at least pretty tired) */
3681590Srgrimes    while (*cs) {
3691590Srgrimes	switch (*cs & (OPER | STR | META)) {
3701590Srgrimes
3711590Srgrimes	/* try to match a string */
3721590Srgrimes	case STR:
3731590Srgrimes	    matched = !STRNCMP (s, SSTR(cs), SCNT(cs));
3741590Srgrimes	    if (matched) {
3751590Srgrimes
3761590Srgrimes		/* hoorah it matches */
3771590Srgrimes		s += SCNT(cs);
3781590Srgrimes		cs = SNEXT(cs);
3791590Srgrimes	    } else if (*cs & ALT) {
3801590Srgrimes
3811590Srgrimes		/* alternation, skip to next expression */
3821590Srgrimes		cs = SNEXT(cs);
3831590Srgrimes	    } else if (*cs & OPT) {
3841590Srgrimes
3851590Srgrimes		/* the match is optional */
3861590Srgrimes		cs = SNEXT(cs);
3871590Srgrimes		matched = 1;		/* indicate a successful match */
3881590Srgrimes	    } else {
3891590Srgrimes
3901590Srgrimes		/* no match, error return */
3911590Srgrimes		return (NIL);
3921590Srgrimes	    }
3931590Srgrimes	    break;
3941590Srgrimes
3951590Srgrimes	/* an operator, do something fancy */
3961590Srgrimes	case OPER:
3971590Srgrimes	    switch (OSYM(cs)) {
3981590Srgrimes
3991590Srgrimes	    /* this is an alternation */
4001590Srgrimes	    case '|':
4011590Srgrimes		if (matched)
4021590Srgrimes
4031590Srgrimes		    /* last thing in the alternation was a match, skip ahead */
4041590Srgrimes		    cs = OPTR(cs);
4051590Srgrimes		else
4061590Srgrimes
4071590Srgrimes		    /* no match, keep trying */
4081590Srgrimes		    cs = ONEXT(cs);
4091590Srgrimes		break;
4101590Srgrimes
4111590Srgrimes	    /* this is a grouping, recurse */
4121590Srgrimes	    case '(':
4131590Srgrimes		ptr = expmatch (s, ONEXT(cs), mstring);
4141590Srgrimes		if (ptr != NIL) {
4151590Srgrimes
4161590Srgrimes		    /* the subexpression matched */
4171590Srgrimes		    matched = 1;
4181590Srgrimes		    s = ptr;
4191590Srgrimes		} else if (*cs & ALT) {
4201590Srgrimes
4211590Srgrimes		    /* alternation, skip to next expression */
4221590Srgrimes		    matched = 0;
4231590Srgrimes		} else if (*cs & OPT) {
4241590Srgrimes
4251590Srgrimes		    /* the match is optional */
4261590Srgrimes		    matched = 1;	/* indicate a successful match */
4271590Srgrimes		} else {
4281590Srgrimes
4291590Srgrimes		    /* no match, error return */
4301590Srgrimes		    return (NIL);
4311590Srgrimes		}
4321590Srgrimes		cs = OPTR(cs);
4331590Srgrimes		break;
4341590Srgrimes	    }
4351590Srgrimes	    break;
4361590Srgrimes
4371590Srgrimes	/* try to match a metasymbol */
4381590Srgrimes	case META:
4391590Srgrimes	    switch (MSYM(cs)) {
4401590Srgrimes
4411590Srgrimes	    /* try to match anything and remember what was matched */
4421590Srgrimes	    case 'p':
4431590Srgrimes		/*
4441590Srgrimes		 *  This is really the same as trying the match the
4451590Srgrimes		 *  remaining parts of the expression to any subset
4461590Srgrimes		 *  of the string.
4471590Srgrimes		 */
4481590Srgrimes		s1 = s;
4491590Srgrimes		do {
4501590Srgrimes		    ptr = expmatch (s1, MNEXT(cs), mstring);
4511590Srgrimes		    if (ptr != NIL && s1 != s) {
4521590Srgrimes
4531590Srgrimes			/* we have a match, remember the match */
4541590Srgrimes			strncpy (mstring, s, s1 - s);
4551590Srgrimes			mstring[s1 - s] = '\0';
4561590Srgrimes			return (ptr);
4571590Srgrimes		    } else if (ptr != NIL && (*cs & OPT)) {
4581590Srgrimes
4591590Srgrimes			/* it was aoptional so no match is ok */
4601590Srgrimes			return (ptr);
4611590Srgrimes		    } else if (ptr != NIL) {
4621590Srgrimes
4631590Srgrimes			/* not optional and we still matched */
4641590Srgrimes			return (NIL);
4651590Srgrimes		    }
46619019Sjoerg		    if (!(isalnum(*s1) || *s1 == '_' ||
46719019Sjoerg			  /* C++ destructor */
46819019Sjoerg			  *s1 == '~' ||
46919019Sjoerg			  /* C++ scope operator */
47019019Sjoerg			  (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' &&
47119019Sjoerg			   (s1++, TRUE))))
4721590Srgrimes			return (NIL);
4731590Srgrimes		    if (*s1 == '\\')
4741590Srgrimes			_escaped = _escaped ? FALSE : TRUE;
4751590Srgrimes		    else
4761590Srgrimes			_escaped = FALSE;
4771590Srgrimes		} while (*s1++);
4781590Srgrimes		return (NIL);
4791590Srgrimes
4801590Srgrimes	    /* try to match anything */
4811590Srgrimes	    case 'a':
4821590Srgrimes		/*
4831590Srgrimes		 *  This is really the same as trying the match the
4841590Srgrimes		 *  remaining parts of the expression to any subset
4851590Srgrimes		 *  of the string.
4861590Srgrimes		 */
4871590Srgrimes		s1 = s;
4881590Srgrimes		do {
4891590Srgrimes		    ptr = expmatch (s1, MNEXT(cs), mstring);
4901590Srgrimes		    if (ptr != NIL && s1 != s) {
4911590Srgrimes
4921590Srgrimes			/* we have a match */
4931590Srgrimes			return (ptr);
4941590Srgrimes		    } else if (ptr != NIL && (*cs & OPT)) {
4951590Srgrimes
4961590Srgrimes			/* it was aoptional so no match is ok */
4971590Srgrimes			return (ptr);
4981590Srgrimes		    } else if (ptr != NIL) {
4991590Srgrimes
5001590Srgrimes			/* not optional and we still matched */
5011590Srgrimes			return (NIL);
5021590Srgrimes		    }
5031590Srgrimes		    if (*s1 == '\\')
5041590Srgrimes			_escaped = _escaped ? FALSE : TRUE;
5051590Srgrimes		    else
5061590Srgrimes			_escaped = FALSE;
5071590Srgrimes		} while (*s1++);
5081590Srgrimes		return (NIL);
5091590Srgrimes
5101590Srgrimes	    /* fail if we are currently _escaped */
5111590Srgrimes	    case 'e':
5121590Srgrimes		if (_escaped)
5131590Srgrimes		    return(NIL);
5148874Srgrimes		cs = MNEXT(cs);
5151590Srgrimes		break;
5161590Srgrimes
5171590Srgrimes	    /* match any number of tabs and spaces */
5181590Srgrimes	    case 'd':
5191590Srgrimes		ptr = s;
5201590Srgrimes		while (*s == ' ' || *s == '\t')
5211590Srgrimes		    s++;
52236053Sjb		if (s != ptr || s == s_start) {
5231590Srgrimes
5241590Srgrimes		    /* match, be happy */
5251590Srgrimes		    matched = 1;
5268874Srgrimes		    cs = MNEXT(cs);
5271590Srgrimes		} else if (*s == '\n' || *s == '\0') {
5281590Srgrimes
5291590Srgrimes		    /* match, be happy */
5301590Srgrimes		    matched = 1;
5318874Srgrimes		    cs = MNEXT(cs);
5321590Srgrimes		} else if (*cs & ALT) {
5331590Srgrimes
5341590Srgrimes		    /* try the next part */
5351590Srgrimes		    matched = 0;
5361590Srgrimes		    cs = MNEXT(cs);
5371590Srgrimes		} else if (*cs & OPT) {
5381590Srgrimes
5391590Srgrimes		    /* doesn't matter */
5401590Srgrimes		    matched = 1;
5411590Srgrimes		    cs = MNEXT(cs);
5421590Srgrimes		} else
5431590Srgrimes
5441590Srgrimes		    /* no match, error return */
5451590Srgrimes		    return (NIL);
5461590Srgrimes		break;
5471590Srgrimes
5481590Srgrimes	    /* check for end of line */
5491590Srgrimes	    case '$':
5501590Srgrimes		if (*s == '\0' || *s == '\n') {
5511590Srgrimes
5521590Srgrimes		    /* match, be happy */
5531590Srgrimes		    s++;
5541590Srgrimes		    matched = 1;
5551590Srgrimes		    cs = MNEXT(cs);
5561590Srgrimes		} else if (*cs & ALT) {
5571590Srgrimes
5581590Srgrimes		    /* try the next part */
5591590Srgrimes		    matched = 0;
5601590Srgrimes		    cs = MNEXT(cs);
5611590Srgrimes		} else if (*cs & OPT) {
5621590Srgrimes
5631590Srgrimes		    /* doesn't matter */
5641590Srgrimes		    matched = 1;
5651590Srgrimes		    cs = MNEXT(cs);
5661590Srgrimes		} else
5671590Srgrimes
5681590Srgrimes		    /* no match, error return */
5691590Srgrimes		    return (NIL);
5701590Srgrimes		break;
5711590Srgrimes
5721590Srgrimes	    /* check for start of line */
5731590Srgrimes	    case '^':
57436053Sjb		if (s == s_start) {
5751590Srgrimes
5761590Srgrimes		    /* match, be happy */
5771590Srgrimes		    matched = 1;
5781590Srgrimes		    cs = MNEXT(cs);
5791590Srgrimes		} else if (*cs & ALT) {
5801590Srgrimes
5811590Srgrimes		    /* try the next part */
5821590Srgrimes		    matched = 0;
5831590Srgrimes		    cs = MNEXT(cs);
5841590Srgrimes		} else if (*cs & OPT) {
5851590Srgrimes
5861590Srgrimes		    /* doesn't matter */
5871590Srgrimes		    matched = 1;
5881590Srgrimes		    cs = MNEXT(cs);
5891590Srgrimes		} else
5901590Srgrimes
5911590Srgrimes		    /* no match, error return */
5921590Srgrimes		    return (NIL);
5931590Srgrimes		break;
5941590Srgrimes
5951590Srgrimes	    /* end of a subexpression, return success */
5961590Srgrimes	    case ')':
5971590Srgrimes		return (s);
5981590Srgrimes	    }
5991590Srgrimes	    break;
6001590Srgrimes	}
6011590Srgrimes    }
6021590Srgrimes    return (s);
6031590Srgrimes}
604