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