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