regexp.c revision 87693
11590Srgrimes/* 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 * 3. All advertising materials mentioning features or use of this software 151590Srgrimes * must display the following acknowledgement: 161590Srgrimes * This product includes software developed by the University of 171590Srgrimes * California, Berkeley and its contributors. 181590Srgrimes * 4. Neither the name of the University nor the names of its contributors 191590Srgrimes * may be used to endorse or promote products derived from this software 201590Srgrimes * without specific prior written permission. 211590Srgrimes * 221590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321590Srgrimes * SUCH DAMAGE. 331590Srgrimes */ 341590Srgrimes 3587693Smarkm#include <sys/cdefs.h> 3687693Smarkm 3787693Smarkm__FBSDID("$FreeBSD: head/usr.bin/vgrind/regexp.c 87693 2001-12-11 23:10:26Z markm $"); 3887693Smarkm 391590Srgrimes#ifndef lint 4087693Smarkmstatic const char copyright[] = 411590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 421590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4387693Smarkm#endif 441590Srgrimes 451590Srgrimes#ifndef lint 4687693Smarkmstatic const char sccsid[] = "@(#)regexp.c 8.1 (Berkeley) 6/6/93"; 4787693Smarkm#endif 481590Srgrimes 491590Srgrimes#include <ctype.h> 501590Srgrimes#include <stdlib.h> 511590Srgrimes#include <string.h> 5287693Smarkm 531590Srgrimes#include "extern.h" 541590Srgrimes 551590Srgrimes#define FALSE 0 561590Srgrimes#define TRUE !(FALSE) 571590Srgrimes#define NIL 0 581590Srgrimes 591590Srgrimesstatic void expconv __P((void)); 601590Srgrimes 611590Srgrimesboolean _escaped; /* true if we are currently _escaped */ 6236053Sjbchar *s_start; /* start of string */ 631590Srgrimesboolean l_onecase; /* true if upper and lower equivalent */ 641590Srgrimes 651590Srgrimes#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) 661590Srgrimes 671590Srgrimes/* STRNCMP - like strncmp except that we convert the 681590Srgrimes * first string to lower case before comparing 691590Srgrimes * if l_onecase is set. 701590Srgrimes */ 711590Srgrimes 721590Srgrimesint 731590SrgrimesSTRNCMP(s1, s2, len) 741590Srgrimes register char *s1,*s2; 751590Srgrimes register int len; 761590Srgrimes{ 771590Srgrimes if (l_onecase) { 781590Srgrimes do 791590Srgrimes if (*s2 - makelower(*s1)) 801590Srgrimes return (*s2 - makelower(*s1)); 811590Srgrimes else { 821590Srgrimes s2++; 831590Srgrimes s1++; 841590Srgrimes } 851590Srgrimes while (--len); 861590Srgrimes } else { 871590Srgrimes do 881590Srgrimes if (*s2 - *s1) 891590Srgrimes return (*s2 - *s1); 901590Srgrimes else { 911590Srgrimes s2++; 921590Srgrimes s1++; 931590Srgrimes } 941590Srgrimes while (--len); 951590Srgrimes } 961590Srgrimes return(0); 971590Srgrimes} 981590Srgrimes 991590Srgrimes/* The following routine converts an irregular expression to 1001590Srgrimes * internal format. 1011590Srgrimes * 1021590Srgrimes * Either meta symbols (\a \d or \p) or character strings or 1031590Srgrimes * operations ( alternation or perenthesizing ) can be 1041590Srgrimes * specified. Each starts with a descriptor byte. The descriptor 1051590Srgrimes * byte has STR set for strings, META set for meta symbols 1061590Srgrimes * and OPER set for operations. 1071590Srgrimes * The descriptor byte can also have the OPT bit set if the object 1081590Srgrimes * defined is optional. Also ALT can be set to indicate an alternation. 1091590Srgrimes * 1101590Srgrimes * For metasymbols the byte following the descriptor byte identities 1111590Srgrimes * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For 1121590Srgrimes * strings the byte after the descriptor is a character count for 1131590Srgrimes * the string: 1141590Srgrimes * 1151590Srgrimes * meta symbols := descriptor 1161590Srgrimes * symbol 1171590Srgrimes * 1181590Srgrimes * strings := descriptor 1191590Srgrimes * character count 1201590Srgrimes * the string 1211590Srgrimes * 1221590Srgrimes * operatins := descriptor 1231590Srgrimes * symbol 1241590Srgrimes * character count 1251590Srgrimes */ 1261590Srgrimes 1271590Srgrimes/* 1281590Srgrimes * handy macros for accessing parts of match blocks 1291590Srgrimes */ 1301590Srgrimes#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ 1311590Srgrimes#define MNEXT(A) (A+2) /* character following a metasymbol block */ 1321590Srgrimes 1331590Srgrimes#define OSYM(A) (*(A+1)) /* symbol in an operation block */ 1341590Srgrimes#define OCNT(A) (*(A+2)) /* character count */ 1351590Srgrimes#define ONEXT(A) (A+3) /* next character after the operation */ 1361590Srgrimes#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ 1371590Srgrimes 1381590Srgrimes#define SCNT(A) (*(A+1)) /* byte count of a string */ 1391590Srgrimes#define SSTR(A) (A+2) /* address of the string */ 1401590Srgrimes#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ 1411590Srgrimes 1421590Srgrimes/* 1438874Srgrimes * bit flags in the descriptor 1441590Srgrimes */ 1451590Srgrimes#define OPT 1 1461590Srgrimes#define STR 2 1471590Srgrimes#define META 4 1481590Srgrimes#define ALT 8 1491590Srgrimes#define OPER 16 1501590Srgrimes 1511590Srgrimesstatic char *ccre; /* pointer to current position in converted exp*/ 1521590Srgrimesstatic char *ure; /* pointer current position in unconverted exp */ 1531590Srgrimes 1541590Srgrimeschar * 1551590Srgrimesconvexp(re) 1561590Srgrimes char *re; /* unconverted irregular expression */ 1571590Srgrimes{ 1581590Srgrimes register char *cre; /* pointer to converted regular expression */ 1591590Srgrimes 1601590Srgrimes /* allocate room for the converted expression */ 1611590Srgrimes if (re == NIL) 1621590Srgrimes return (NIL); 1631590Srgrimes if (*re == '\0') 1641590Srgrimes return (NIL); 1651590Srgrimes cre = malloc (4 * strlen(re) + 3); 1661590Srgrimes ccre = cre; 1671590Srgrimes ure = re; 1681590Srgrimes 1691590Srgrimes /* start the conversion with a \a */ 1701590Srgrimes *cre = META | OPT; 1711590Srgrimes MSYM(cre) = 'a'; 1721590Srgrimes ccre = MNEXT(cre); 1731590Srgrimes 1741590Srgrimes /* start the conversion (its recursive) */ 1751590Srgrimes expconv (); 1761590Srgrimes *ccre = 0; 1771590Srgrimes return (cre); 1781590Srgrimes} 1791590Srgrimes 1801590Srgrimesstatic void 1811590Srgrimesexpconv() 1821590Srgrimes{ 1831590Srgrimes register char *cs; /* pointer to current symbol in converted exp */ 1841590Srgrimes register char c; /* character being processed */ 1851590Srgrimes register char *acs; /* pinter to last alternate */ 1861590Srgrimes register int temp; 1871590Srgrimes 1881590Srgrimes /* let the conversion begin */ 1891590Srgrimes acs = NIL; 1901590Srgrimes cs = NIL; 1911590Srgrimes while (*ure != NIL) { 1921590Srgrimes switch (c = *ure++) { 1931590Srgrimes 1941590Srgrimes case '\\': 1951590Srgrimes switch (c = *ure++) { 1961590Srgrimes 1971590Srgrimes /* escaped characters are just characters */ 1981590Srgrimes default: 1991590Srgrimes if (cs == NIL || (*cs & STR) == 0) { 2001590Srgrimes cs = ccre; 2011590Srgrimes *cs = STR; 2021590Srgrimes SCNT(cs) = 1; 2031590Srgrimes ccre += 2; 2048874Srgrimes } else 2051590Srgrimes SCNT(cs)++; 2061590Srgrimes *ccre++ = c; 2071590Srgrimes break; 2081590Srgrimes 2091590Srgrimes /* normal(?) metacharacters */ 2101590Srgrimes case 'a': 2111590Srgrimes case 'd': 2121590Srgrimes case 'e': 2131590Srgrimes case 'p': 2141590Srgrimes if (acs != NIL && acs != cs) { 2151590Srgrimes do { 2161590Srgrimes temp = OCNT(acs); 2178874Srgrimes OCNT(acs) = ccre - acs; 2181590Srgrimes acs -= temp; 2191590Srgrimes } while (temp != 0); 2201590Srgrimes acs = NIL; 2211590Srgrimes } 2221590Srgrimes cs = ccre; 2231590Srgrimes *cs = META; 2241590Srgrimes MSYM(cs) = c; 2251590Srgrimes ccre = MNEXT(cs); 2261590Srgrimes break; 2271590Srgrimes } 2281590Srgrimes break; 2298874Srgrimes 2301590Srgrimes /* just put the symbol in */ 2311590Srgrimes case '^': 2321590Srgrimes case '$': 2331590Srgrimes if (acs != NIL && acs != cs) { 2341590Srgrimes do { 2351590Srgrimes temp = OCNT(acs); 2361590Srgrimes OCNT(acs) = ccre - acs; 2371590Srgrimes acs -= temp; 2381590Srgrimes } while (temp != 0); 2391590Srgrimes acs = NIL; 2401590Srgrimes } 2411590Srgrimes cs = ccre; 2421590Srgrimes *cs = META; 2431590Srgrimes MSYM(cs) = c; 2441590Srgrimes ccre = MNEXT(cs); 2451590Srgrimes break; 2461590Srgrimes 2471590Srgrimes /* mark the last match sequence as optional */ 2481590Srgrimes case '?': 2491590Srgrimes if (cs) 2501590Srgrimes *cs = *cs | OPT; 2511590Srgrimes break; 2521590Srgrimes 2531590Srgrimes /* recurse and define a subexpression */ 2541590Srgrimes case '(': 2551590Srgrimes if (acs != NIL && acs != cs) { 2561590Srgrimes do { 2571590Srgrimes temp = OCNT(acs); 2581590Srgrimes OCNT(acs) = ccre - acs; 2591590Srgrimes acs -= temp; 2601590Srgrimes } while (temp != 0); 2611590Srgrimes acs = NIL; 2621590Srgrimes } 2631590Srgrimes cs = ccre; 2641590Srgrimes *cs = OPER; 2651590Srgrimes OSYM(cs) = '('; 2661590Srgrimes ccre = ONEXT(cs); 2671590Srgrimes expconv (); 2681590Srgrimes OCNT(cs) = ccre - cs; /* offset to next symbol */ 2691590Srgrimes break; 2701590Srgrimes 27119012Sjoerg /* return from a recursion */ 2721590Srgrimes case ')': 2731590Srgrimes if (acs != NIL) { 2741590Srgrimes do { 2751590Srgrimes temp = OCNT(acs); 2761590Srgrimes OCNT(acs) = ccre - acs; 2771590Srgrimes acs -= temp; 2781590Srgrimes } while (temp != 0); 2791590Srgrimes acs = NIL; 2801590Srgrimes } 2811590Srgrimes cs = ccre; 2821590Srgrimes *cs = META; 2831590Srgrimes MSYM(cs) = c; 2841590Srgrimes ccre = MNEXT(cs); 2851590Srgrimes return; 2861590Srgrimes 2871590Srgrimes /* mark the last match sequence as having an alternate */ 2881590Srgrimes /* the third byte will contain an offset to jump over the */ 2891590Srgrimes /* alternate match in case the first did not fail */ 2901590Srgrimes case '|': 2911590Srgrimes if (acs != NIL && acs != cs) 2921590Srgrimes OCNT(ccre) = ccre - acs; /* make a back pointer */ 2931590Srgrimes else 2941590Srgrimes OCNT(ccre) = 0; 2951590Srgrimes *cs |= ALT; 2961590Srgrimes cs = ccre; 2971590Srgrimes *cs = OPER; 2981590Srgrimes OSYM(cs) = '|'; 2991590Srgrimes ccre = ONEXT(cs); 3001590Srgrimes acs = cs; /* remember that the pointer is to be filles */ 3011590Srgrimes break; 3021590Srgrimes 3031590Srgrimes /* if its not a metasymbol just build a scharacter string */ 3041590Srgrimes default: 3051590Srgrimes if (cs == NIL || (*cs & STR) == 0) { 3061590Srgrimes cs = ccre; 3071590Srgrimes *cs = STR; 3081590Srgrimes SCNT(cs) = 1; 3091590Srgrimes ccre = SSTR(cs); 3101590Srgrimes } else 3111590Srgrimes SCNT(cs)++; 3121590Srgrimes *ccre++ = c; 3131590Srgrimes break; 3141590Srgrimes } 3151590Srgrimes } 3161590Srgrimes if (acs != NIL) { 3171590Srgrimes do { 3181590Srgrimes temp = OCNT(acs); 3191590Srgrimes OCNT(acs) = ccre - acs; 3201590Srgrimes acs -= temp; 3211590Srgrimes } while (temp != 0); 3221590Srgrimes acs = NIL; 3231590Srgrimes } 3241590Srgrimes return; 3251590Srgrimes} 3261590Srgrimes/* end of convertre */ 3271590Srgrimes 3281590Srgrimes 3291590Srgrimes/* 3301590Srgrimes * The following routine recognises an irregular expresion 3311590Srgrimes * with the following special characters: 3321590Srgrimes * 3331590Srgrimes * \? - means last match was optional 3341590Srgrimes * \a - matches any number of characters 3351590Srgrimes * \d - matches any number of spaces and tabs 3361590Srgrimes * \p - matches any number of alphanumeric 3371590Srgrimes * characters. The 3381590Srgrimes * characters matched will be copied into 3391590Srgrimes * the area pointed to by 'name'. 3401590Srgrimes * \| - alternation 3411590Srgrimes * \( \) - grouping used mostly for alternation and 3421590Srgrimes * optionality 3431590Srgrimes * 3441590Srgrimes * The irregular expression must be translated to internal form 3451590Srgrimes * prior to calling this routine 3461590Srgrimes * 3478874Srgrimes * The value returned is the pointer to the first non \a 3481590Srgrimes * character matched. 3491590Srgrimes */ 3501590Srgrimes 3511590Srgrimeschar * 3521590Srgrimesexpmatch (s, re, mstring) 3531590Srgrimes register char *s; /* string to check for a match in */ 3541590Srgrimes register char *re; /* a converted irregular expression */ 3551590Srgrimes register char *mstring; /* where to put whatever matches a \p */ 3561590Srgrimes{ 3571590Srgrimes register char *cs; /* the current symbol */ 3581590Srgrimes register char *ptr,*s1; /* temporary pointer */ 3591590Srgrimes boolean matched; /* a temporary boolean */ 3601590Srgrimes 3611590Srgrimes /* initial conditions */ 3621590Srgrimes if (re == NIL) 3631590Srgrimes return (NIL); 3641590Srgrimes cs = re; 3651590Srgrimes matched = FALSE; 3661590Srgrimes 3671590Srgrimes /* loop till expression string is exhausted (or at least pretty tired) */ 3681590Srgrimes while (*cs) { 3691590Srgrimes switch (*cs & (OPER | STR | META)) { 3701590Srgrimes 3711590Srgrimes /* try to match a string */ 3721590Srgrimes case STR: 3731590Srgrimes matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); 3741590Srgrimes if (matched) { 3751590Srgrimes 3761590Srgrimes /* hoorah it matches */ 3771590Srgrimes s += SCNT(cs); 3781590Srgrimes cs = SNEXT(cs); 3791590Srgrimes } else if (*cs & ALT) { 3801590Srgrimes 3811590Srgrimes /* alternation, skip to next expression */ 3821590Srgrimes cs = SNEXT(cs); 3831590Srgrimes } else if (*cs & OPT) { 3841590Srgrimes 3851590Srgrimes /* the match is optional */ 3861590Srgrimes cs = SNEXT(cs); 3871590Srgrimes matched = 1; /* indicate a successful match */ 3881590Srgrimes } else { 3891590Srgrimes 3901590Srgrimes /* no match, error return */ 3911590Srgrimes return (NIL); 3921590Srgrimes } 3931590Srgrimes break; 3941590Srgrimes 3951590Srgrimes /* an operator, do something fancy */ 3961590Srgrimes case OPER: 3971590Srgrimes switch (OSYM(cs)) { 3981590Srgrimes 3991590Srgrimes /* this is an alternation */ 4001590Srgrimes case '|': 4011590Srgrimes if (matched) 4021590Srgrimes 4031590Srgrimes /* last thing in the alternation was a match, skip ahead */ 4041590Srgrimes cs = OPTR(cs); 4051590Srgrimes else 4061590Srgrimes 4071590Srgrimes /* no match, keep trying */ 4081590Srgrimes cs = ONEXT(cs); 4091590Srgrimes break; 4101590Srgrimes 4111590Srgrimes /* this is a grouping, recurse */ 4121590Srgrimes case '(': 4131590Srgrimes ptr = expmatch (s, ONEXT(cs), mstring); 4141590Srgrimes if (ptr != NIL) { 4151590Srgrimes 4161590Srgrimes /* the subexpression matched */ 4171590Srgrimes matched = 1; 4181590Srgrimes s = ptr; 4191590Srgrimes } else if (*cs & ALT) { 4201590Srgrimes 4211590Srgrimes /* alternation, skip to next expression */ 4221590Srgrimes matched = 0; 4231590Srgrimes } else if (*cs & OPT) { 4241590Srgrimes 4251590Srgrimes /* the match is optional */ 4261590Srgrimes matched = 1; /* indicate a successful match */ 4271590Srgrimes } else { 4281590Srgrimes 4291590Srgrimes /* no match, error return */ 4301590Srgrimes return (NIL); 4311590Srgrimes } 4321590Srgrimes cs = OPTR(cs); 4331590Srgrimes break; 4341590Srgrimes } 4351590Srgrimes break; 4361590Srgrimes 4371590Srgrimes /* try to match a metasymbol */ 4381590Srgrimes case META: 4391590Srgrimes switch (MSYM(cs)) { 4401590Srgrimes 4411590Srgrimes /* try to match anything and remember what was matched */ 4421590Srgrimes case 'p': 4431590Srgrimes /* 4441590Srgrimes * This is really the same as trying the match the 4451590Srgrimes * remaining parts of the expression to any subset 4461590Srgrimes * of the string. 4471590Srgrimes */ 4481590Srgrimes s1 = s; 4491590Srgrimes do { 4501590Srgrimes ptr = expmatch (s1, MNEXT(cs), mstring); 4511590Srgrimes if (ptr != NIL && s1 != s) { 4521590Srgrimes 4531590Srgrimes /* we have a match, remember the match */ 4541590Srgrimes strncpy (mstring, s, s1 - s); 4551590Srgrimes mstring[s1 - s] = '\0'; 4561590Srgrimes return (ptr); 4571590Srgrimes } else if (ptr != NIL && (*cs & OPT)) { 4581590Srgrimes 4591590Srgrimes /* it was aoptional so no match is ok */ 4601590Srgrimes return (ptr); 4611590Srgrimes } else if (ptr != NIL) { 4621590Srgrimes 4631590Srgrimes /* not optional and we still matched */ 4641590Srgrimes return (NIL); 4651590Srgrimes } 46619019Sjoerg if (!(isalnum(*s1) || *s1 == '_' || 46719019Sjoerg /* C++ destructor */ 46819019Sjoerg *s1 == '~' || 46919019Sjoerg /* C++ scope operator */ 47019019Sjoerg (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' && 47119019Sjoerg (s1++, TRUE)))) 4721590Srgrimes return (NIL); 4731590Srgrimes if (*s1 == '\\') 4741590Srgrimes _escaped = _escaped ? FALSE : TRUE; 4751590Srgrimes else 4761590Srgrimes _escaped = FALSE; 4771590Srgrimes } while (*s1++); 4781590Srgrimes return (NIL); 4791590Srgrimes 4801590Srgrimes /* try to match anything */ 4811590Srgrimes case 'a': 4821590Srgrimes /* 4831590Srgrimes * This is really the same as trying the match the 4841590Srgrimes * remaining parts of the expression to any subset 4851590Srgrimes * of the string. 4861590Srgrimes */ 4871590Srgrimes s1 = s; 4881590Srgrimes do { 4891590Srgrimes ptr = expmatch (s1, MNEXT(cs), mstring); 4901590Srgrimes if (ptr != NIL && s1 != s) { 4911590Srgrimes 4921590Srgrimes /* we have a match */ 4931590Srgrimes return (ptr); 4941590Srgrimes } else if (ptr != NIL && (*cs & OPT)) { 4951590Srgrimes 4961590Srgrimes /* it was aoptional so no match is ok */ 4971590Srgrimes return (ptr); 4981590Srgrimes } else if (ptr != NIL) { 4991590Srgrimes 5001590Srgrimes /* not optional and we still matched */ 5011590Srgrimes return (NIL); 5021590Srgrimes } 5031590Srgrimes if (*s1 == '\\') 5041590Srgrimes _escaped = _escaped ? FALSE : TRUE; 5051590Srgrimes else 5061590Srgrimes _escaped = FALSE; 5071590Srgrimes } while (*s1++); 5081590Srgrimes return (NIL); 5091590Srgrimes 5101590Srgrimes /* fail if we are currently _escaped */ 5111590Srgrimes case 'e': 5121590Srgrimes if (_escaped) 5131590Srgrimes return(NIL); 5148874Srgrimes cs = MNEXT(cs); 5151590Srgrimes break; 5161590Srgrimes 5171590Srgrimes /* match any number of tabs and spaces */ 5181590Srgrimes case 'd': 5191590Srgrimes ptr = s; 5201590Srgrimes while (*s == ' ' || *s == '\t') 5211590Srgrimes s++; 52236053Sjb if (s != ptr || s == s_start) { 5231590Srgrimes 5241590Srgrimes /* match, be happy */ 5251590Srgrimes matched = 1; 5268874Srgrimes cs = MNEXT(cs); 5271590Srgrimes } else if (*s == '\n' || *s == '\0') { 5281590Srgrimes 5291590Srgrimes /* match, be happy */ 5301590Srgrimes matched = 1; 5318874Srgrimes cs = MNEXT(cs); 5321590Srgrimes } else if (*cs & ALT) { 5331590Srgrimes 5341590Srgrimes /* try the next part */ 5351590Srgrimes matched = 0; 5361590Srgrimes cs = MNEXT(cs); 5371590Srgrimes } else if (*cs & OPT) { 5381590Srgrimes 5391590Srgrimes /* doesn't matter */ 5401590Srgrimes matched = 1; 5411590Srgrimes cs = MNEXT(cs); 5421590Srgrimes } else 5431590Srgrimes 5441590Srgrimes /* no match, error return */ 5451590Srgrimes return (NIL); 5461590Srgrimes break; 5471590Srgrimes 5481590Srgrimes /* check for end of line */ 5491590Srgrimes case '$': 5501590Srgrimes if (*s == '\0' || *s == '\n') { 5511590Srgrimes 5521590Srgrimes /* match, be happy */ 5531590Srgrimes s++; 5541590Srgrimes matched = 1; 5551590Srgrimes cs = MNEXT(cs); 5561590Srgrimes } else if (*cs & ALT) { 5571590Srgrimes 5581590Srgrimes /* try the next part */ 5591590Srgrimes matched = 0; 5601590Srgrimes cs = MNEXT(cs); 5611590Srgrimes } else if (*cs & OPT) { 5621590Srgrimes 5631590Srgrimes /* doesn't matter */ 5641590Srgrimes matched = 1; 5651590Srgrimes cs = MNEXT(cs); 5661590Srgrimes } else 5671590Srgrimes 5681590Srgrimes /* no match, error return */ 5691590Srgrimes return (NIL); 5701590Srgrimes break; 5711590Srgrimes 5721590Srgrimes /* check for start of line */ 5731590Srgrimes case '^': 57436053Sjb if (s == s_start) { 5751590Srgrimes 5761590Srgrimes /* match, be happy */ 5771590Srgrimes matched = 1; 5781590Srgrimes cs = MNEXT(cs); 5791590Srgrimes } else if (*cs & ALT) { 5801590Srgrimes 5811590Srgrimes /* try the next part */ 5821590Srgrimes matched = 0; 5831590Srgrimes cs = MNEXT(cs); 5841590Srgrimes } else if (*cs & OPT) { 5851590Srgrimes 5861590Srgrimes /* doesn't matter */ 5871590Srgrimes matched = 1; 5881590Srgrimes cs = MNEXT(cs); 5891590Srgrimes } else 5901590Srgrimes 5911590Srgrimes /* no match, error return */ 5921590Srgrimes return (NIL); 5931590Srgrimes break; 5941590Srgrimes 5951590Srgrimes /* end of a subexpression, return success */ 5961590Srgrimes case ')': 5971590Srgrimes return (s); 5981590Srgrimes } 5991590Srgrimes break; 6001590Srgrimes } 6011590Srgrimes } 6021590Srgrimes return (s); 6031590Srgrimes} 604