1219019Sgabor/* 2219019Sgabor * Copyright (c) 1980, 1993 3219019Sgabor * The Regents of the University of California. All rights reserved. 4219019Sgabor * 5219019Sgabor * 6219019Sgabor * Redistribution and use in source and binary forms, with or without 7219019Sgabor * modification, are permitted provided that the following conditions 8219019Sgabor * are met: 9219019Sgabor * 1. Redistributions of source code must retain the above copyright 10219019Sgabor * notice, this list of conditions and the following disclaimer. 11219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer in the 13219019Sgabor * documentation and/or other materials provided with the distribution. 14219019Sgabor * 4. Neither the name of the University nor the names of its contributors 15219019Sgabor * may be used to endorse or promote products derived from this software 16219019Sgabor * without specific prior written permission. 17219019Sgabor * 18219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28219019Sgabor * SUCH DAMAGE. 29219019Sgabor */ 30219019Sgabor 31219019Sgabor#include <sys/cdefs.h> 32219019Sgabor 33219019Sgabor__FBSDID("$FreeBSD$"); 34219019Sgabor 35219019Sgabor#ifndef lint 36219019Sgaborstatic const char copyright[] = 37219019Sgabor"@(#) Copyright (c) 1980, 1993\n\ 38219019Sgabor The Regents of the University of California. All rights reserved.\n"; 39219019Sgabor#endif 40219019Sgabor 41219019Sgabor#ifndef lint 42219019Sgaborstatic const char sccsid[] = "@(#)regexp.c 8.1 (Berkeley) 6/6/93"; 43219019Sgabor#endif 44219019Sgabor 45219019Sgabor#include <ctype.h> 46219019Sgabor#include <stdlib.h> 47219019Sgabor#include <string.h> 48219019Sgabor 49219019Sgabor#include "extern.h" 50219019Sgabor 51219019Sgabor#define FALSE 0 52219019Sgabor#define TRUE !(FALSE) 53219019Sgabor#define NIL 0 54219019Sgabor 55219019Sgaborstatic void expconv(void); 56219019Sgabor 57219019Sgaborboolean _escaped; /* true if we are currently _escaped */ 58219019Sgaborchar *s_start; /* start of string */ 59219019Sgaborboolean l_onecase; /* true if upper and lower equivalent */ 60219019Sgabor 61219019Sgabor#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) 62219019Sgabor 63219019Sgabor/* STRNCMP - like strncmp except that we convert the 64219019Sgabor * first string to lower case before comparing 65219019Sgabor * if l_onecase is set. 66219019Sgabor */ 67219019Sgabor 68219019Sgaborint 69219019SgaborSTRNCMP(s1, s2, len) 70219019Sgabor register char *s1,*s2; 71219019Sgabor register int len; 72219019Sgabor{ 73219019Sgabor if (l_onecase) { 74219019Sgabor do 75219019Sgabor if (*s2 - makelower(*s1)) 76219019Sgabor return (*s2 - makelower(*s1)); 77219019Sgabor else { 78219019Sgabor s2++; 79219019Sgabor s1++; 80219019Sgabor } 81219019Sgabor while (--len); 82219019Sgabor } else { 83219019Sgabor do 84219019Sgabor if (*s2 - *s1) 85219019Sgabor return (*s2 - *s1); 86219019Sgabor else { 87219019Sgabor s2++; 88219019Sgabor s1++; 89219019Sgabor } 90219019Sgabor while (--len); 91219019Sgabor } 92219019Sgabor return(0); 93219019Sgabor} 94219019Sgabor 95219019Sgabor/* The following routine converts an irregular expression to 96219019Sgabor * internal format. 97219019Sgabor * 98219019Sgabor * Either meta symbols (\a \d or \p) or character strings or 99219019Sgabor * operations ( alternation or perenthesizing ) can be 100219019Sgabor * specified. Each starts with a descriptor byte. The descriptor 101219019Sgabor * byte has STR set for strings, META set for meta symbols 102219019Sgabor * and OPER set for operations. 103219019Sgabor * The descriptor byte can also have the OPT bit set if the object 104219019Sgabor * defined is optional. Also ALT can be set to indicate an alternation. 105219019Sgabor * 106219019Sgabor * For metasymbols the byte following the descriptor byte identities 107219019Sgabor * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For 108219019Sgabor * strings the byte after the descriptor is a character count for 109219019Sgabor * the string: 110219019Sgabor * 111219019Sgabor * meta symbols := descriptor 112219019Sgabor * symbol 113219019Sgabor * 114219019Sgabor * strings := descriptor 115219019Sgabor * character count 116219019Sgabor * the string 117219019Sgabor * 118219019Sgabor * operatins := descriptor 119219019Sgabor * symbol 120219019Sgabor * character count 121219019Sgabor */ 122219019Sgabor 123219019Sgabor/* 124219019Sgabor * handy macros for accessing parts of match blocks 125219019Sgabor */ 126219019Sgabor#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ 127219019Sgabor#define MNEXT(A) (A+2) /* character following a metasymbol block */ 128219019Sgabor 129219019Sgabor#define OSYM(A) (*(A+1)) /* symbol in an operation block */ 130219019Sgabor#define OCNT(A) (*(A+2)) /* character count */ 131219019Sgabor#define ONEXT(A) (A+3) /* next character after the operation */ 132219019Sgabor#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ 133219019Sgabor 134219019Sgabor#define SCNT(A) (*(A+1)) /* byte count of a string */ 135219019Sgabor#define SSTR(A) (A+2) /* address of the string */ 136219019Sgabor#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ 137219019Sgabor 138219019Sgabor/* 139219019Sgabor * bit flags in the descriptor 140219019Sgabor */ 141219019Sgabor#define OPT 1 142219019Sgabor#define STR 2 143219019Sgabor#define META 4 144219019Sgabor#define ALT 8 145219019Sgabor#define OPER 16 146219019Sgabor 147219019Sgaborstatic char *ccre; /* pointer to current position in converted exp*/ 148219019Sgaborstatic char *ure; /* pointer current position in unconverted exp */ 149219019Sgabor 150219019Sgaborchar * 151219019Sgaborconvexp(re) 152219019Sgabor char *re; /* unconverted irregular expression */ 153219019Sgabor{ 154219019Sgabor register char *cre; /* pointer to converted regular expression */ 155219019Sgabor 156219019Sgabor /* allocate room for the converted expression */ 157219019Sgabor if (re == NIL) 158219019Sgabor return (NIL); 159219019Sgabor if (*re == '\0') 160219019Sgabor return (NIL); 161219019Sgabor cre = malloc (4 * strlen(re) + 3); 162219019Sgabor ccre = cre; 163219019Sgabor ure = re; 164219019Sgabor 165219019Sgabor /* start the conversion with a \a */ 166219019Sgabor *cre = META | OPT; 167219019Sgabor MSYM(cre) = 'a'; 168219019Sgabor ccre = MNEXT(cre); 169219019Sgabor 170219019Sgabor /* start the conversion (its recursive) */ 171219019Sgabor expconv (); 172219019Sgabor *ccre = 0; 173219019Sgabor return (cre); 174219019Sgabor} 175219019Sgabor 176219019Sgaborstatic void 177219019Sgaborexpconv() 178219019Sgabor{ 179219019Sgabor register char *cs; /* pointer to current symbol in converted exp */ 180219019Sgabor register char c; /* character being processed */ 181219019Sgabor register char *acs; /* pinter to last alternate */ 182219019Sgabor register int temp; 183219019Sgabor 184219019Sgabor /* let the conversion begin */ 185219019Sgabor acs = NIL; 186219019Sgabor cs = NIL; 187219019Sgabor while (*ure != NIL) { 188219019Sgabor switch (c = *ure++) { 189219019Sgabor 190219019Sgabor case '\\': 191219019Sgabor switch (c = *ure++) { 192219019Sgabor 193219019Sgabor /* escaped characters are just characters */ 194219019Sgabor default: 195219019Sgabor if (cs == NIL || (*cs & STR) == 0) { 196219019Sgabor cs = ccre; 197219019Sgabor *cs = STR; 198219019Sgabor SCNT(cs) = 1; 199219019Sgabor ccre += 2; 200219019Sgabor } else 201219019Sgabor SCNT(cs)++; 202219019Sgabor *ccre++ = c; 203219019Sgabor break; 204219019Sgabor 205219019Sgabor /* normal(?) metacharacters */ 206219019Sgabor case 'a': 207219019Sgabor case 'd': 208219019Sgabor case 'e': 209219019Sgabor case 'p': 210219019Sgabor if (acs != NIL && acs != cs) { 211219019Sgabor do { 212219019Sgabor temp = OCNT(acs); 213219019Sgabor OCNT(acs) = ccre - acs; 214219019Sgabor acs -= temp; 215219019Sgabor } while (temp != 0); 216219019Sgabor acs = NIL; 217219019Sgabor } 218219019Sgabor cs = ccre; 219219019Sgabor *cs = META; 220219019Sgabor MSYM(cs) = c; 221219019Sgabor ccre = MNEXT(cs); 222219019Sgabor break; 223219019Sgabor } 224219019Sgabor break; 225219019Sgabor 226219019Sgabor /* just put the symbol in */ 227219019Sgabor case '^': 228219019Sgabor case '$': 229219019Sgabor if (acs != NIL && acs != cs) { 230219019Sgabor do { 231219019Sgabor temp = OCNT(acs); 232219019Sgabor OCNT(acs) = ccre - acs; 233219019Sgabor acs -= temp; 234219019Sgabor } while (temp != 0); 235219019Sgabor acs = NIL; 236219019Sgabor } 237219019Sgabor cs = ccre; 238219019Sgabor *cs = META; 239219019Sgabor MSYM(cs) = c; 240219019Sgabor ccre = MNEXT(cs); 241219019Sgabor break; 242219019Sgabor 243219019Sgabor /* mark the last match sequence as optional */ 244219019Sgabor case '?': 245219019Sgabor if (cs) 246219019Sgabor *cs = *cs | OPT; 247219019Sgabor break; 248219019Sgabor 249219019Sgabor /* recurse and define a subexpression */ 250219019Sgabor case '(': 251219019Sgabor if (acs != NIL && acs != cs) { 252219019Sgabor do { 253219019Sgabor temp = OCNT(acs); 254219019Sgabor OCNT(acs) = ccre - acs; 255219019Sgabor acs -= temp; 256219019Sgabor } while (temp != 0); 257219019Sgabor acs = NIL; 258219019Sgabor } 259219019Sgabor cs = ccre; 260219019Sgabor *cs = OPER; 261219019Sgabor OSYM(cs) = '('; 262219019Sgabor ccre = ONEXT(cs); 263219019Sgabor expconv (); 264219019Sgabor OCNT(cs) = ccre - cs; /* offset to next symbol */ 265219019Sgabor break; 266219019Sgabor 267219019Sgabor /* return from a recursion */ 268219019Sgabor case ')': 269219019Sgabor if (acs != NIL) { 270219019Sgabor do { 271219019Sgabor temp = OCNT(acs); 272219019Sgabor OCNT(acs) = ccre - acs; 273219019Sgabor acs -= temp; 274219019Sgabor } while (temp != 0); 275219019Sgabor acs = NIL; 276219019Sgabor } 277219019Sgabor cs = ccre; 278219019Sgabor *cs = META; 279219019Sgabor MSYM(cs) = c; 280219019Sgabor ccre = MNEXT(cs); 281219019Sgabor return; 282219019Sgabor 283219019Sgabor /* mark the last match sequence as having an alternate */ 284219019Sgabor /* the third byte will contain an offset to jump over the */ 285219019Sgabor /* alternate match in case the first did not fail */ 286219019Sgabor case '|': 287219019Sgabor if (acs != NIL && acs != cs) 288219019Sgabor OCNT(ccre) = ccre - acs; /* make a back pointer */ 289219019Sgabor else 290219019Sgabor OCNT(ccre) = 0; 291219019Sgabor *cs |= ALT; 292219019Sgabor cs = ccre; 293219019Sgabor *cs = OPER; 294219019Sgabor OSYM(cs) = '|'; 295219019Sgabor ccre = ONEXT(cs); 296219019Sgabor acs = cs; /* remember that the pointer is to be filles */ 297219019Sgabor break; 298219019Sgabor 299219019Sgabor /* if its not a metasymbol just build a scharacter string */ 300219019Sgabor default: 301219019Sgabor if (cs == NIL || (*cs & STR) == 0) { 302219019Sgabor cs = ccre; 303219019Sgabor *cs = STR; 304219019Sgabor SCNT(cs) = 1; 305219019Sgabor ccre = SSTR(cs); 306219019Sgabor } else 307219019Sgabor SCNT(cs)++; 308219019Sgabor *ccre++ = c; 309219019Sgabor break; 310219019Sgabor } 311219019Sgabor } 312219019Sgabor if (acs != NIL) { 313219019Sgabor do { 314219019Sgabor temp = OCNT(acs); 315219019Sgabor OCNT(acs) = ccre - acs; 316219019Sgabor acs -= temp; 317219019Sgabor } while (temp != 0); 318219019Sgabor acs = NIL; 319219019Sgabor } 320219019Sgabor return; 321219019Sgabor} 322219019Sgabor/* end of convertre */ 323219019Sgabor 324219019Sgabor 325219019Sgabor/* 326219019Sgabor * The following routine recognises an irregular expresion 327219019Sgabor * with the following special characters: 328219019Sgabor * 329219019Sgabor * \? - means last match was optional 330219019Sgabor * \a - matches any number of characters 331219019Sgabor * \d - matches any number of spaces and tabs 332219019Sgabor * \p - matches any number of alphanumeric 333219019Sgabor * characters. The 334219019Sgabor * characters matched will be copied into 335219019Sgabor * the area pointed to by 'name'. 336219019Sgabor * \| - alternation 337219019Sgabor * \( \) - grouping used mostly for alternation and 338219019Sgabor * optionality 339219019Sgabor * 340219019Sgabor * The irregular expression must be translated to internal form 341219019Sgabor * prior to calling this routine 342219019Sgabor * 343219019Sgabor * The value returned is the pointer to the first non \a 344219019Sgabor * character matched. 345219019Sgabor */ 346219019Sgabor 347219019Sgaborchar * 348219019Sgaborexpmatch (s, re, mstring) 349219019Sgabor register char *s; /* string to check for a match in */ 350219019Sgabor register char *re; /* a converted irregular expression */ 351219019Sgabor register char *mstring; /* where to put whatever matches a \p */ 352219019Sgabor{ 353219019Sgabor register char *cs; /* the current symbol */ 354219019Sgabor register char *ptr,*s1; /* temporary pointer */ 355219019Sgabor boolean matched; /* a temporary boolean */ 356219019Sgabor 357219019Sgabor /* initial conditions */ 358219019Sgabor if (re == NIL) 359219019Sgabor return (NIL); 360219019Sgabor cs = re; 361219019Sgabor matched = FALSE; 362219019Sgabor 363219019Sgabor /* loop till expression string is exhausted (or at least pretty tired) */ 364219019Sgabor while (*cs) { 365219019Sgabor switch (*cs & (OPER | STR | META)) { 366219019Sgabor 367219019Sgabor /* try to match a string */ 368219019Sgabor case STR: 369219019Sgabor matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); 370219019Sgabor if (matched) { 371219019Sgabor 372219019Sgabor /* hoorah it matches */ 373219019Sgabor s += SCNT(cs); 374219019Sgabor cs = SNEXT(cs); 375219019Sgabor } else if (*cs & ALT) { 376219019Sgabor 377219019Sgabor /* alternation, skip to next expression */ 378219019Sgabor cs = SNEXT(cs); 379219019Sgabor } else if (*cs & OPT) { 380219019Sgabor 381219019Sgabor /* the match is optional */ 382219019Sgabor cs = SNEXT(cs); 383219019Sgabor matched = 1; /* indicate a successful match */ 384219019Sgabor } else { 385219019Sgabor 386219019Sgabor /* no match, error return */ 387219019Sgabor return (NIL); 388219019Sgabor } 389219019Sgabor break; 390219019Sgabor 391219019Sgabor /* an operator, do something fancy */ 392219019Sgabor case OPER: 393219019Sgabor switch (OSYM(cs)) { 394219019Sgabor 395219019Sgabor /* this is an alternation */ 396219019Sgabor case '|': 397219019Sgabor if (matched) 398219019Sgabor 399219019Sgabor /* last thing in the alternation was a match, skip ahead */ 400219019Sgabor cs = OPTR(cs); 401219019Sgabor else 402219019Sgabor 403219019Sgabor /* no match, keep trying */ 404219019Sgabor cs = ONEXT(cs); 405219019Sgabor break; 406219019Sgabor 407219019Sgabor /* this is a grouping, recurse */ 408219019Sgabor case '(': 409219019Sgabor ptr = expmatch (s, ONEXT(cs), mstring); 410219019Sgabor if (ptr != NIL) { 411219019Sgabor 412219019Sgabor /* the subexpression matched */ 413219019Sgabor matched = 1; 414219019Sgabor s = ptr; 415219019Sgabor } else if (*cs & ALT) { 416219019Sgabor 417219019Sgabor /* alternation, skip to next expression */ 418219019Sgabor matched = 0; 419219019Sgabor } else if (*cs & OPT) { 420219019Sgabor 421219019Sgabor /* the match is optional */ 422219019Sgabor matched = 1; /* indicate a successful match */ 423219019Sgabor } else { 424219019Sgabor 425219019Sgabor /* no match, error return */ 426219019Sgabor return (NIL); 427219019Sgabor } 428219019Sgabor cs = OPTR(cs); 429219019Sgabor break; 430219019Sgabor } 431219019Sgabor break; 432219019Sgabor 433219019Sgabor /* try to match a metasymbol */ 434219019Sgabor case META: 435219019Sgabor switch (MSYM(cs)) { 436219019Sgabor 437219019Sgabor /* try to match anything and remember what was matched */ 438219019Sgabor case 'p': 439219019Sgabor /* 440219019Sgabor * This is really the same as trying the match the 441219019Sgabor * remaining parts of the expression to any subset 442219019Sgabor * of the string. 443219019Sgabor */ 444219019Sgabor s1 = s; 445219019Sgabor do { 446219019Sgabor ptr = expmatch (s1, MNEXT(cs), mstring); 447219019Sgabor if (ptr != NIL && s1 != s) { 448219019Sgabor 449219019Sgabor /* we have a match, remember the match */ 450219019Sgabor strncpy (mstring, s, s1 - s); 451219019Sgabor mstring[s1 - s] = '\0'; 452219019Sgabor return (ptr); 453219019Sgabor } else if (ptr != NIL && (*cs & OPT)) { 454219019Sgabor 455219019Sgabor /* it was aoptional so no match is ok */ 456219019Sgabor return (ptr); 457219019Sgabor } else if (ptr != NIL) { 458219019Sgabor 459219019Sgabor /* not optional and we still matched */ 460219019Sgabor return (NIL); 461219019Sgabor } 462219019Sgabor if (!(isalnum(*s1) || *s1 == '_' || 463219019Sgabor /* C++ destructor */ 464219019Sgabor *s1 == '~' || 465219019Sgabor /* C++ scope operator */ 466219019Sgabor (strlen(s1) > 1 && *s1 == ':' && s1[1] == ':' && 467219019Sgabor (s1++, TRUE)))) 468219019Sgabor return (NIL); 469219019Sgabor if (*s1 == '\\') 470219019Sgabor _escaped = _escaped ? FALSE : TRUE; 471219019Sgabor else 472219019Sgabor _escaped = FALSE; 473219019Sgabor } while (*s1++); 474219019Sgabor return (NIL); 475219019Sgabor 476219019Sgabor /* try to match anything */ 477219019Sgabor case 'a': 478219019Sgabor /* 479219019Sgabor * This is really the same as trying the match the 480219019Sgabor * remaining parts of the expression to any subset 481219019Sgabor * of the string. 482219019Sgabor */ 483219019Sgabor s1 = s; 484219019Sgabor do { 485219019Sgabor ptr = expmatch (s1, MNEXT(cs), mstring); 486219019Sgabor if (ptr != NIL && s1 != s) { 487219019Sgabor 488219019Sgabor /* we have a match */ 489219019Sgabor return (ptr); 490219019Sgabor } else if (ptr != NIL && (*cs & OPT)) { 491219019Sgabor 492219019Sgabor /* it was aoptional so no match is ok */ 493219019Sgabor return (ptr); 494219019Sgabor } else if (ptr != NIL) { 495219019Sgabor 496219019Sgabor /* not optional and we still matched */ 497219019Sgabor return (NIL); 498219019Sgabor } 499219019Sgabor if (*s1 == '\\') 500219019Sgabor _escaped = _escaped ? FALSE : TRUE; 501219019Sgabor else 502219019Sgabor _escaped = FALSE; 503219019Sgabor } while (*s1++); 504219019Sgabor return (NIL); 505219019Sgabor 506219019Sgabor /* fail if we are currently _escaped */ 507219019Sgabor case 'e': 508219019Sgabor if (_escaped) 509219019Sgabor return(NIL); 510219019Sgabor cs = MNEXT(cs); 511219019Sgabor break; 512219019Sgabor 513219019Sgabor /* match any number of tabs and spaces */ 514219019Sgabor case 'd': 515219019Sgabor ptr = s; 516219019Sgabor while (*s == ' ' || *s == '\t') 517219019Sgabor s++; 518219019Sgabor if (s != ptr || s == s_start) { 519219019Sgabor 520219019Sgabor /* match, be happy */ 521219019Sgabor matched = 1; 522219019Sgabor cs = MNEXT(cs); 523219019Sgabor } else if (*s == '\n' || *s == '\0') { 524219019Sgabor 525219019Sgabor /* match, be happy */ 526219019Sgabor matched = 1; 527219019Sgabor cs = MNEXT(cs); 528219019Sgabor } else if (*cs & ALT) { 529219019Sgabor 530219019Sgabor /* try the next part */ 531219019Sgabor matched = 0; 532219019Sgabor cs = MNEXT(cs); 533219019Sgabor } else if (*cs & OPT) { 534219019Sgabor 535219019Sgabor /* doesn't matter */ 536219019Sgabor matched = 1; 537219019Sgabor cs = MNEXT(cs); 538219019Sgabor } else 539219019Sgabor 540219019Sgabor /* no match, error return */ 541219019Sgabor return (NIL); 542219019Sgabor break; 543219019Sgabor 544219019Sgabor /* check for end of line */ 545219019Sgabor case '$': 546219019Sgabor if (*s == '\0' || *s == '\n') { 547219019Sgabor 548219019Sgabor /* match, be happy */ 549219019Sgabor s++; 550219019Sgabor matched = 1; 551219019Sgabor cs = MNEXT(cs); 552219019Sgabor } else if (*cs & ALT) { 553219019Sgabor 554219019Sgabor /* try the next part */ 555219019Sgabor matched = 0; 556219019Sgabor cs = MNEXT(cs); 557219019Sgabor } else if (*cs & OPT) { 558219019Sgabor 559219019Sgabor /* doesn't matter */ 560219019Sgabor matched = 1; 561219019Sgabor cs = MNEXT(cs); 562219019Sgabor } else 563219019Sgabor 564219019Sgabor /* no match, error return */ 565219019Sgabor return (NIL); 566219019Sgabor break; 567219019Sgabor 568219019Sgabor /* check for start of line */ 569219019Sgabor case '^': 570219019Sgabor if (s == s_start) { 571219019Sgabor 572219019Sgabor /* match, be happy */ 573219019Sgabor matched = 1; 574219019Sgabor cs = MNEXT(cs); 575219019Sgabor } else if (*cs & ALT) { 576219019Sgabor 577219019Sgabor /* try the next part */ 578219019Sgabor matched = 0; 579219019Sgabor cs = MNEXT(cs); 580219019Sgabor } else if (*cs & OPT) { 581219019Sgabor 582219019Sgabor /* doesn't matter */ 583219019Sgabor matched = 1; 584219019Sgabor cs = MNEXT(cs); 585219019Sgabor } else 586219019Sgabor 587219019Sgabor /* no match, error return */ 588219019Sgabor return (NIL); 589219019Sgabor break; 590219019Sgabor 591219019Sgabor /* end of a subexpression, return success */ 592219019Sgabor case ')': 593219019Sgabor return (s); 594219019Sgabor } 595219019Sgabor break; 596219019Sgabor } 597219019Sgabor } 598219019Sgabor return (s); 599219019Sgabor} 600219019Sgabor