regexp.c revision 19019
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 351590Srgrimes#ifndef lint 361590Srgrimesstatic char copyright[] = 371590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 381590Srgrimes The Regents of the University of California. All rights reserved.\n"; 391590Srgrimes#endif /* not lint */ 401590Srgrimes 411590Srgrimes#ifndef lint 421590Srgrimesstatic char sccsid[] = "@(#)regexp.c 8.1 (Berkeley) 6/6/93"; 431590Srgrimes#endif /* not lint */ 441590Srgrimes 451590Srgrimes#include <ctype.h> 461590Srgrimes#include <stdlib.h> 471590Srgrimes#include <string.h> 481590Srgrimes#include "extern.h" 491590Srgrimes 501590Srgrimes#define FALSE 0 511590Srgrimes#define TRUE !(FALSE) 521590Srgrimes#define NIL 0 531590Srgrimes 541590Srgrimesstatic void expconv __P((void)); 551590Srgrimes 561590Srgrimesboolean _escaped; /* true if we are currently _escaped */ 571590Srgrimeschar *_start; /* start of string */ 581590Srgrimesboolean l_onecase; /* true if upper and lower equivalent */ 591590Srgrimes 601590Srgrimes#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) 611590Srgrimes 621590Srgrimes/* STRNCMP - like strncmp except that we convert the 631590Srgrimes * first string to lower case before comparing 641590Srgrimes * if l_onecase is set. 651590Srgrimes */ 661590Srgrimes 671590Srgrimesint 681590SrgrimesSTRNCMP(s1, s2, len) 691590Srgrimes register char *s1,*s2; 701590Srgrimes register int len; 711590Srgrimes{ 721590Srgrimes if (l_onecase) { 731590Srgrimes do 741590Srgrimes if (*s2 - makelower(*s1)) 751590Srgrimes return (*s2 - makelower(*s1)); 761590Srgrimes else { 771590Srgrimes s2++; 781590Srgrimes s1++; 791590Srgrimes } 801590Srgrimes while (--len); 811590Srgrimes } else { 821590Srgrimes do 831590Srgrimes if (*s2 - *s1) 841590Srgrimes return (*s2 - *s1); 851590Srgrimes else { 861590Srgrimes s2++; 871590Srgrimes s1++; 881590Srgrimes } 891590Srgrimes while (--len); 901590Srgrimes } 911590Srgrimes return(0); 921590Srgrimes} 931590Srgrimes 941590Srgrimes/* The following routine converts an irregular expression to 951590Srgrimes * internal format. 961590Srgrimes * 971590Srgrimes * Either meta symbols (\a \d or \p) or character strings or 981590Srgrimes * operations ( alternation or perenthesizing ) can be 991590Srgrimes * specified. Each starts with a descriptor byte. The descriptor 1001590Srgrimes * byte has STR set for strings, META set for meta symbols 1011590Srgrimes * and OPER set for operations. 1021590Srgrimes * The descriptor byte can also have the OPT bit set if the object 1031590Srgrimes * defined is optional. Also ALT can be set to indicate an alternation. 1041590Srgrimes * 1051590Srgrimes * For metasymbols the byte following the descriptor byte identities 1061590Srgrimes * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For 1071590Srgrimes * strings the byte after the descriptor is a character count for 1081590Srgrimes * the string: 1091590Srgrimes * 1101590Srgrimes * meta symbols := descriptor 1111590Srgrimes * symbol 1121590Srgrimes * 1131590Srgrimes * strings := descriptor 1141590Srgrimes * character count 1151590Srgrimes * the string 1161590Srgrimes * 1171590Srgrimes * operatins := descriptor 1181590Srgrimes * symbol 1191590Srgrimes * character count 1201590Srgrimes */ 1211590Srgrimes 1221590Srgrimes/* 1231590Srgrimes * handy macros for accessing parts of match blocks 1241590Srgrimes */ 1251590Srgrimes#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ 1261590Srgrimes#define MNEXT(A) (A+2) /* character following a metasymbol block */ 1271590Srgrimes 1281590Srgrimes#define OSYM(A) (*(A+1)) /* symbol in an operation block */ 1291590Srgrimes#define OCNT(A) (*(A+2)) /* character count */ 1301590Srgrimes#define ONEXT(A) (A+3) /* next character after the operation */ 1311590Srgrimes#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ 1321590Srgrimes 1331590Srgrimes#define SCNT(A) (*(A+1)) /* byte count of a string */ 1341590Srgrimes#define SSTR(A) (A+2) /* address of the string */ 1351590Srgrimes#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ 1361590Srgrimes 1371590Srgrimes/* 1388874Srgrimes * bit flags in the descriptor 1391590Srgrimes */ 1401590Srgrimes#define OPT 1 1411590Srgrimes#define STR 2 1421590Srgrimes#define META 4 1431590Srgrimes#define ALT 8 1441590Srgrimes#define OPER 16 1451590Srgrimes 1461590Srgrimesstatic char *ccre; /* pointer to current position in converted exp*/ 1471590Srgrimesstatic char *ure; /* pointer current position in unconverted exp */ 1481590Srgrimes 1491590Srgrimeschar * 1501590Srgrimesconvexp(re) 1511590Srgrimes char *re; /* unconverted irregular expression */ 1521590Srgrimes{ 1531590Srgrimes register char *cre; /* pointer to converted regular expression */ 1541590Srgrimes 1551590Srgrimes /* allocate room for the converted expression */ 1561590Srgrimes if (re == NIL) 1571590Srgrimes return (NIL); 1581590Srgrimes if (*re == '\0') 1591590Srgrimes return (NIL); 1601590Srgrimes cre = malloc (4 * strlen(re) + 3); 1611590Srgrimes ccre = cre; 1621590Srgrimes ure = re; 1631590Srgrimes 1641590Srgrimes /* start the conversion with a \a */ 1651590Srgrimes *cre = META | OPT; 1661590Srgrimes MSYM(cre) = 'a'; 1671590Srgrimes ccre = MNEXT(cre); 1681590Srgrimes 1691590Srgrimes /* start the conversion (its recursive) */ 1701590Srgrimes expconv (); 1711590Srgrimes *ccre = 0; 1721590Srgrimes return (cre); 1731590Srgrimes} 1741590Srgrimes 1751590Srgrimesstatic void 1761590Srgrimesexpconv() 1771590Srgrimes{ 1781590Srgrimes register char *cs; /* pointer to current symbol in converted exp */ 1791590Srgrimes register char c; /* character being processed */ 1801590Srgrimes register char *acs; /* pinter to last alternate */ 1811590Srgrimes register int temp; 1821590Srgrimes 1831590Srgrimes /* let the conversion begin */ 1841590Srgrimes acs = NIL; 1851590Srgrimes cs = NIL; 1861590Srgrimes while (*ure != NIL) { 1871590Srgrimes switch (c = *ure++) { 1881590Srgrimes 1891590Srgrimes case '\\': 1901590Srgrimes switch (c = *ure++) { 1911590Srgrimes 1921590Srgrimes /* escaped characters are just characters */ 1931590Srgrimes default: 1941590Srgrimes if (cs == NIL || (*cs & STR) == 0) { 1951590Srgrimes cs = ccre; 1961590Srgrimes *cs = STR; 1971590Srgrimes SCNT(cs) = 1; 1981590Srgrimes ccre += 2; 1998874Srgrimes } else 2001590Srgrimes SCNT(cs)++; 2011590Srgrimes *ccre++ = c; 2021590Srgrimes break; 2031590Srgrimes 2041590Srgrimes /* normal(?) metacharacters */ 2051590Srgrimes case 'a': 2061590Srgrimes case 'd': 2071590Srgrimes case 'e': 2081590Srgrimes case 'p': 2091590Srgrimes if (acs != NIL && acs != cs) { 2101590Srgrimes do { 2111590Srgrimes temp = OCNT(acs); 2128874Srgrimes OCNT(acs) = ccre - acs; 2131590Srgrimes acs -= temp; 2141590Srgrimes } while (temp != 0); 2151590Srgrimes acs = NIL; 2161590Srgrimes } 2171590Srgrimes cs = ccre; 2181590Srgrimes *cs = META; 2191590Srgrimes MSYM(cs) = c; 2201590Srgrimes ccre = MNEXT(cs); 2211590Srgrimes break; 2221590Srgrimes } 2231590Srgrimes break; 2248874Srgrimes 2251590Srgrimes /* just put the symbol in */ 2261590Srgrimes case '^': 2271590Srgrimes case '$': 2281590Srgrimes if (acs != NIL && acs != cs) { 2291590Srgrimes do { 2301590Srgrimes temp = OCNT(acs); 2311590Srgrimes OCNT(acs) = ccre - acs; 2321590Srgrimes acs -= temp; 2331590Srgrimes } while (temp != 0); 2341590Srgrimes acs = NIL; 2351590Srgrimes } 2361590Srgrimes cs = ccre; 2371590Srgrimes *cs = META; 2381590Srgrimes MSYM(cs) = c; 2391590Srgrimes ccre = MNEXT(cs); 2401590Srgrimes break; 2411590Srgrimes 2421590Srgrimes /* mark the last match sequence as optional */ 2431590Srgrimes case '?': 2441590Srgrimes if (cs) 2451590Srgrimes *cs = *cs | OPT; 2461590Srgrimes break; 2471590Srgrimes 2481590Srgrimes /* recurse and define a subexpression */ 2491590Srgrimes case '(': 2501590Srgrimes if (acs != NIL && acs != cs) { 2511590Srgrimes do { 2521590Srgrimes temp = OCNT(acs); 2531590Srgrimes OCNT(acs) = ccre - acs; 2541590Srgrimes acs -= temp; 2551590Srgrimes } while (temp != 0); 2561590Srgrimes acs = NIL; 2571590Srgrimes } 2581590Srgrimes cs = ccre; 2591590Srgrimes *cs = OPER; 2601590Srgrimes OSYM(cs) = '('; 2611590Srgrimes ccre = ONEXT(cs); 2621590Srgrimes expconv (); 2631590Srgrimes OCNT(cs) = ccre - cs; /* offset to next symbol */ 2641590Srgrimes break; 2651590Srgrimes 26619012Sjoerg /* return from a recursion */ 2671590Srgrimes case ')': 2681590Srgrimes if (acs != NIL) { 2691590Srgrimes do { 2701590Srgrimes temp = OCNT(acs); 2711590Srgrimes OCNT(acs) = ccre - acs; 2721590Srgrimes acs -= temp; 2731590Srgrimes } while (temp != 0); 2741590Srgrimes acs = NIL; 2751590Srgrimes } 2761590Srgrimes cs = ccre; 2771590Srgrimes *cs = META; 2781590Srgrimes MSYM(cs) = c; 2791590Srgrimes ccre = MNEXT(cs); 2801590Srgrimes return; 2811590Srgrimes 2821590Srgrimes /* mark the last match sequence as having an alternate */ 2831590Srgrimes /* the third byte will contain an offset to jump over the */ 2841590Srgrimes /* alternate match in case the first did not fail */ 2851590Srgrimes case '|': 2861590Srgrimes if (acs != NIL && acs != cs) 2871590Srgrimes OCNT(ccre) = ccre - acs; /* make a back pointer */ 2881590Srgrimes else 2891590Srgrimes OCNT(ccre) = 0; 2901590Srgrimes *cs |= ALT; 2911590Srgrimes cs = ccre; 2921590Srgrimes *cs = OPER; 2931590Srgrimes OSYM(cs) = '|'; 2941590Srgrimes ccre = ONEXT(cs); 2951590Srgrimes acs = cs; /* remember that the pointer is to be filles */ 2961590Srgrimes break; 2971590Srgrimes 2981590Srgrimes /* if its not a metasymbol just build a scharacter string */ 2991590Srgrimes default: 3001590Srgrimes if (cs == NIL || (*cs & STR) == 0) { 3011590Srgrimes cs = ccre; 3021590Srgrimes *cs = STR; 3031590Srgrimes SCNT(cs) = 1; 3041590Srgrimes ccre = SSTR(cs); 3051590Srgrimes } else 3061590Srgrimes SCNT(cs)++; 3071590Srgrimes *ccre++ = c; 3081590Srgrimes break; 3091590Srgrimes } 3101590Srgrimes } 3111590Srgrimes if (acs != NIL) { 3121590Srgrimes do { 3131590Srgrimes temp = OCNT(acs); 3141590Srgrimes OCNT(acs) = ccre - acs; 3151590Srgrimes acs -= temp; 3161590Srgrimes } while (temp != 0); 3171590Srgrimes acs = NIL; 3181590Srgrimes } 3191590Srgrimes return; 3201590Srgrimes} 3211590Srgrimes/* end of convertre */ 3221590Srgrimes 3231590Srgrimes 3241590Srgrimes/* 3251590Srgrimes * The following routine recognises an irregular expresion 3261590Srgrimes * with the following special characters: 3271590Srgrimes * 3281590Srgrimes * \? - means last match was optional 3291590Srgrimes * \a - matches any number of characters 3301590Srgrimes * \d - matches any number of spaces and tabs 3311590Srgrimes * \p - matches any number of alphanumeric 3321590Srgrimes * characters. The 3331590Srgrimes * characters matched will be copied into 3341590Srgrimes * the area pointed to by 'name'. 3351590Srgrimes * \| - alternation 3361590Srgrimes * \( \) - grouping used mostly for alternation and 3371590Srgrimes * optionality 3381590Srgrimes * 3391590Srgrimes * The irregular expression must be translated to internal form 3401590Srgrimes * prior to calling this routine 3411590Srgrimes * 3428874Srgrimes * The value returned is the pointer to the first non \a 3431590Srgrimes * character matched. 3441590Srgrimes */ 3451590Srgrimes 3461590Srgrimeschar * 3471590Srgrimesexpmatch (s, re, mstring) 3481590Srgrimes register char *s; /* string to check for a match in */ 3491590Srgrimes register char *re; /* a converted irregular expression */ 3501590Srgrimes register char *mstring; /* where to put whatever matches a \p */ 3511590Srgrimes{ 3521590Srgrimes register char *cs; /* the current symbol */ 3531590Srgrimes register char *ptr,*s1; /* temporary pointer */ 3541590Srgrimes boolean matched; /* a temporary boolean */ 3551590Srgrimes 3561590Srgrimes /* initial conditions */ 3571590Srgrimes if (re == NIL) 3581590Srgrimes return (NIL); 3591590Srgrimes cs = re; 3601590Srgrimes matched = FALSE; 3611590Srgrimes 3621590Srgrimes /* loop till expression string is exhausted (or at least pretty tired) */ 3631590Srgrimes while (*cs) { 3641590Srgrimes switch (*cs & (OPER | STR | META)) { 3651590Srgrimes 3661590Srgrimes /* try to match a string */ 3671590Srgrimes case STR: 3681590Srgrimes matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); 3691590Srgrimes if (matched) { 3701590Srgrimes 3711590Srgrimes /* hoorah it matches */ 3721590Srgrimes s += SCNT(cs); 3731590Srgrimes cs = SNEXT(cs); 3741590Srgrimes } else if (*cs & ALT) { 3751590Srgrimes 3761590Srgrimes /* alternation, skip to next expression */ 3771590Srgrimes cs = SNEXT(cs); 3781590Srgrimes } else if (*cs & OPT) { 3791590Srgrimes 3801590Srgrimes /* the match is optional */ 3811590Srgrimes cs = SNEXT(cs); 3821590Srgrimes matched = 1; /* indicate a successful match */ 3831590Srgrimes } else { 3841590Srgrimes 3851590Srgrimes /* no match, error return */ 3861590Srgrimes return (NIL); 3871590Srgrimes } 3881590Srgrimes break; 3891590Srgrimes 3901590Srgrimes /* an operator, do something fancy */ 3911590Srgrimes case OPER: 3921590Srgrimes switch (OSYM(cs)) { 3931590Srgrimes 3941590Srgrimes /* this is an alternation */ 3951590Srgrimes case '|': 3961590Srgrimes if (matched) 3971590Srgrimes 3981590Srgrimes /* last thing in the alternation was a match, skip ahead */ 3991590Srgrimes cs = OPTR(cs); 4001590Srgrimes else 4011590Srgrimes 4021590Srgrimes /* no match, keep trying */ 4031590Srgrimes cs = ONEXT(cs); 4041590Srgrimes break; 4051590Srgrimes 4061590Srgrimes /* this is a grouping, recurse */ 4071590Srgrimes case '(': 4081590Srgrimes ptr = expmatch (s, ONEXT(cs), mstring); 4091590Srgrimes if (ptr != NIL) { 4101590Srgrimes 4111590Srgrimes /* the subexpression matched */ 4121590Srgrimes matched = 1; 4131590Srgrimes s = ptr; 4141590Srgrimes } else if (*cs & ALT) { 4151590Srgrimes 4161590Srgrimes /* alternation, skip to next expression */ 4171590Srgrimes matched = 0; 4181590Srgrimes } else if (*cs & OPT) { 4191590Srgrimes 4201590Srgrimes /* the match is optional */ 4211590Srgrimes matched = 1; /* indicate a successful match */ 4221590Srgrimes } else { 4231590Srgrimes 4241590Srgrimes /* no match, error return */ 4251590Srgrimes return (NIL); 4261590Srgrimes } 4271590Srgrimes cs = OPTR(cs); 4281590Srgrimes break; 4291590Srgrimes } 4301590Srgrimes break; 4311590Srgrimes 4321590Srgrimes /* try to match a metasymbol */ 4331590Srgrimes case META: 4341590Srgrimes switch (MSYM(cs)) { 4351590Srgrimes 4361590Srgrimes /* try to match anything and remember what was matched */ 4371590Srgrimes case 'p': 4381590Srgrimes /* 4391590Srgrimes * This is really the same as trying the match the 4401590Srgrimes * remaining parts of the expression to any subset 4411590Srgrimes * of the string. 4421590Srgrimes */ 4431590Srgrimes s1 = s; 4441590Srgrimes do { 4451590Srgrimes ptr = expmatch (s1, MNEXT(cs), mstring); 4461590Srgrimes if (ptr != NIL && s1 != s) { 4471590Srgrimes 4481590Srgrimes /* we have a match, remember the match */ 4491590Srgrimes strncpy (mstring, s, s1 - s); 4501590Srgrimes mstring[s1 - s] = '\0'; 4511590Srgrimes return (ptr); 4521590Srgrimes } else if (ptr != NIL && (*cs & OPT)) { 4531590Srgrimes 4541590Srgrimes /* it was aoptional so no match is ok */ 4551590Srgrimes return (ptr); 4561590Srgrimes } else if (ptr != NIL) { 4571590Srgrimes 4581590Srgrimes /* not optional and we still matched */ 4591590Srgrimes return (NIL); 4601590Srgrimes } 46119019Sjoerg if (!(isalnum(*s1) || *s1 == '_' || 46219019Sjoerg /* C++ destructor */ 46319019Sjoerg *s1 == '~' || 46419019Sjoerg /* C++ scope operator */ 46519019Sjoerg (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' && 46619019Sjoerg (s1++, TRUE)))) 4671590Srgrimes return (NIL); 4681590Srgrimes if (*s1 == '\\') 4691590Srgrimes _escaped = _escaped ? FALSE : TRUE; 4701590Srgrimes else 4711590Srgrimes _escaped = FALSE; 4721590Srgrimes } while (*s1++); 4731590Srgrimes return (NIL); 4741590Srgrimes 4751590Srgrimes /* try to match anything */ 4761590Srgrimes case 'a': 4771590Srgrimes /* 4781590Srgrimes * This is really the same as trying the match the 4791590Srgrimes * remaining parts of the expression to any subset 4801590Srgrimes * of the string. 4811590Srgrimes */ 4821590Srgrimes s1 = s; 4831590Srgrimes do { 4841590Srgrimes ptr = expmatch (s1, MNEXT(cs), mstring); 4851590Srgrimes if (ptr != NIL && s1 != s) { 4861590Srgrimes 4871590Srgrimes /* we have a match */ 4881590Srgrimes return (ptr); 4891590Srgrimes } else if (ptr != NIL && (*cs & OPT)) { 4901590Srgrimes 4911590Srgrimes /* it was aoptional so no match is ok */ 4921590Srgrimes return (ptr); 4931590Srgrimes } else if (ptr != NIL) { 4941590Srgrimes 4951590Srgrimes /* not optional and we still matched */ 4961590Srgrimes return (NIL); 4971590Srgrimes } 4981590Srgrimes if (*s1 == '\\') 4991590Srgrimes _escaped = _escaped ? FALSE : TRUE; 5001590Srgrimes else 5011590Srgrimes _escaped = FALSE; 5021590Srgrimes } while (*s1++); 5031590Srgrimes return (NIL); 5041590Srgrimes 5051590Srgrimes /* fail if we are currently _escaped */ 5061590Srgrimes case 'e': 5071590Srgrimes if (_escaped) 5081590Srgrimes return(NIL); 5098874Srgrimes cs = MNEXT(cs); 5101590Srgrimes break; 5111590Srgrimes 5121590Srgrimes /* match any number of tabs and spaces */ 5131590Srgrimes case 'd': 5141590Srgrimes ptr = s; 5151590Srgrimes while (*s == ' ' || *s == '\t') 5161590Srgrimes s++; 5171590Srgrimes if (s != ptr || s == _start) { 5181590Srgrimes 5191590Srgrimes /* match, be happy */ 5201590Srgrimes matched = 1; 5218874Srgrimes cs = MNEXT(cs); 5221590Srgrimes } else if (*s == '\n' || *s == '\0') { 5231590Srgrimes 5241590Srgrimes /* match, be happy */ 5251590Srgrimes matched = 1; 5268874Srgrimes cs = MNEXT(cs); 5271590Srgrimes } else if (*cs & ALT) { 5281590Srgrimes 5291590Srgrimes /* try the next part */ 5301590Srgrimes matched = 0; 5311590Srgrimes cs = MNEXT(cs); 5321590Srgrimes } else if (*cs & OPT) { 5331590Srgrimes 5341590Srgrimes /* doesn't matter */ 5351590Srgrimes matched = 1; 5361590Srgrimes cs = MNEXT(cs); 5371590Srgrimes } else 5381590Srgrimes 5391590Srgrimes /* no match, error return */ 5401590Srgrimes return (NIL); 5411590Srgrimes break; 5421590Srgrimes 5431590Srgrimes /* check for end of line */ 5441590Srgrimes case '$': 5451590Srgrimes if (*s == '\0' || *s == '\n') { 5461590Srgrimes 5471590Srgrimes /* match, be happy */ 5481590Srgrimes s++; 5491590Srgrimes matched = 1; 5501590Srgrimes cs = MNEXT(cs); 5511590Srgrimes } else if (*cs & ALT) { 5521590Srgrimes 5531590Srgrimes /* try the next part */ 5541590Srgrimes matched = 0; 5551590Srgrimes cs = MNEXT(cs); 5561590Srgrimes } else if (*cs & OPT) { 5571590Srgrimes 5581590Srgrimes /* doesn't matter */ 5591590Srgrimes matched = 1; 5601590Srgrimes cs = MNEXT(cs); 5611590Srgrimes } else 5621590Srgrimes 5631590Srgrimes /* no match, error return */ 5641590Srgrimes return (NIL); 5651590Srgrimes break; 5661590Srgrimes 5671590Srgrimes /* check for start of line */ 5681590Srgrimes case '^': 5691590Srgrimes if (s == _start) { 5701590Srgrimes 5711590Srgrimes /* match, be happy */ 5721590Srgrimes matched = 1; 5731590Srgrimes cs = MNEXT(cs); 5741590Srgrimes } else if (*cs & ALT) { 5751590Srgrimes 5761590Srgrimes /* try the next part */ 5771590Srgrimes matched = 0; 5781590Srgrimes cs = MNEXT(cs); 5791590Srgrimes } else if (*cs & OPT) { 5801590Srgrimes 5811590Srgrimes /* doesn't matter */ 5821590Srgrimes matched = 1; 5831590Srgrimes cs = MNEXT(cs); 5841590Srgrimes } else 5851590Srgrimes 5861590Srgrimes /* no match, error return */ 5871590Srgrimes return (NIL); 5881590Srgrimes break; 5891590Srgrimes 5901590Srgrimes /* end of a subexpression, return success */ 5911590Srgrimes case ')': 5921590Srgrimes return (s); 5931590Srgrimes } 5941590Srgrimes break; 5951590Srgrimes } 5961590Srgrimes } 5971590Srgrimes return (s); 5981590Srgrimes} 599