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