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