122063Sdist /* 236167Sbostic * Copyright (c) 1980 The Regents of the University of California. 336167Sbostic * All rights reserved. 436167Sbostic * 5*56144Selan * Redistribution and use in source and binary forms, with or without 6*56144Selan * modification, are permitted provided that the following conditions 7*56144Selan * are met: 8*56144Selan * 1. Redistributions of source code must retain the above copyright 9*56144Selan * notice, this list of conditions and the following disclaimer. 10*56144Selan * 2. Redistributions in binary form must reproduce the above copyright 11*56144Selan * notice, this list of conditions and the following disclaimer in the 12*56144Selan * documentation and/or other materials provided with the distribution. 13*56144Selan * 3. All advertising materials mentioning features or use of this software 14*56144Selan * must display the following acknowledgement: 15*56144Selan * This product includes software developed by the University of 16*56144Selan * California, Berkeley and its contributors. 17*56144Selan * 4. Neither the name of the University nor the names of its contributors 18*56144Selan * may be used to endorse or promote products derived from this software 19*56144Selan * without specific prior written permission. 20*56144Selan * 21*56144Selan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22*56144Selan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*56144Selan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*56144Selan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25*56144Selan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*56144Selan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*56144Selan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*56144Selan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*56144Selan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*56144Selan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*56144Selan * SUCH DAMAGE. 3222063Sdist */ 338659Smckusick 3422063Sdist #ifndef lint 35*56144Selan static char sccsid[] = "@(#)regexp.c 5.4 (Berkeley) 8/3/92"; 3636167Sbostic #endif /* not lint */ 3722063Sdist 388659Smckusick #include <ctype.h> 39*56144Selan #include <stdlib.h> 40*56144Selan #include <string.h> 41*56144Selan #include "extern.h" 428659Smckusick 438659Smckusick #define FALSE 0 44*56144Selan #define TRUE !(FALSE) 458659Smckusick #define NIL 0 468659Smckusick 47*56144Selan static void expconv __P((void)); 488659Smckusick 49*56144Selan boolean _escaped; /* true if we are currently _escaped */ 50*56144Selan char *_start; /* start of string */ 51*56144Selan boolean l_onecase; /* true if upper and lower equivalent */ 52*56144Selan 538659Smckusick #define makelower(c) (isupper((c)) ? tolower((c)) : (c)) 548659Smckusick 558659Smckusick /* STRNCMP - like strncmp except that we convert the 568659Smckusick * first string to lower case before comparing 578659Smckusick * if l_onecase is set. 588659Smckusick */ 598659Smckusick 60*56144Selan int 618659Smckusick STRNCMP(s1, s2, len) 628659Smckusick register char *s1,*s2; 638659Smckusick register int len; 648659Smckusick { 658659Smckusick if (l_onecase) { 668659Smckusick do 678659Smckusick if (*s2 - makelower(*s1)) 688659Smckusick return (*s2 - makelower(*s1)); 698659Smckusick else { 708659Smckusick s2++; 718659Smckusick s1++; 728659Smckusick } 738659Smckusick while (--len); 748659Smckusick } else { 758659Smckusick do 768659Smckusick if (*s2 - *s1) 778659Smckusick return (*s2 - *s1); 788659Smckusick else { 798659Smckusick s2++; 808659Smckusick s1++; 818659Smckusick } 828659Smckusick while (--len); 838659Smckusick } 848659Smckusick return(0); 858659Smckusick } 868659Smckusick 878659Smckusick /* The following routine converts an irregular expression to 888659Smckusick * internal format. 898659Smckusick * 908659Smckusick * Either meta symbols (\a \d or \p) or character strings or 918659Smckusick * operations ( alternation or perenthesizing ) can be 928659Smckusick * specified. Each starts with a descriptor byte. The descriptor 938659Smckusick * byte has STR set for strings, META set for meta symbols 948659Smckusick * and OPER set for operations. 958659Smckusick * The descriptor byte can also have the OPT bit set if the object 968659Smckusick * defined is optional. Also ALT can be set to indicate an alternation. 978659Smckusick * 988659Smckusick * For metasymbols the byte following the descriptor byte identities 998659Smckusick * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For 1008659Smckusick * strings the byte after the descriptor is a character count for 1018659Smckusick * the string: 1028659Smckusick * 1038659Smckusick * meta symbols := descriptor 1048659Smckusick * symbol 1058659Smckusick * 1068659Smckusick * strings := descriptor 1078659Smckusick * character count 1088659Smckusick * the string 1098659Smckusick * 1108659Smckusick * operatins := descriptor 1118659Smckusick * symbol 1128659Smckusick * character count 1138659Smckusick */ 1148659Smckusick 1158659Smckusick /* 1168659Smckusick * handy macros for accessing parts of match blocks 1178659Smckusick */ 1188659Smckusick #define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ 1198659Smckusick #define MNEXT(A) (A+2) /* character following a metasymbol block */ 1208659Smckusick 1218659Smckusick #define OSYM(A) (*(A+1)) /* symbol in an operation block */ 1228659Smckusick #define OCNT(A) (*(A+2)) /* character count */ 1238659Smckusick #define ONEXT(A) (A+3) /* next character after the operation */ 1248659Smckusick #define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ 1258659Smckusick 1268659Smckusick #define SCNT(A) (*(A+1)) /* byte count of a string */ 1278659Smckusick #define SSTR(A) (A+2) /* address of the string */ 1288659Smckusick #define SNEXT(A) (A+2+*(A+1)) /* character following the string */ 1298659Smckusick 1308659Smckusick /* 1318659Smckusick * bit flags in the descriptor 1328659Smckusick */ 1338659Smckusick #define OPT 1 1348659Smckusick #define STR 2 1358659Smckusick #define META 4 1368659Smckusick #define ALT 8 1378659Smckusick #define OPER 16 1388659Smckusick 139*56144Selan static char *ccre; /* pointer to current position in converted exp*/ 140*56144Selan static char *ure; /* pointer current position in unconverted exp */ 1418659Smckusick 1428659Smckusick char * 1438659Smckusick convexp(re) 1448659Smckusick char *re; /* unconverted irregular expression */ 1458659Smckusick { 1468659Smckusick register char *cre; /* pointer to converted regular expression */ 1478659Smckusick 1488659Smckusick /* allocate room for the converted expression */ 1498659Smckusick if (re == NIL) 1508659Smckusick return (NIL); 1518659Smckusick if (*re == '\0') 1528659Smckusick return (NIL); 1538659Smckusick cre = malloc (4 * strlen(re) + 3); 1548659Smckusick ccre = cre; 1558659Smckusick ure = re; 1568659Smckusick 1578659Smckusick /* start the conversion with a \a */ 1588659Smckusick *cre = META | OPT; 1598659Smckusick MSYM(cre) = 'a'; 1608659Smckusick ccre = MNEXT(cre); 1618659Smckusick 1628659Smckusick /* start the conversion (its recursive) */ 1638659Smckusick expconv (); 1648659Smckusick *ccre = 0; 1658659Smckusick return (cre); 1668659Smckusick } 1678659Smckusick 168*56144Selan static void 1698659Smckusick expconv() 1708659Smckusick { 1718659Smckusick register char *cs; /* pointer to current symbol in converted exp */ 1728659Smckusick register char c; /* character being processed */ 1738659Smckusick register char *acs; /* pinter to last alternate */ 1748659Smckusick register int temp; 1758659Smckusick 1768659Smckusick /* let the conversion begin */ 1778659Smckusick acs = NIL; 17817500Sralph cs = NIL; 1798659Smckusick while (*ure != NIL) { 1808659Smckusick switch (c = *ure++) { 1818659Smckusick 1828659Smckusick case '\\': 1838659Smckusick switch (c = *ure++) { 1848659Smckusick 1858659Smckusick /* escaped characters are just characters */ 1868659Smckusick default: 18717500Sralph if (cs == NIL || (*cs & STR) == 0) { 1888659Smckusick cs = ccre; 1898659Smckusick *cs = STR; 1908659Smckusick SCNT(cs) = 1; 1918659Smckusick ccre += 2; 1928659Smckusick } else 1938659Smckusick SCNT(cs)++; 1948659Smckusick *ccre++ = c; 1958659Smckusick break; 1968659Smckusick 1978659Smckusick /* normal(?) metacharacters */ 1988659Smckusick case 'a': 1998659Smckusick case 'd': 2008659Smckusick case 'e': 2018659Smckusick case 'p': 2028659Smckusick if (acs != NIL && acs != cs) { 2038659Smckusick do { 2048659Smckusick temp = OCNT(acs); 2058659Smckusick OCNT(acs) = ccre - acs; 2068659Smckusick acs -= temp; 2078659Smckusick } while (temp != 0); 2088659Smckusick acs = NIL; 2098659Smckusick } 2108659Smckusick cs = ccre; 2118659Smckusick *cs = META; 2128659Smckusick MSYM(cs) = c; 2138659Smckusick ccre = MNEXT(cs); 2148659Smckusick break; 2158659Smckusick } 2168659Smckusick break; 2178659Smckusick 2188659Smckusick /* just put the symbol in */ 2198659Smckusick case '^': 2208659Smckusick case '$': 2218659Smckusick if (acs != NIL && acs != cs) { 2228659Smckusick do { 2238659Smckusick temp = OCNT(acs); 2248659Smckusick OCNT(acs) = ccre - acs; 2258659Smckusick acs -= temp; 2268659Smckusick } while (temp != 0); 2278659Smckusick acs = NIL; 2288659Smckusick } 2298659Smckusick cs = ccre; 2308659Smckusick *cs = META; 2318659Smckusick MSYM(cs) = c; 2328659Smckusick ccre = MNEXT(cs); 2338659Smckusick break; 2348659Smckusick 2358659Smckusick /* mark the last match sequence as optional */ 2368659Smckusick case '?': 23717500Sralph if (cs) 23817500Sralph *cs = *cs | OPT; 2398659Smckusick break; 2408659Smckusick 2418659Smckusick /* recurse and define a subexpression */ 2428659Smckusick case '(': 2438659Smckusick if (acs != NIL && acs != cs) { 2448659Smckusick do { 2458659Smckusick temp = OCNT(acs); 2468659Smckusick OCNT(acs) = ccre - acs; 2478659Smckusick acs -= temp; 2488659Smckusick } while (temp != 0); 2498659Smckusick acs = NIL; 2508659Smckusick } 2518659Smckusick cs = ccre; 2528659Smckusick *cs = OPER; 2538659Smckusick OSYM(cs) = '('; 2548659Smckusick ccre = ONEXT(cs); 2558659Smckusick expconv (); 2568659Smckusick OCNT(cs) = ccre - cs; /* offset to next symbol */ 2578659Smckusick break; 2588659Smckusick 259*56144Selan /* reurn from a recursion */ 2608659Smckusick case ')': 2618659Smckusick if (acs != NIL) { 2628659Smckusick do { 2638659Smckusick temp = OCNT(acs); 2648659Smckusick OCNT(acs) = ccre - acs; 2658659Smckusick acs -= temp; 2668659Smckusick } while (temp != 0); 2678659Smckusick acs = NIL; 2688659Smckusick } 2698659Smckusick cs = ccre; 2708659Smckusick *cs = META; 2718659Smckusick MSYM(cs) = c; 2728659Smckusick ccre = MNEXT(cs); 2738659Smckusick return; 2748659Smckusick 2758659Smckusick /* mark the last match sequence as having an alternate */ 2768659Smckusick /* the third byte will contain an offset to jump over the */ 2778659Smckusick /* alternate match in case the first did not fail */ 2788659Smckusick case '|': 2798659Smckusick if (acs != NIL && acs != cs) 2808659Smckusick OCNT(ccre) = ccre - acs; /* make a back pointer */ 2818659Smckusick else 2828659Smckusick OCNT(ccre) = 0; 2838659Smckusick *cs |= ALT; 2848659Smckusick cs = ccre; 2858659Smckusick *cs = OPER; 2868659Smckusick OSYM(cs) = '|'; 2878659Smckusick ccre = ONEXT(cs); 2888659Smckusick acs = cs; /* remember that the pointer is to be filles */ 2898659Smckusick break; 2908659Smckusick 2918659Smckusick /* if its not a metasymbol just build a scharacter string */ 2928659Smckusick default: 29317500Sralph if (cs == NIL || (*cs & STR) == 0) { 2948659Smckusick cs = ccre; 2958659Smckusick *cs = STR; 2968659Smckusick SCNT(cs) = 1; 2978659Smckusick ccre = SSTR(cs); 2988659Smckusick } else 2998659Smckusick SCNT(cs)++; 3008659Smckusick *ccre++ = c; 3018659Smckusick break; 3028659Smckusick } 3038659Smckusick } 3048659Smckusick if (acs != NIL) { 3058659Smckusick do { 3068659Smckusick temp = OCNT(acs); 3078659Smckusick OCNT(acs) = ccre - acs; 3088659Smckusick acs -= temp; 3098659Smckusick } while (temp != 0); 3108659Smckusick acs = NIL; 3118659Smckusick } 3128659Smckusick return; 3138659Smckusick } 3148659Smckusick /* end of convertre */ 3158659Smckusick 3168659Smckusick 3178659Smckusick /* 3188659Smckusick * The following routine recognises an irregular expresion 3198659Smckusick * with the following special characters: 3208659Smckusick * 3218659Smckusick * \? - means last match was optional 3228659Smckusick * \a - matches any number of characters 3238659Smckusick * \d - matches any number of spaces and tabs 3248659Smckusick * \p - matches any number of alphanumeric 3258659Smckusick * characters. The 3268659Smckusick * characters matched will be copied into 3278659Smckusick * the area pointed to by 'name'. 3288659Smckusick * \| - alternation 3298659Smckusick * \( \) - grouping used mostly for alternation and 3308659Smckusick * optionality 3318659Smckusick * 3328659Smckusick * The irregular expression must be translated to internal form 3338659Smckusick * prior to calling this routine 3348659Smckusick * 3358659Smckusick * The value returned is the pointer to the first non \a 3368659Smckusick * character matched. 3378659Smckusick */ 3388659Smckusick 3398659Smckusick char * 3408659Smckusick expmatch (s, re, mstring) 3418659Smckusick register char *s; /* string to check for a match in */ 3428659Smckusick register char *re; /* a converted irregular expression */ 3438659Smckusick register char *mstring; /* where to put whatever matches a \p */ 3448659Smckusick { 3458659Smckusick register char *cs; /* the current symbol */ 3468659Smckusick register char *ptr,*s1; /* temporary pointer */ 3478659Smckusick boolean matched; /* a temporary boolean */ 3488659Smckusick 3498659Smckusick /* initial conditions */ 3508659Smckusick if (re == NIL) 3518659Smckusick return (NIL); 3528659Smckusick cs = re; 3538659Smckusick matched = FALSE; 3548659Smckusick 3558659Smckusick /* loop till expression string is exhausted (or at least pretty tired) */ 3568659Smckusick while (*cs) { 3578659Smckusick switch (*cs & (OPER | STR | META)) { 3588659Smckusick 3598659Smckusick /* try to match a string */ 3608659Smckusick case STR: 3618659Smckusick matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); 3628659Smckusick if (matched) { 3638659Smckusick 3648659Smckusick /* hoorah it matches */ 3658659Smckusick s += SCNT(cs); 3668659Smckusick cs = SNEXT(cs); 3678659Smckusick } else if (*cs & ALT) { 3688659Smckusick 3698659Smckusick /* alternation, skip to next expression */ 3708659Smckusick cs = SNEXT(cs); 3718659Smckusick } else if (*cs & OPT) { 3728659Smckusick 3738659Smckusick /* the match is optional */ 3748659Smckusick cs = SNEXT(cs); 3758659Smckusick matched = 1; /* indicate a successful match */ 3768659Smckusick } else { 3778659Smckusick 3788659Smckusick /* no match, error return */ 3798659Smckusick return (NIL); 3808659Smckusick } 3818659Smckusick break; 3828659Smckusick 3838659Smckusick /* an operator, do something fancy */ 3848659Smckusick case OPER: 3858659Smckusick switch (OSYM(cs)) { 3868659Smckusick 3878659Smckusick /* this is an alternation */ 3888659Smckusick case '|': 3898659Smckusick if (matched) 3908659Smckusick 3918659Smckusick /* last thing in the alternation was a match, skip ahead */ 3928659Smckusick cs = OPTR(cs); 3938659Smckusick else 3948659Smckusick 3958659Smckusick /* no match, keep trying */ 3968659Smckusick cs = ONEXT(cs); 3978659Smckusick break; 3988659Smckusick 3998659Smckusick /* this is a grouping, recurse */ 4008659Smckusick case '(': 4018659Smckusick ptr = expmatch (s, ONEXT(cs), mstring); 4028659Smckusick if (ptr != NIL) { 4038659Smckusick 4048659Smckusick /* the subexpression matched */ 4058659Smckusick matched = 1; 4068659Smckusick s = ptr; 4078659Smckusick } else if (*cs & ALT) { 4088659Smckusick 4098659Smckusick /* alternation, skip to next expression */ 4108659Smckusick matched = 0; 4118659Smckusick } else if (*cs & OPT) { 4128659Smckusick 4138659Smckusick /* the match is optional */ 4148659Smckusick matched = 1; /* indicate a successful match */ 4158659Smckusick } else { 4168659Smckusick 4178659Smckusick /* no match, error return */ 4188659Smckusick return (NIL); 4198659Smckusick } 4208659Smckusick cs = OPTR(cs); 4218659Smckusick break; 4228659Smckusick } 4238659Smckusick break; 4248659Smckusick 4258659Smckusick /* try to match a metasymbol */ 4268659Smckusick case META: 4278659Smckusick switch (MSYM(cs)) { 4288659Smckusick 4298659Smckusick /* try to match anything and remember what was matched */ 4308659Smckusick case 'p': 4318659Smckusick /* 4328659Smckusick * This is really the same as trying the match the 4338659Smckusick * remaining parts of the expression to any subset 4348659Smckusick * of the string. 4358659Smckusick */ 4368659Smckusick s1 = s; 4378659Smckusick do { 4388659Smckusick ptr = expmatch (s1, MNEXT(cs), mstring); 4398659Smckusick if (ptr != NIL && s1 != s) { 4408659Smckusick 4418659Smckusick /* we have a match, remember the match */ 4428659Smckusick strncpy (mstring, s, s1 - s); 4438659Smckusick mstring[s1 - s] = '\0'; 4448659Smckusick return (ptr); 4458659Smckusick } else if (ptr != NIL && (*cs & OPT)) { 4468659Smckusick 4478659Smckusick /* it was aoptional so no match is ok */ 4488659Smckusick return (ptr); 4498659Smckusick } else if (ptr != NIL) { 4508659Smckusick 4518659Smckusick /* not optional and we still matched */ 4528659Smckusick return (NIL); 4538659Smckusick } 4548659Smckusick if (!isalnum(*s1) && *s1 != '_') 4558659Smckusick return (NIL); 4568659Smckusick if (*s1 == '\\') 4578659Smckusick _escaped = _escaped ? FALSE : TRUE; 4588659Smckusick else 4598659Smckusick _escaped = FALSE; 4608659Smckusick } while (*s1++); 4618659Smckusick return (NIL); 4628659Smckusick 4638659Smckusick /* try to match anything */ 4648659Smckusick case 'a': 4658659Smckusick /* 4668659Smckusick * This is really the same as trying the match the 4678659Smckusick * remaining parts of the expression to any subset 4688659Smckusick * of the string. 4698659Smckusick */ 4708659Smckusick s1 = s; 4718659Smckusick do { 4728659Smckusick ptr = expmatch (s1, MNEXT(cs), mstring); 4738659Smckusick if (ptr != NIL && s1 != s) { 4748659Smckusick 4758659Smckusick /* we have a match */ 4768659Smckusick return (ptr); 4778659Smckusick } else if (ptr != NIL && (*cs & OPT)) { 4788659Smckusick 4798659Smckusick /* it was aoptional so no match is ok */ 4808659Smckusick return (ptr); 4818659Smckusick } else if (ptr != NIL) { 4828659Smckusick 4838659Smckusick /* not optional and we still matched */ 4848659Smckusick return (NIL); 4858659Smckusick } 4868659Smckusick if (*s1 == '\\') 4878659Smckusick _escaped = _escaped ? FALSE : TRUE; 4888659Smckusick else 4898659Smckusick _escaped = FALSE; 4908659Smckusick } while (*s1++); 4918659Smckusick return (NIL); 4928659Smckusick 4938659Smckusick /* fail if we are currently _escaped */ 4948659Smckusick case 'e': 4958659Smckusick if (_escaped) 4968659Smckusick return(NIL); 4978659Smckusick cs = MNEXT(cs); 4988659Smckusick break; 4998659Smckusick 5008659Smckusick /* match any number of tabs and spaces */ 5018659Smckusick case 'd': 5028659Smckusick ptr = s; 5038659Smckusick while (*s == ' ' || *s == '\t') 5048659Smckusick s++; 5058659Smckusick if (s != ptr || s == _start) { 5068659Smckusick 5078659Smckusick /* match, be happy */ 5088659Smckusick matched = 1; 5098659Smckusick cs = MNEXT(cs); 5108659Smckusick } else if (*s == '\n' || *s == '\0') { 5118659Smckusick 5128659Smckusick /* match, be happy */ 5138659Smckusick matched = 1; 5148659Smckusick cs = MNEXT(cs); 5158659Smckusick } else if (*cs & ALT) { 5168659Smckusick 5178659Smckusick /* try the next part */ 5188659Smckusick matched = 0; 5198659Smckusick cs = MNEXT(cs); 5208659Smckusick } else if (*cs & OPT) { 5218659Smckusick 5228659Smckusick /* doesn't matter */ 5238659Smckusick matched = 1; 5248659Smckusick cs = MNEXT(cs); 5258659Smckusick } else 5268659Smckusick 5278659Smckusick /* no match, error return */ 5288659Smckusick return (NIL); 5298659Smckusick break; 5308659Smckusick 5318659Smckusick /* check for end of line */ 5328659Smckusick case '$': 5338659Smckusick if (*s == '\0' || *s == '\n') { 5348659Smckusick 5358659Smckusick /* match, be happy */ 5368659Smckusick s++; 5378659Smckusick matched = 1; 5388659Smckusick cs = MNEXT(cs); 5398659Smckusick } else if (*cs & ALT) { 5408659Smckusick 5418659Smckusick /* try the next part */ 5428659Smckusick matched = 0; 5438659Smckusick cs = MNEXT(cs); 5448659Smckusick } else if (*cs & OPT) { 5458659Smckusick 5468659Smckusick /* doesn't matter */ 5478659Smckusick matched = 1; 5488659Smckusick cs = MNEXT(cs); 5498659Smckusick } else 5508659Smckusick 5518659Smckusick /* no match, error return */ 5528659Smckusick return (NIL); 5538659Smckusick break; 5548659Smckusick 5558659Smckusick /* check for start of line */ 5568659Smckusick case '^': 5578659Smckusick if (s == _start) { 5588659Smckusick 5598659Smckusick /* match, be happy */ 5608659Smckusick matched = 1; 5618659Smckusick cs = MNEXT(cs); 5628659Smckusick } else if (*cs & ALT) { 5638659Smckusick 5648659Smckusick /* try the next part */ 5658659Smckusick matched = 0; 5668659Smckusick cs = MNEXT(cs); 5678659Smckusick } else if (*cs & OPT) { 5688659Smckusick 5698659Smckusick /* doesn't matter */ 5708659Smckusick matched = 1; 5718659Smckusick cs = MNEXT(cs); 5728659Smckusick } else 5738659Smckusick 5748659Smckusick /* no match, error return */ 5758659Smckusick return (NIL); 5768659Smckusick break; 5778659Smckusick 5788659Smckusick /* end of a subexpression, return success */ 5798659Smckusick case ')': 5808659Smckusick return (s); 5818659Smckusick } 5828659Smckusick break; 5838659Smckusick } 5848659Smckusick } 5858659Smckusick return (s); 5868659Smckusick } 587