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