1331722Seadler/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions and the following disclaimer. 111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer in the 131590Srgrimes * documentation and/or other materials provided with the distribution. 141590Srgrimes * 4. Neither the name of the University nor the names of its contributors 151590Srgrimes * may be used to endorse or promote products derived from this software 161590Srgrimes * without specific prior written permission. 171590Srgrimes * 181590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 191590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 221590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281590Srgrimes * SUCH DAMAGE. 291590Srgrimes */ 301590Srgrimes 3187693Smarkm#include <sys/cdefs.h> 3287693Smarkm 3387693Smarkm__FBSDID("$FreeBSD$"); 3487693Smarkm 351590Srgrimes#ifndef lint 3687693Smarkmstatic const char copyright[] = 371590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 381590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3987693Smarkm#endif 401590Srgrimes 411590Srgrimes#ifndef lint 4287693Smarkmstatic const char sccsid[] = "@(#)regexp.c 8.1 (Berkeley) 6/6/93"; 4387693Smarkm#endif 441590Srgrimes 451590Srgrimes#include <ctype.h> 461590Srgrimes#include <stdlib.h> 47282457Sbapt#include <stdbool.h> 481590Srgrimes#include <string.h> 4987693Smarkm 501590Srgrimes#include "extern.h" 511590Srgrimes 5292922Simpstatic void expconv(void); 531590Srgrimes 54282457Sbaptbool _escaped; /* true if we are currently x_escaped */ 5536053Sjbchar *s_start; /* start of string */ 56282457Sbaptbool l_onecase; /* true if upper and lower equivalent */ 571590Srgrimes 581590Srgrimes#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) 591590Srgrimes 601590Srgrimes/* STRNCMP - like strncmp except that we convert the 611590Srgrimes * first string to lower case before comparing 621590Srgrimes * if l_onecase is set. 631590Srgrimes */ 641590Srgrimes 651590Srgrimesint 66282449SbaptSTRNCMP(register char *s1, register char *s2, register int len) 671590Srgrimes{ 681590Srgrimes if (l_onecase) { 691590Srgrimes do 701590Srgrimes if (*s2 - makelower(*s1)) 711590Srgrimes return (*s2 - makelower(*s1)); 721590Srgrimes else { 731590Srgrimes s2++; 741590Srgrimes s1++; 751590Srgrimes } 761590Srgrimes while (--len); 771590Srgrimes } else { 781590Srgrimes do 791590Srgrimes if (*s2 - *s1) 801590Srgrimes return (*s2 - *s1); 811590Srgrimes else { 821590Srgrimes s2++; 831590Srgrimes s1++; 841590Srgrimes } 851590Srgrimes while (--len); 861590Srgrimes } 871590Srgrimes return(0); 881590Srgrimes} 891590Srgrimes 901590Srgrimes/* The following routine converts an irregular expression to 911590Srgrimes * internal format. 921590Srgrimes * 931590Srgrimes * Either meta symbols (\a \d or \p) or character strings or 94284047Sbapt * operations ( alternation or parenthesizing ) can be 951590Srgrimes * specified. Each starts with a descriptor byte. The descriptor 961590Srgrimes * byte has STR set for strings, META set for meta symbols 971590Srgrimes * and OPER set for operations. 981590Srgrimes * The descriptor byte can also have the OPT bit set if the object 991590Srgrimes * defined is optional. Also ALT can be set to indicate an alternation. 1001590Srgrimes * 1011590Srgrimes * For metasymbols the byte following the descriptor byte identities 1021590Srgrimes * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For 1031590Srgrimes * strings the byte after the descriptor is a character count for 1041590Srgrimes * the string: 1051590Srgrimes * 1061590Srgrimes * meta symbols := descriptor 1071590Srgrimes * symbol 1081590Srgrimes * 1091590Srgrimes * strings := descriptor 1101590Srgrimes * character count 1111590Srgrimes * the string 1121590Srgrimes * 113284047Sbapt * operations := descriptor 1141590Srgrimes * symbol 1151590Srgrimes * character count 1161590Srgrimes */ 1171590Srgrimes 1181590Srgrimes/* 1191590Srgrimes * handy macros for accessing parts of match blocks 1201590Srgrimes */ 1211590Srgrimes#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ 1221590Srgrimes#define MNEXT(A) (A+2) /* character following a metasymbol block */ 1231590Srgrimes 1241590Srgrimes#define OSYM(A) (*(A+1)) /* symbol in an operation block */ 1251590Srgrimes#define OCNT(A) (*(A+2)) /* character count */ 1261590Srgrimes#define ONEXT(A) (A+3) /* next character after the operation */ 1271590Srgrimes#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ 1281590Srgrimes 1291590Srgrimes#define SCNT(A) (*(A+1)) /* byte count of a string */ 1301590Srgrimes#define SSTR(A) (A+2) /* address of the string */ 1311590Srgrimes#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ 1321590Srgrimes 1331590Srgrimes/* 1348874Srgrimes * bit flags in the descriptor 1351590Srgrimes */ 1361590Srgrimes#define OPT 1 1371590Srgrimes#define STR 2 1381590Srgrimes#define META 4 1391590Srgrimes#define ALT 8 1401590Srgrimes#define OPER 16 1411590Srgrimes 1421590Srgrimesstatic char *ccre; /* pointer to current position in converted exp*/ 1431590Srgrimesstatic char *ure; /* pointer current position in unconverted exp */ 1441590Srgrimes 145282449Sbapt/* re: unconverted irregular expression */ 1461590Srgrimeschar * 147282449Sbaptconvexp(char *re) 1481590Srgrimes{ 1491590Srgrimes register char *cre; /* pointer to converted regular expression */ 1501590Srgrimes 1511590Srgrimes /* allocate room for the converted expression */ 152282459Sbapt if (re == NULL) 153282459Sbapt return (NULL); 1541590Srgrimes if (*re == '\0') 155282459Sbapt return (NULL); 156282461Sbapt cre = malloc(4 * strlen(re) + 3); 1571590Srgrimes ccre = cre; 1581590Srgrimes ure = re; 1591590Srgrimes 1601590Srgrimes /* start the conversion with a \a */ 1611590Srgrimes *cre = META | OPT; 1621590Srgrimes MSYM(cre) = 'a'; 1631590Srgrimes ccre = MNEXT(cre); 1641590Srgrimes 1651590Srgrimes /* start the conversion (its recursive) */ 1661590Srgrimes expconv (); 1671590Srgrimes *ccre = 0; 1681590Srgrimes return (cre); 1691590Srgrimes} 1701590Srgrimes 1711590Srgrimesstatic void 1721590Srgrimesexpconv() 1731590Srgrimes{ 1741590Srgrimes register char *cs; /* pointer to current symbol in converted exp */ 1751590Srgrimes register char c; /* character being processed */ 1761590Srgrimes register char *acs; /* pinter to last alternate */ 1771590Srgrimes register int temp; 1781590Srgrimes 1791590Srgrimes /* let the conversion begin */ 180282459Sbapt acs = NULL; 181282459Sbapt cs = NULL; 182282459Sbapt while (*ure) { 1831590Srgrimes switch (c = *ure++) { 1841590Srgrimes 1851590Srgrimes case '\\': 1861590Srgrimes switch (c = *ure++) { 1871590Srgrimes 1881590Srgrimes /* escaped characters are just characters */ 1891590Srgrimes default: 190282459Sbapt if (cs == NULL || (*cs & STR) == 0) { 1911590Srgrimes cs = ccre; 1921590Srgrimes *cs = STR; 1931590Srgrimes SCNT(cs) = 1; 1941590Srgrimes ccre += 2; 1958874Srgrimes } else 1961590Srgrimes SCNT(cs)++; 1971590Srgrimes *ccre++ = c; 1981590Srgrimes break; 1991590Srgrimes 2001590Srgrimes /* normal(?) metacharacters */ 2011590Srgrimes case 'a': 2021590Srgrimes case 'd': 2031590Srgrimes case 'e': 2041590Srgrimes case 'p': 205282459Sbapt if (acs != NULL && acs != cs) { 2061590Srgrimes do { 2071590Srgrimes temp = OCNT(acs); 2088874Srgrimes OCNT(acs) = ccre - acs; 2091590Srgrimes acs -= temp; 2101590Srgrimes } while (temp != 0); 211282459Sbapt acs = NULL; 2121590Srgrimes } 2131590Srgrimes cs = ccre; 2141590Srgrimes *cs = META; 2151590Srgrimes MSYM(cs) = c; 2161590Srgrimes ccre = MNEXT(cs); 2171590Srgrimes break; 2181590Srgrimes } 2191590Srgrimes break; 2208874Srgrimes 2211590Srgrimes /* just put the symbol in */ 2221590Srgrimes case '^': 2231590Srgrimes case '$': 224282459Sbapt if (acs != NULL && acs != cs) { 2251590Srgrimes do { 2261590Srgrimes temp = OCNT(acs); 2271590Srgrimes OCNT(acs) = ccre - acs; 2281590Srgrimes acs -= temp; 2291590Srgrimes } while (temp != 0); 230282459Sbapt acs = NULL; 2311590Srgrimes } 2321590Srgrimes cs = ccre; 2331590Srgrimes *cs = META; 2341590Srgrimes MSYM(cs) = c; 2351590Srgrimes ccre = MNEXT(cs); 2361590Srgrimes break; 2371590Srgrimes 2381590Srgrimes /* mark the last match sequence as optional */ 2391590Srgrimes case '?': 2401590Srgrimes if (cs) 2411590Srgrimes *cs = *cs | OPT; 2421590Srgrimes break; 2431590Srgrimes 2441590Srgrimes /* recurse and define a subexpression */ 2451590Srgrimes case '(': 246282459Sbapt if (acs != NULL && acs != cs) { 2471590Srgrimes do { 2481590Srgrimes temp = OCNT(acs); 2491590Srgrimes OCNT(acs) = ccre - acs; 2501590Srgrimes acs -= temp; 2511590Srgrimes } while (temp != 0); 252282459Sbapt acs = NULL; 2531590Srgrimes } 2541590Srgrimes cs = ccre; 2551590Srgrimes *cs = OPER; 2561590Srgrimes OSYM(cs) = '('; 2571590Srgrimes ccre = ONEXT(cs); 258282461Sbapt expconv(); 2591590Srgrimes OCNT(cs) = ccre - cs; /* offset to next symbol */ 2601590Srgrimes break; 2611590Srgrimes 26219012Sjoerg /* return from a recursion */ 2631590Srgrimes case ')': 264282459Sbapt if (acs != NULL) { 2651590Srgrimes do { 2661590Srgrimes temp = OCNT(acs); 2671590Srgrimes OCNT(acs) = ccre - acs; 2681590Srgrimes acs -= temp; 2691590Srgrimes } while (temp != 0); 270282459Sbapt acs = NULL; 2711590Srgrimes } 2721590Srgrimes cs = ccre; 2731590Srgrimes *cs = META; 2741590Srgrimes MSYM(cs) = c; 2751590Srgrimes ccre = MNEXT(cs); 2761590Srgrimes return; 2771590Srgrimes 2781590Srgrimes /* mark the last match sequence as having an alternate */ 2791590Srgrimes /* the third byte will contain an offset to jump over the */ 2801590Srgrimes /* alternate match in case the first did not fail */ 2811590Srgrimes case '|': 282282459Sbapt if (acs != NULL && acs != cs) 2831590Srgrimes OCNT(ccre) = ccre - acs; /* make a back pointer */ 2841590Srgrimes else 2851590Srgrimes OCNT(ccre) = 0; 2861590Srgrimes *cs |= ALT; 2871590Srgrimes cs = ccre; 2881590Srgrimes *cs = OPER; 2891590Srgrimes OSYM(cs) = '|'; 2901590Srgrimes ccre = ONEXT(cs); 2911590Srgrimes acs = cs; /* remember that the pointer is to be filles */ 2921590Srgrimes break; 2931590Srgrimes 2941590Srgrimes /* if its not a metasymbol just build a scharacter string */ 2951590Srgrimes default: 296282459Sbapt if (cs == NULL || (*cs & STR) == 0) { 2971590Srgrimes cs = ccre; 2981590Srgrimes *cs = STR; 2991590Srgrimes SCNT(cs) = 1; 3001590Srgrimes ccre = SSTR(cs); 3011590Srgrimes } else 3021590Srgrimes SCNT(cs)++; 3031590Srgrimes *ccre++ = c; 3041590Srgrimes break; 3051590Srgrimes } 3061590Srgrimes } 307282459Sbapt if (acs != NULL) { 3081590Srgrimes do { 3091590Srgrimes temp = OCNT(acs); 3101590Srgrimes OCNT(acs) = ccre - acs; 3111590Srgrimes acs -= temp; 3121590Srgrimes } while (temp != 0); 313282459Sbapt acs = NULL; 3141590Srgrimes } 3151590Srgrimes return; 3161590Srgrimes} 3171590Srgrimes/* end of convertre */ 3181590Srgrimes 3191590Srgrimes 3201590Srgrimes/* 321289677Seadler * The following routine recognises an irregular expression 3221590Srgrimes * with the following special characters: 3231590Srgrimes * 3241590Srgrimes * \? - means last match was optional 3251590Srgrimes * \a - matches any number of characters 3261590Srgrimes * \d - matches any number of spaces and tabs 3271590Srgrimes * \p - matches any number of alphanumeric 3281590Srgrimes * characters. The 3291590Srgrimes * characters matched will be copied into 3301590Srgrimes * the area pointed to by 'name'. 3311590Srgrimes * \| - alternation 3321590Srgrimes * \( \) - grouping used mostly for alternation and 3331590Srgrimes * optionality 3341590Srgrimes * 3351590Srgrimes * The irregular expression must be translated to internal form 3361590Srgrimes * prior to calling this routine 3371590Srgrimes * 3388874Srgrimes * The value returned is the pointer to the first non \a 3391590Srgrimes * character matched. 3401590Srgrimes */ 3411590Srgrimes 342282449Sbapt/* 343282449Sbapt * s: string to check for a match in 344282449Sbapt * re: a converted irregular expression 345282449Sbapt * mstring: where to put whatever matches a \p 346282449Sbapt */ 3471590Srgrimeschar * 348282449Sbaptexpmatch (register char *s, register char *re, register char *mstring) 3491590Srgrimes{ 3501590Srgrimes register char *cs; /* the current symbol */ 3511590Srgrimes register char *ptr,*s1; /* temporary pointer */ 352282457Sbapt bool matched; /* a temporary bool */ 3531590Srgrimes 3541590Srgrimes /* initial conditions */ 355282459Sbapt if (re == NULL) 356282459Sbapt return (NULL); 3571590Srgrimes cs = re; 358282457Sbapt matched = false; 3591590Srgrimes 3601590Srgrimes /* loop till expression string is exhausted (or at least pretty tired) */ 3611590Srgrimes while (*cs) { 3621590Srgrimes switch (*cs & (OPER | STR | META)) { 3631590Srgrimes 3641590Srgrimes /* try to match a string */ 3651590Srgrimes case STR: 3661590Srgrimes matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); 3671590Srgrimes if (matched) { 3681590Srgrimes 3691590Srgrimes /* hoorah it matches */ 3701590Srgrimes s += SCNT(cs); 3711590Srgrimes cs = SNEXT(cs); 3721590Srgrimes } else if (*cs & ALT) { 3731590Srgrimes 3741590Srgrimes /* alternation, skip to next expression */ 3751590Srgrimes cs = SNEXT(cs); 3761590Srgrimes } else if (*cs & OPT) { 3771590Srgrimes 3781590Srgrimes /* the match is optional */ 3791590Srgrimes cs = SNEXT(cs); 3801590Srgrimes matched = 1; /* indicate a successful match */ 3811590Srgrimes } else { 3821590Srgrimes 3831590Srgrimes /* no match, error return */ 384282459Sbapt return (NULL); 3851590Srgrimes } 3861590Srgrimes break; 3871590Srgrimes 3881590Srgrimes /* an operator, do something fancy */ 3891590Srgrimes case OPER: 3901590Srgrimes switch (OSYM(cs)) { 3911590Srgrimes 3921590Srgrimes /* this is an alternation */ 3931590Srgrimes case '|': 3941590Srgrimes if (matched) 3951590Srgrimes 3961590Srgrimes /* last thing in the alternation was a match, skip ahead */ 3971590Srgrimes cs = OPTR(cs); 3981590Srgrimes else 3991590Srgrimes 4001590Srgrimes /* no match, keep trying */ 4011590Srgrimes cs = ONEXT(cs); 4021590Srgrimes break; 4031590Srgrimes 4041590Srgrimes /* this is a grouping, recurse */ 4051590Srgrimes case '(': 406282461Sbapt ptr = expmatch(s, ONEXT(cs), mstring); 407282459Sbapt if (ptr != NULL) { 4081590Srgrimes 4091590Srgrimes /* the subexpression matched */ 4101590Srgrimes matched = 1; 4111590Srgrimes s = ptr; 4121590Srgrimes } else if (*cs & ALT) { 4131590Srgrimes 4141590Srgrimes /* alternation, skip to next expression */ 4151590Srgrimes matched = 0; 4161590Srgrimes } else if (*cs & OPT) { 4171590Srgrimes 4181590Srgrimes /* the match is optional */ 4191590Srgrimes matched = 1; /* indicate a successful match */ 4201590Srgrimes } else { 4211590Srgrimes 4221590Srgrimes /* no match, error return */ 423282459Sbapt return (NULL); 4241590Srgrimes } 4251590Srgrimes cs = OPTR(cs); 4261590Srgrimes break; 4271590Srgrimes } 4281590Srgrimes break; 4291590Srgrimes 4301590Srgrimes /* try to match a metasymbol */ 4311590Srgrimes case META: 4321590Srgrimes switch (MSYM(cs)) { 4331590Srgrimes 4341590Srgrimes /* try to match anything and remember what was matched */ 4351590Srgrimes case 'p': 4361590Srgrimes /* 4371590Srgrimes * This is really the same as trying the match the 4381590Srgrimes * remaining parts of the expression to any subset 4391590Srgrimes * of the string. 4401590Srgrimes */ 4411590Srgrimes s1 = s; 4421590Srgrimes do { 443282461Sbapt ptr = expmatch(s1, MNEXT(cs), mstring); 444282459Sbapt if (ptr != NULL && s1 != s) { 4451590Srgrimes 4461590Srgrimes /* we have a match, remember the match */ 4471590Srgrimes strncpy (mstring, s, s1 - s); 4481590Srgrimes mstring[s1 - s] = '\0'; 4491590Srgrimes return (ptr); 450282459Sbapt } else if (ptr != NULL && (*cs & OPT)) { 4511590Srgrimes 4521590Srgrimes /* it was aoptional so no match is ok */ 4531590Srgrimes return (ptr); 454282459Sbapt } else if (ptr != NULL) { 4551590Srgrimes 4561590Srgrimes /* not optional and we still matched */ 457282459Sbapt return (NULL); 4581590Srgrimes } 45919019Sjoerg if (!(isalnum(*s1) || *s1 == '_' || 46019019Sjoerg /* C++ destructor */ 46119019Sjoerg *s1 == '~' || 46219019Sjoerg /* C++ scope operator */ 46319019Sjoerg (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' && 464282457Sbapt (s1++, true)))) 465282459Sbapt return (NULL); 4661590Srgrimes if (*s1 == '\\') 467282457Sbapt _escaped = _escaped ? false : true; 4681590Srgrimes else 469282457Sbapt _escaped = false; 4701590Srgrimes } while (*s1++); 471282459Sbapt return (NULL); 4721590Srgrimes 4731590Srgrimes /* try to match anything */ 4741590Srgrimes case 'a': 4751590Srgrimes /* 4761590Srgrimes * This is really the same as trying the match the 4771590Srgrimes * remaining parts of the expression to any subset 4781590Srgrimes * of the string. 4791590Srgrimes */ 4801590Srgrimes s1 = s; 4811590Srgrimes do { 482282461Sbapt ptr = expmatch(s1, MNEXT(cs), mstring); 483282459Sbapt if (ptr != NULL && s1 != s) { 4841590Srgrimes 4851590Srgrimes /* we have a match */ 4861590Srgrimes return (ptr); 487282459Sbapt } else if (ptr != NULL && (*cs & OPT)) { 4881590Srgrimes 4891590Srgrimes /* it was aoptional so no match is ok */ 4901590Srgrimes return (ptr); 491282459Sbapt } else if (ptr != NULL) { 4921590Srgrimes 4931590Srgrimes /* not optional and we still matched */ 494282459Sbapt return (NULL); 4951590Srgrimes } 4961590Srgrimes if (*s1 == '\\') 497282457Sbapt _escaped = _escaped ? false : true; 4981590Srgrimes else 499282457Sbapt _escaped = false; 5001590Srgrimes } while (*s1++); 501282459Sbapt return (NULL); 5021590Srgrimes 5031590Srgrimes /* fail if we are currently _escaped */ 5041590Srgrimes case 'e': 5051590Srgrimes if (_escaped) 506282459Sbapt return(NULL); 5078874Srgrimes cs = MNEXT(cs); 5081590Srgrimes break; 5091590Srgrimes 5101590Srgrimes /* match any number of tabs and spaces */ 5111590Srgrimes case 'd': 5121590Srgrimes ptr = s; 5131590Srgrimes while (*s == ' ' || *s == '\t') 5141590Srgrimes s++; 51536053Sjb if (s != ptr || s == s_start) { 5161590Srgrimes 5171590Srgrimes /* match, be happy */ 5181590Srgrimes matched = 1; 5198874Srgrimes cs = MNEXT(cs); 5201590Srgrimes } else if (*s == '\n' || *s == '\0') { 5211590Srgrimes 5221590Srgrimes /* match, be happy */ 5231590Srgrimes matched = 1; 5248874Srgrimes cs = MNEXT(cs); 5251590Srgrimes } else if (*cs & ALT) { 5261590Srgrimes 5271590Srgrimes /* try the next part */ 5281590Srgrimes matched = 0; 5291590Srgrimes cs = MNEXT(cs); 5301590Srgrimes } else if (*cs & OPT) { 5311590Srgrimes 5321590Srgrimes /* doesn't matter */ 5331590Srgrimes matched = 1; 5341590Srgrimes cs = MNEXT(cs); 5351590Srgrimes } else 5361590Srgrimes 5371590Srgrimes /* no match, error return */ 538282459Sbapt return (NULL); 5391590Srgrimes break; 5401590Srgrimes 5411590Srgrimes /* check for end of line */ 5421590Srgrimes case '$': 5431590Srgrimes if (*s == '\0' || *s == '\n') { 5441590Srgrimes 5451590Srgrimes /* match, be happy */ 5461590Srgrimes s++; 5471590Srgrimes matched = 1; 5481590Srgrimes cs = MNEXT(cs); 5491590Srgrimes } else if (*cs & ALT) { 5501590Srgrimes 5511590Srgrimes /* try the next part */ 5521590Srgrimes matched = 0; 5531590Srgrimes cs = MNEXT(cs); 5541590Srgrimes } else if (*cs & OPT) { 5551590Srgrimes 5561590Srgrimes /* doesn't matter */ 5571590Srgrimes matched = 1; 5581590Srgrimes cs = MNEXT(cs); 5591590Srgrimes } else 5601590Srgrimes 5611590Srgrimes /* no match, error return */ 562282459Sbapt return (NULL); 5631590Srgrimes break; 5641590Srgrimes 5651590Srgrimes /* check for start of line */ 5661590Srgrimes case '^': 56736053Sjb if (s == s_start) { 5681590Srgrimes 5691590Srgrimes /* match, be happy */ 5701590Srgrimes matched = 1; 5711590Srgrimes cs = MNEXT(cs); 5721590Srgrimes } else if (*cs & ALT) { 5731590Srgrimes 5741590Srgrimes /* try the next part */ 5751590Srgrimes matched = 0; 5761590Srgrimes cs = MNEXT(cs); 5771590Srgrimes } else if (*cs & OPT) { 5781590Srgrimes 5791590Srgrimes /* doesn't matter */ 5801590Srgrimes matched = 1; 5811590Srgrimes cs = MNEXT(cs); 5821590Srgrimes } else 5831590Srgrimes 5841590Srgrimes /* no match, error return */ 585282459Sbapt return (NULL); 5861590Srgrimes break; 5871590Srgrimes 5881590Srgrimes /* end of a subexpression, return success */ 5891590Srgrimes case ')': 5901590Srgrimes return (s); 5911590Srgrimes } 5921590Srgrimes break; 5931590Srgrimes } 5941590Srgrimes } 5951590Srgrimes return (s); 5961590Srgrimes} 597