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