1254225Speter/* $NetBSD: engine.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */ 2254225Speter 3254225Speter/*- 4254225Speter * Copyright (c) 1992, 1993, 1994 Henry Spencer. 5254225Speter * Copyright (c) 1992, 1993, 1994 6254225Speter * The Regents of the University of California. All rights reserved. 7254225Speter * 8254225Speter * This code is derived from software contributed to Berkeley by 9254225Speter * Henry Spencer of the University of Toronto. 10254225Speter * 11254225Speter * Redistribution and use in source and binary forms, with or without 12254225Speter * modification, are permitted provided that the following conditions 13254225Speter * are met: 14254225Speter * 1. Redistributions of source code must retain the above copyright 15254225Speter * notice, this list of conditions and the following disclaimer. 16254225Speter * 2. Redistributions in binary form must reproduce the above copyright 17254225Speter * notice, this list of conditions and the following disclaimer in the 18254225Speter * documentation and/or other materials provided with the distribution. 19254225Speter * 3. All advertising materials mentioning features or use of this software 20254225Speter * must display the following acknowledgement: 21254225Speter * This product includes software developed by the University of 22254225Speter * California, Berkeley and its contributors. 23254225Speter * 4. Neither the name of the University nor the names of its contributors 24254225Speter * may be used to endorse or promote products derived from this software 25254225Speter * without specific prior written permission. 26254225Speter * 27254225Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28254225Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29254225Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30254225Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31254225Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32254225Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33254225Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34254225Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35254225Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36254225Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37254225Speter * SUCH DAMAGE. 38254225Speter * 39254225Speter * @(#)engine.c 8.4 (Berkeley) 3/19/94 40254225Speter */ 41254225Speter 42254225Speter/* 43254225Speter * The matching engine and friends. This file is #included by regexec.c 44254225Speter * after suitable #defines of a variety of macros used herein, so that 45254225Speter * different state representations can be used without duplicating masses 46254225Speter * of code. 47254225Speter */ 48254225Speter 49254225Speter#ifdef SNAMES 50254225Speter#define matcher smatcher 51254225Speter#define fast sfast 52254225Speter#define slow sslow 53254225Speter#define dissect sdissect 54254225Speter#define backref sbackref 55254225Speter#define step sstep 56254225Speter#define print sprint 57254225Speter#define at sat 58254225Speter#define match smat 59254225Speter#endif 60254225Speter#ifdef LNAMES 61254225Speter#define matcher lmatcher 62254225Speter#define fast lfast 63254225Speter#define slow lslow 64254225Speter#define dissect ldissect 65254225Speter#define backref lbackref 66254225Speter#define step lstep 67254225Speter#define print lprint 68254225Speter#define at lat 69254225Speter#define match lmat 70254225Speter#endif 71254225Speter 72254225Speter/* another structure passed up and down to avoid zillions of parameters */ 73254225Speterstruct match { 74254225Speter struct re_guts *g; 75254225Speter int eflags; 76254225Speter regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ 77254225Speter const RCHAR_T *offp; /* offsets work from here */ 78254225Speter const RCHAR_T *beginp; /* start of string -- virtual NUL precedes */ 79254225Speter const RCHAR_T *endp; /* end of string -- virtual NUL here */ 80254225Speter const RCHAR_T *coldp; /* can be no match starting before here */ 81254225Speter const RCHAR_T **lastpos; /* [nplus+1] */ 82254225Speter STATEVARS; 83254225Speter states st; /* current states */ 84254225Speter states fresh; /* states for a fresh start */ 85254225Speter states tmp; /* temporary */ 86254225Speter states empty; /* empty set of states */ 87254225Speter}; 88254225Speter 89254225Speter/* ========= begin header generated by ./mkh ========= */ 90254225Speter#ifdef __cplusplus 91254225Speterextern "C" { 92254225Speter#endif 93254225Speter 94254225Speter/* === engine.c === */ 95254225Speterstatic int matcher __P((struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags)); 96254225Speterstatic const RCHAR_T *dissect __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst)); 97254225Speterstatic const RCHAR_T *backref __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev)); 98254225Speterstatic const RCHAR_T *fast __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst)); 99254225Speterstatic const RCHAR_T *slow __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst)); 100254225Speterstatic states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft)); 101254225Speter#define BOL (1) 102254225Speter#define EOL (BOL+1) 103254225Speter#define BOLEOL (BOL+2) 104254225Speter#define NOTHING (BOL+3) 105254225Speter#define BOW (BOL+4) 106254225Speter#define EOW (BOL+5) 107254225Speter#ifdef REDEBUG 108254225Speterstatic void print __P((struct match *m, char *caption, states st, int ch, FILE *d)); 109254225Speter#endif 110254225Speter#ifdef REDEBUG 111254225Speterstatic void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst)); 112254225Speter#endif 113254225Speter#ifdef REDEBUG 114254225Speterstatic char *pchar __P((int ch)); 115254225Speter#endif 116254225Speter 117254225Speter#ifdef __cplusplus 118254225Speter} 119254225Speter#endif 120254225Speter/* ========= end header generated by ./mkh ========= */ 121254225Speter 122254225Speter#ifdef REDEBUG 123254225Speter#define SP(t, s, c) print(m, t, s, c, stdout) 124254225Speter#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) 125254225Speter#define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } 126254225Speter#else 127254225Speter#define SP(t, s, c) /* nothing */ 128254225Speter#define AT(t, p1, p2, s1, s2) /* nothing */ 129254225Speter#define NOTE(s) /* nothing */ 130254225Speter#endif 131254225Speter 132254225Speter/* 133254225Speter - matcher - the actual matching engine 134254225Speter == static int matcher(register struct re_guts *g, const RCHAR_T *string, \ 135254225Speter == size_t nmatch, regmatch_t pmatch[], int eflags); 136254225Speter */ 137254225Speterstatic int /* 0 success, REG_NOMATCH failure */ 138254225Spetermatcher(g, string, nmatch, pmatch, eflags) 139254225Speterregister struct re_guts *g; 140254225Speterconst RCHAR_T *string; 141254225Spetersize_t nmatch; 142254225Speterregmatch_t pmatch[]; 143254225Speterint eflags; 144254225Speter{ 145254225Speter register const RCHAR_T *endp; 146254225Speter register size_t i; 147254225Speter struct match mv; 148254225Speter register struct match *m = &mv; 149254225Speter register const RCHAR_T *dp; 150254225Speter register const sopno gf = g->firststate+1; /* +1 for OEND */ 151254225Speter register const sopno gl = g->laststate; 152254225Speter const RCHAR_T *start; 153254225Speter const RCHAR_T *stop; 154254225Speter 155254225Speter /* simplify the situation where possible */ 156254225Speter if (g->cflags®_NOSUB) 157254225Speter nmatch = 0; 158254225Speter if (eflags®_STARTEND) { 159254225Speter start = string + pmatch[0].rm_so; 160254225Speter stop = string + pmatch[0].rm_eo; 161254225Speter } else { 162254225Speter start = string; 163254225Speter stop = start + STRLEN(start); 164254225Speter } 165254225Speter if (stop < start) 166254225Speter return(REG_INVARG); 167254225Speter 168254225Speter /* prescreening; this does wonders for this rather slow code */ 169254225Speter if (g->must != NULL) { 170254225Speter for (dp = start; dp < stop; dp++) 171254225Speter if (*dp == g->must[0] && (size_t)(stop - dp) >= g->mlen && 172254225Speter MEMCMP(dp, g->must, g->mlen) == 0) 173254225Speter break; 174254225Speter if (dp == stop) /* we didn't find g->must */ 175254225Speter return(REG_NOMATCH); 176254225Speter } 177254225Speter 178254225Speter /* match struct setup */ 179254225Speter m->g = g; 180254225Speter m->eflags = eflags; 181254225Speter m->pmatch = NULL; 182254225Speter m->lastpos = NULL; 183254225Speter m->offp = string; 184254225Speter m->beginp = start; 185254225Speter m->endp = stop; 186254225Speter STATESETUP(m, 4); 187254225Speter SETUP(m->st); 188254225Speter SETUP(m->fresh); 189254225Speter SETUP(m->tmp); 190254225Speter SETUP(m->empty); 191254225Speter CLEAR(m->empty); 192254225Speter 193254225Speter /* this loop does only one repetition except for backrefs */ 194254225Speter for (;;) { 195254225Speter endp = fast(m, start, stop, gf, gl); 196254225Speter if (endp == NULL) { /* a miss */ 197254225Speter STATETEARDOWN(m); 198254225Speter return(REG_NOMATCH); 199254225Speter } 200254225Speter if (nmatch == 0 && !g->backrefs) 201254225Speter break; /* no further info needed */ 202254225Speter 203254225Speter /* where? */ 204254225Speter assert(m->coldp != NULL); 205254225Speter for (;;) { 206254225Speter NOTE("finding start"); 207254225Speter endp = slow(m, m->coldp, stop, gf, gl); 208254225Speter if (endp != NULL) 209254225Speter break; 210254225Speter assert(m->coldp < m->endp); 211254225Speter m->coldp++; 212254225Speter } 213254225Speter if (nmatch == 1 && !g->backrefs) 214254225Speter break; /* no further info needed */ 215254225Speter 216254225Speter /* oh my, he wants the subexpressions... */ 217254225Speter if (m->pmatch == NULL) 218254225Speter m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * 219254225Speter sizeof(regmatch_t)); 220254225Speter if (m->pmatch == NULL) { 221254225Speter STATETEARDOWN(m); 222254225Speter return(REG_ESPACE); 223254225Speter } 224254225Speter for (i = 1; i <= m->g->nsub; i++) 225254225Speter m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; 226254225Speter if (!g->backrefs && !(m->eflags®_BACKR)) { 227254225Speter NOTE("dissecting"); 228254225Speter dp = dissect(m, m->coldp, endp, gf, gl); 229254225Speter } else { 230254225Speter if (g->nplus > 0 && m->lastpos == NULL) 231254225Speter m->lastpos = (const RCHAR_T **)malloc((g->nplus+1) * 232254225Speter sizeof(const RCHAR_T *)); 233254225Speter if (g->nplus > 0 && m->lastpos == NULL) { 234254225Speter free(m->pmatch); 235254225Speter STATETEARDOWN(m); 236254225Speter return(REG_ESPACE); 237254225Speter } 238254225Speter NOTE("backref dissect"); 239254225Speter dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 240254225Speter } 241254225Speter if (dp != NULL) 242254225Speter break; 243254225Speter 244254225Speter /* uh-oh... we couldn't find a subexpression-level match */ 245254225Speter assert(g->backrefs); /* must be back references doing it */ 246254225Speter assert(g->nplus == 0 || m->lastpos != NULL); 247254225Speter for (;;) { 248254225Speter if (dp != NULL || endp <= m->coldp) 249254225Speter break; /* defeat */ 250254225Speter NOTE("backoff"); 251254225Speter endp = slow(m, m->coldp, endp-1, gf, gl); 252254225Speter if (endp == NULL) 253254225Speter break; /* defeat */ 254254225Speter /* try it on a shorter possibility */ 255254225Speter#ifndef NDEBUG 256254225Speter for (i = 1; i <= m->g->nsub; i++) { 257254225Speter assert(m->pmatch[i].rm_so == -1); 258254225Speter assert(m->pmatch[i].rm_eo == -1); 259254225Speter } 260254225Speter#endif 261254225Speter NOTE("backoff dissect"); 262254225Speter dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 263254225Speter } 264254225Speter assert(dp == NULL || dp == endp); 265254225Speter if (dp != NULL) /* found a shorter one */ 266254225Speter break; 267254225Speter 268254225Speter /* despite initial appearances, there is no match here */ 269254225Speter NOTE("false alarm"); 270254225Speter start = m->coldp + 1; /* recycle starting later */ 271254225Speter assert(start <= stop); 272254225Speter } 273254225Speter 274254225Speter /* fill in the details if requested */ 275254225Speter if (nmatch > 0) { 276254225Speter pmatch[0].rm_so = m->coldp - m->offp; 277254225Speter pmatch[0].rm_eo = endp - m->offp; 278254225Speter } 279254225Speter if (nmatch > 1) { 280254225Speter assert(m->pmatch != NULL); 281254225Speter for (i = 1; i < nmatch; i++) 282254225Speter if (i <= m->g->nsub) 283254225Speter pmatch[i] = m->pmatch[i]; 284254225Speter else { 285254225Speter pmatch[i].rm_so = -1; 286254225Speter pmatch[i].rm_eo = -1; 287254225Speter } 288254225Speter } 289254225Speter 290254225Speter if (m->pmatch != NULL) 291254225Speter free((char *)m->pmatch); 292254225Speter if (m->lastpos != NULL) 293254225Speter free((char *)m->lastpos); 294254225Speter STATETEARDOWN(m); 295254225Speter return(0); 296254225Speter} 297254225Speter 298254225Speter/* 299254225Speter - dissect - figure out what matched what, no back references 300254225Speter == static const RCHAR_T *dissect(register struct match *m, const RCHAR_T *start, \ 301254225Speter == const RCHAR_T *stop, sopno startst, sopno stopst); 302254225Speter */ 303254225Speterstatic const RCHAR_T * /* == stop (success) always */ 304254225Speterdissect(m, start, stop, startst, stopst) 305254225Speterregister struct match *m; 306254225Speterconst RCHAR_T *start; 307254225Speterconst RCHAR_T *stop; 308254225Spetersopno startst; 309254225Spetersopno stopst; 310254225Speter{ 311254225Speter register int i; 312254225Speter register sopno ss; /* start sop of current subRE */ 313254225Speter register sopno es; /* end sop of current subRE */ 314254225Speter register const RCHAR_T *sp; /* start of string matched by it */ 315254225Speter register const RCHAR_T *stp; /* string matched by it cannot pass here */ 316254225Speter register const RCHAR_T *rest; /* start of rest of string */ 317254225Speter register const RCHAR_T *tail; /* string unmatched by rest of RE */ 318254225Speter register sopno ssub; /* start sop of subsubRE */ 319254225Speter register sopno esub; /* end sop of subsubRE */ 320254225Speter register const RCHAR_T *ssp; /* start of string matched by subsubRE */ 321254225Speter register const RCHAR_T *sep; /* end of string matched by subsubRE */ 322254225Speter register const RCHAR_T *oldssp; /* previous ssp */ 323254225Speter register const RCHAR_T *dp; 324254225Speter 325254225Speter AT("diss", start, stop, startst, stopst); 326254225Speter sp = start; 327254225Speter for (ss = startst; ss < stopst; ss = es) { 328254225Speter /* identify end of subRE */ 329254225Speter es = ss; 330254225Speter switch (m->g->strip[es]) { 331254225Speter case OPLUS_: 332254225Speter case OQUEST_: 333254225Speter es += m->g->stripdata[es]; 334254225Speter break; 335254225Speter case OCH_: 336254225Speter while (m->g->strip[es] != O_CH) 337254225Speter es += m->g->stripdata[es]; 338254225Speter break; 339254225Speter } 340254225Speter es++; 341254225Speter 342254225Speter /* figure out what it matched */ 343254225Speter switch (m->g->strip[ss]) { 344254225Speter case OEND: 345254225Speter assert(nope); 346254225Speter break; 347254225Speter case OCHAR: 348254225Speter sp++; 349254225Speter break; 350254225Speter case OBOL: 351254225Speter case OEOL: 352254225Speter case OBOW: 353254225Speter case OEOW: 354254225Speter break; 355254225Speter case OANY: 356254225Speter case OANYOF: 357254225Speter sp++; 358254225Speter break; 359254225Speter case OBACK_: 360254225Speter case O_BACK: 361254225Speter assert(nope); 362254225Speter break; 363254225Speter /* cases where length of match is hard to find */ 364254225Speter case OQUEST_: 365254225Speter stp = stop; 366254225Speter for (;;) { 367254225Speter /* how long could this one be? */ 368254225Speter rest = slow(m, sp, stp, ss, es); 369254225Speter assert(rest != NULL); /* it did match */ 370254225Speter /* could the rest match the rest? */ 371254225Speter tail = slow(m, rest, stop, es, stopst); 372254225Speter if (tail == stop) 373254225Speter break; /* yes! */ 374254225Speter /* no -- try a shorter match for this one */ 375254225Speter stp = rest - 1; 376254225Speter assert(stp >= sp); /* it did work */ 377254225Speter } 378254225Speter ssub = ss + 1; 379254225Speter esub = es - 1; 380254225Speter /* did innards match? */ 381254225Speter if (slow(m, sp, rest, ssub, esub) != NULL) { 382254225Speter dp = dissect(m, sp, rest, ssub, esub); 383254225Speter assert(dp == rest); 384254225Speter } else /* no */ 385254225Speter assert(sp == rest); 386254225Speter sp = rest; 387254225Speter break; 388254225Speter case OPLUS_: 389254225Speter stp = stop; 390254225Speter for (;;) { 391254225Speter /* how long could this one be? */ 392254225Speter rest = slow(m, sp, stp, ss, es); 393254225Speter assert(rest != NULL); /* it did match */ 394254225Speter /* could the rest match the rest? */ 395254225Speter tail = slow(m, rest, stop, es, stopst); 396254225Speter if (tail == stop) 397254225Speter break; /* yes! */ 398254225Speter /* no -- try a shorter match for this one */ 399254225Speter stp = rest - 1; 400254225Speter assert(stp >= sp); /* it did work */ 401254225Speter } 402254225Speter ssub = ss + 1; 403254225Speter esub = es - 1; 404254225Speter ssp = sp; 405254225Speter oldssp = ssp; 406254225Speter for (;;) { /* find last match of innards */ 407254225Speter sep = slow(m, ssp, rest, ssub, esub); 408254225Speter if (sep == NULL || sep == ssp) 409254225Speter break; /* failed or matched null */ 410254225Speter oldssp = ssp; /* on to next try */ 411254225Speter ssp = sep; 412254225Speter } 413254225Speter if (sep == NULL) { 414254225Speter /* last successful match */ 415254225Speter sep = ssp; 416254225Speter ssp = oldssp; 417254225Speter } 418254225Speter assert(sep == rest); /* must exhaust substring */ 419254225Speter assert(slow(m, ssp, sep, ssub, esub) == rest); 420254225Speter dp = dissect(m, ssp, sep, ssub, esub); 421254225Speter assert(dp == sep); 422254225Speter sp = rest; 423254225Speter break; 424254225Speter case OCH_: 425254225Speter stp = stop; 426254225Speter for (;;) { 427254225Speter /* how long could this one be? */ 428254225Speter rest = slow(m, sp, stp, ss, es); 429254225Speter assert(rest != NULL); /* it did match */ 430254225Speter /* could the rest match the rest? */ 431254225Speter tail = slow(m, rest, stop, es, stopst); 432254225Speter if (tail == stop) 433254225Speter break; /* yes! */ 434254225Speter /* no -- try a shorter match for this one */ 435254225Speter stp = rest - 1; 436254225Speter assert(stp >= sp); /* it did work */ 437254225Speter } 438254225Speter ssub = ss + 1; 439254225Speter esub = ss + m->g->stripdata[ss] - 1; 440254225Speter assert(m->g->strip[esub] == OOR1); 441254225Speter for (;;) { /* find first matching branch */ 442254225Speter if (slow(m, sp, rest, ssub, esub) == rest) 443254225Speter break; /* it matched all of it */ 444254225Speter /* that one missed, try next one */ 445254225Speter assert(m->g->strip[esub] == OOR1); 446254225Speter esub++; 447254225Speter assert(m->g->strip[esub] == OOR2); 448254225Speter ssub = esub + 1; 449254225Speter esub += m->g->stripdata[esub]; 450254225Speter if (m->g->strip[esub] == OOR2) 451254225Speter esub--; 452254225Speter else 453254225Speter assert(m->g->strip[esub] == O_CH); 454254225Speter } 455254225Speter dp = dissect(m, sp, rest, ssub, esub); 456254225Speter assert(dp == rest); 457254225Speter sp = rest; 458254225Speter break; 459254225Speter case O_PLUS: 460254225Speter case O_QUEST: 461254225Speter case OOR1: 462254225Speter case OOR2: 463254225Speter case O_CH: 464254225Speter assert(nope); 465254225Speter break; 466254225Speter case OLPAREN: 467254225Speter i = m->g->stripdata[ss]; 468254225Speter assert(0 < i && i <= m->g->nsub); 469254225Speter m->pmatch[i].rm_so = sp - m->offp; 470254225Speter break; 471254225Speter case ORPAREN: 472254225Speter i = m->g->stripdata[ss]; 473254225Speter assert(0 < i && i <= m->g->nsub); 474254225Speter m->pmatch[i].rm_eo = sp - m->offp; 475254225Speter break; 476254225Speter default: /* uh oh */ 477254225Speter assert(nope); 478254225Speter break; 479254225Speter } 480254225Speter } 481254225Speter 482254225Speter assert(sp == stop); 483254225Speter return(sp); 484254225Speter} 485254225Speter 486254225Speter/* 487254225Speter - backref - figure out what matched what, figuring in back references 488254225Speter == static const RCHAR_T *backref(register struct match *m, const RCHAR_T *start, \ 489254225Speter == const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev); 490254225Speter */ 491254225Speterstatic const RCHAR_T * /* == stop (success) or NULL (failure) */ 492254225Speterbackref(m, start, stop, startst, stopst, lev) 493254225Speterregister struct match *m; 494254225Speterconst RCHAR_T *start; 495254225Speterconst RCHAR_T *stop; 496254225Spetersopno startst; 497254225Spetersopno stopst; 498254225Spetersopno lev; /* PLUS nesting level */ 499254225Speter{ 500254225Speter register int i; 501254225Speter register sopno ss; /* start sop of current subRE */ 502254225Speter register const RCHAR_T *sp; /* start of string matched by it */ 503254225Speter register sopno ssub; /* start sop of subsubRE */ 504254225Speter register sopno esub; /* end sop of subsubRE */ 505254225Speter register const RCHAR_T *ssp; /* start of string matched by subsubRE */ 506254225Speter register const RCHAR_T *dp; 507254225Speter register size_t len; 508254225Speter register int hard; 509254225Speter register sop s; 510254225Speter register RCHAR_T d; 511254225Speter register regoff_t offsave; 512254225Speter register cset *cs; 513254225Speter 514254225Speter AT("back", start, stop, startst, stopst); 515254225Speter sp = start; 516254225Speter 517254225Speter /* get as far as we can with easy stuff */ 518254225Speter hard = 0; 519254225Speter for (ss = startst; !hard && ss < stopst; ss++) { 520254225Speter s = m->g->strip[ss]; 521254225Speter d = m->g->stripdata[ss]; 522254225Speter switch (s) { 523254225Speter case OCHAR: 524254225Speter if (sp == stop || *sp++ != d) 525254225Speter return(NULL); 526254225Speter break; 527254225Speter case OANY: 528254225Speter if (sp == stop) 529254225Speter return(NULL); 530254225Speter sp++; 531254225Speter break; 532254225Speter case OANYOF: 533254225Speter cs = &m->g->sets[d]; 534254225Speter if (sp == stop || !CHIN(cs, *sp++)) 535254225Speter return(NULL); 536254225Speter break; 537254225Speter case OBOL: 538254225Speter if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 539254225Speter (sp < m->endp && *(sp-1) == '\n' && 540254225Speter (m->g->cflags®_NEWLINE)) ) 541254225Speter { /* yes */ } 542254225Speter else 543254225Speter return(NULL); 544254225Speter break; 545254225Speter case OEOL: 546254225Speter if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || 547254225Speter (sp < m->endp && *sp == '\n' && 548254225Speter (m->g->cflags®_NEWLINE)) ) 549254225Speter { /* yes */ } 550254225Speter else 551254225Speter return(NULL); 552254225Speter break; 553254225Speter case OBOW: 554254225Speter if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 555254225Speter (sp < m->endp && *(sp-1) == '\n' && 556254225Speter (m->g->cflags®_NEWLINE)) || 557254225Speter (sp > m->beginp && 558254225Speter !ISWORD(*(sp-1))) ) && 559254225Speter (sp < m->endp && ISWORD(*sp)) ) 560254225Speter { /* yes */ } 561254225Speter else 562254225Speter return(NULL); 563254225Speter break; 564254225Speter case OEOW: 565254225Speter if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || 566254225Speter (sp < m->endp && *sp == '\n' && 567254225Speter (m->g->cflags®_NEWLINE)) || 568254225Speter (sp < m->endp && !ISWORD(*sp)) ) && 569254225Speter (sp > m->beginp && ISWORD(*(sp-1))) ) 570254225Speter { /* yes */ } 571254225Speter else 572254225Speter return(NULL); 573254225Speter break; 574254225Speter case O_QUEST: 575254225Speter break; 576254225Speter case OOR1: /* matches null but needs to skip */ 577254225Speter ss++; 578254225Speter s = m->g->strip[ss]; 579254225Speter d = m->g->stripdata[ss]; 580254225Speter do { 581254225Speter assert(s == OOR2); 582254225Speter ss += d; 583254225Speter s = m->g->strip[ss]; 584254225Speter d = m->g->stripdata[ss]; 585254225Speter } while (s != O_CH); 586254225Speter /* note that the ss++ gets us past the O_CH */ 587254225Speter break; 588254225Speter default: /* have to make a choice */ 589254225Speter hard = 1; 590254225Speter break; 591254225Speter } 592254225Speter } 593254225Speter if (!hard) { /* that was it! */ 594254225Speter if (sp != stop) 595254225Speter return(NULL); 596254225Speter return(sp); 597254225Speter } 598254225Speter ss--; /* adjust for the for's final increment */ 599254225Speter 600254225Speter /* the hard stuff */ 601254225Speter AT("hard", sp, stop, ss, stopst); 602254225Speter s = m->g->strip[ss]; 603254225Speter d = m->g->stripdata[ss]; 604254225Speter switch (s) { 605254225Speter case OBACK_: /* the vilest depths */ 606254225Speter i = d; 607254225Speter assert(0 < i && i <= m->g->nsub); 608254225Speter if (m->pmatch[i].rm_eo == -1) 609254225Speter return(NULL); 610254225Speter assert(m->pmatch[i].rm_so != -1); 611254225Speter len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; 612254225Speter assert(stop - m->beginp >= len); 613254225Speter if (sp > stop - len) 614254225Speter return(NULL); /* not enough left to match */ 615254225Speter ssp = m->offp + m->pmatch[i].rm_so; 616254225Speter if (memcmp(sp, ssp, len) != 0) 617254225Speter return(NULL); 618254225Speter while (m->g->strip[ss] != O_BACK || m->g->stripdata[ss] != i) 619254225Speter ss++; 620254225Speter return(backref(m, sp+len, stop, ss+1, stopst, lev)); 621254225Speter break; 622254225Speter case OQUEST_: /* to null or not */ 623254225Speter dp = backref(m, sp, stop, ss+1, stopst, lev); 624254225Speter if (dp != NULL) 625254225Speter return(dp); /* not */ 626254225Speter return(backref(m, sp, stop, ss+d+1, stopst, lev)); 627254225Speter break; 628254225Speter case OPLUS_: 629254225Speter assert(m->lastpos != NULL); 630254225Speter assert(lev+1 <= m->g->nplus); 631254225Speter m->lastpos[lev+1] = sp; 632254225Speter return(backref(m, sp, stop, ss+1, stopst, lev+1)); 633254225Speter break; 634254225Speter case O_PLUS: 635254225Speter if (sp == m->lastpos[lev]) /* last pass matched null */ 636254225Speter return(backref(m, sp, stop, ss+1, stopst, lev-1)); 637254225Speter /* try another pass */ 638254225Speter m->lastpos[lev] = sp; 639254225Speter dp = backref(m, sp, stop, ss-d+1, stopst, lev); 640254225Speter if (dp == NULL) 641254225Speter return(backref(m, sp, stop, ss+1, stopst, lev-1)); 642254225Speter else 643254225Speter return(dp); 644254225Speter break; 645254225Speter case OCH_: /* find the right one, if any */ 646254225Speter ssub = ss + 1; 647254225Speter esub = ss + d - 1; 648254225Speter assert(m->g->strip[esub] == OOR1); 649254225Speter for (;;) { /* find first matching branch */ 650254225Speter dp = backref(m, sp, stop, ssub, esub, lev); 651254225Speter if (dp != NULL) 652254225Speter return(dp); 653254225Speter /* that one missed, try next one */ 654254225Speter if (m->g->strip[esub] == O_CH) 655254225Speter return(NULL); /* there is none */ 656254225Speter esub++; 657254225Speter assert(m->g->strip[esub] == OOR2); 658254225Speter ssub = esub + 1; 659254225Speter esub += m->g->stripdata[esub]; 660254225Speter if (m->g->strip[esub] == OOR2) 661254225Speter esub--; 662254225Speter else 663254225Speter assert(m->g->strip[esub] == O_CH); 664254225Speter } 665254225Speter break; 666254225Speter case OLPAREN: /* must undo assignment if rest fails */ 667254225Speter i = d; 668254225Speter assert(0 < i && i <= m->g->nsub); 669254225Speter offsave = m->pmatch[i].rm_so; 670254225Speter m->pmatch[i].rm_so = sp - m->offp; 671254225Speter dp = backref(m, sp, stop, ss+1, stopst, lev); 672254225Speter if (dp != NULL) 673254225Speter return(dp); 674254225Speter m->pmatch[i].rm_so = offsave; 675254225Speter return(NULL); 676254225Speter break; 677254225Speter case ORPAREN: /* must undo assignment if rest fails */ 678254225Speter i = d; 679254225Speter assert(0 < i && i <= m->g->nsub); 680254225Speter offsave = m->pmatch[i].rm_eo; 681254225Speter m->pmatch[i].rm_eo = sp - m->offp; 682254225Speter dp = backref(m, sp, stop, ss+1, stopst, lev); 683254225Speter if (dp != NULL) 684254225Speter return(dp); 685254225Speter m->pmatch[i].rm_eo = offsave; 686254225Speter return(NULL); 687254225Speter break; 688254225Speter default: /* uh oh */ 689254225Speter assert(nope); 690254225Speter break; 691254225Speter } 692254225Speter 693254225Speter /* "can't happen" */ 694254225Speter assert(nope); 695254225Speter /* NOTREACHED */ 696254225Speter return NULL; 697254225Speter} 698254225Speter 699254225Speter/* 700254225Speter - fast - step through the string at top speed 701254225Speter == static const RCHAR_T *fast(register struct match *m, const RCHAR_T *start, \ 702254225Speter == const RCHAR_T *stop, sopno startst, sopno stopst); 703254225Speter */ 704254225Speterstatic const RCHAR_T * /* where tentative match ended, or NULL */ 705254225Speterfast(m, start, stop, startst, stopst) 706254225Speterregister struct match *m; 707254225Speterconst RCHAR_T *start; 708254225Speterconst RCHAR_T *stop; 709254225Spetersopno startst; 710254225Spetersopno stopst; 711254225Speter{ 712254225Speter register states st = m->st; 713254225Speter register states fresh = m->fresh; 714254225Speter register states tmp = m->tmp; 715254225Speter register const RCHAR_T *p = start; 716254225Speter register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1); 717254225Speter register RCHAR_T lastc; /* previous c */ 718254225Speter register int flag; 719254225Speter register int i; 720254225Speter register const RCHAR_T *coldp; /* last p after which no match was underway */ 721254225Speter 722254225Speter CLEAR(st); 723254225Speter SET1(st, startst); 724254225Speter st = step(m->g, startst, stopst, st, NOTHING, OUT, st); 725254225Speter ASSIGN(fresh, st); 726254225Speter SP("start", st, *p); 727254225Speter coldp = NULL; 728254225Speter for (;;) { 729254225Speter /* next character */ 730254225Speter lastc = c; 731254225Speter c = (p == m->endp) ? OUT : *p; 732254225Speter if (EQ(st, fresh)) 733254225Speter coldp = p; 734254225Speter 735254225Speter /* is there an EOL and/or BOL between lastc and c? */ 736254225Speter flag = 0; 737254225Speter i = 0; 738254225Speter if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 739254225Speter (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 740254225Speter flag = BOL; 741254225Speter i = m->g->nbol; 742254225Speter } 743254225Speter if ( (c == '\n' && m->g->cflags®_NEWLINE) || 744254225Speter (c == OUT && !(m->eflags®_NOTEOL)) ) { 745254225Speter flag = (flag == BOL) ? BOLEOL : EOL; 746254225Speter i += m->g->neol; 747254225Speter } 748254225Speter if (i != 0) { 749254225Speter for (; i > 0; i--) 750254225Speter st = step(m->g, startst, stopst, st, flag, OUT, st); 751254225Speter SP("boleol", st, c); 752254225Speter } 753254225Speter 754254225Speter /* how about a word boundary? */ 755254225Speter if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) && 756254225Speter (c != OUT && ISWORD(c)) ) { 757254225Speter flag = BOW; 758254225Speter } 759254225Speter if ( (lastc != OUT && ISWORD(lastc)) && 760254225Speter (flag == EOL || (c != OUT && !ISWORD(c))) ) { 761254225Speter flag = EOW; 762254225Speter } 763254225Speter if (flag == BOW || flag == EOW) { 764254225Speter st = step(m->g, startst, stopst, st, flag, OUT, st); 765254225Speter SP("boweow", st, c); 766254225Speter } 767254225Speter 768254225Speter /* are we done? */ 769254225Speter if (ISSET(st, stopst) || p == stop) 770254225Speter break; /* NOTE BREAK OUT */ 771254225Speter 772254225Speter /* no, we must deal with this character */ 773254225Speter ASSIGN(tmp, st); 774254225Speter ASSIGN(st, fresh); 775254225Speter assert(c != OUT); 776254225Speter st = step(m->g, startst, stopst, tmp, 0, c, st); 777254225Speter SP("aft", st, c); 778254225Speter assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st)); 779254225Speter p++; 780254225Speter } 781254225Speter 782254225Speter assert(coldp != NULL); 783254225Speter m->coldp = coldp; 784254225Speter if (ISSET(st, stopst)) 785254225Speter return(p+1); 786254225Speter else 787254225Speter return(NULL); 788254225Speter} 789254225Speter 790254225Speter/* 791254225Speter - slow - step through the string more deliberately 792254225Speter == static const RCHAR_T *slow(register struct match *m, const RCHAR_T *start, \ 793254225Speter == const RCHAR_T *stop, sopno startst, sopno stopst); 794254225Speter */ 795254225Speterstatic const RCHAR_T * /* where it ended */ 796254225Speterslow(m, start, stop, startst, stopst) 797254225Speterregister struct match *m; 798254225Speterconst RCHAR_T *start; 799254225Speterconst RCHAR_T *stop; 800254225Spetersopno startst; 801254225Spetersopno stopst; 802254225Speter{ 803254225Speter register states st = m->st; 804254225Speter register states empty = m->empty; 805254225Speter register states tmp = m->tmp; 806254225Speter register const RCHAR_T *p = start; 807254225Speter register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1); 808254225Speter register RCHAR_T lastc; /* previous c */ 809254225Speter register int flag; 810254225Speter register int i; 811254225Speter register const RCHAR_T *matchp; /* last p at which a match ended */ 812254225Speter 813254225Speter AT("slow", start, stop, startst, stopst); 814254225Speter CLEAR(st); 815254225Speter SET1(st, startst); 816254225Speter SP("sstart", st, *p); 817254225Speter st = step(m->g, startst, stopst, st, NOTHING, OUT, st); 818254225Speter matchp = NULL; 819254225Speter for (;;) { 820254225Speter /* next character */ 821254225Speter lastc = c; 822254225Speter c = (p == m->endp) ? OUT : *p; 823254225Speter 824254225Speter /* is there an EOL and/or BOL between lastc and c? */ 825254225Speter flag = 0; 826254225Speter i = 0; 827254225Speter if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 828254225Speter (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 829254225Speter flag = BOL; 830254225Speter i = m->g->nbol; 831254225Speter } 832254225Speter if ( (c == '\n' && m->g->cflags®_NEWLINE) || 833254225Speter (c == OUT && !(m->eflags®_NOTEOL)) ) { 834254225Speter flag = (flag == BOL) ? BOLEOL : EOL; 835254225Speter i += m->g->neol; 836254225Speter } 837254225Speter if (i != 0) { 838254225Speter for (; i > 0; i--) 839254225Speter st = step(m->g, startst, stopst, st, flag, OUT, st); 840254225Speter SP("sboleol", st, c); 841254225Speter } 842254225Speter 843254225Speter /* how about a word boundary? */ 844254225Speter if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) && 845254225Speter (c != OUT && ISWORD(c)) ) { 846254225Speter flag = BOW; 847254225Speter } 848254225Speter if ( (lastc != OUT && ISWORD(lastc)) && 849254225Speter (flag == EOL || (c != OUT && !ISWORD(c))) ) { 850254225Speter flag = EOW; 851254225Speter } 852254225Speter if (flag == BOW || flag == EOW) { 853254225Speter st = step(m->g, startst, stopst, st, flag, OUT, st); 854254225Speter SP("sboweow", st, c); 855254225Speter } 856254225Speter 857254225Speter /* are we done? */ 858254225Speter if (ISSET(st, stopst)) 859254225Speter matchp = p; 860254225Speter if (EQ(st, empty) || p == stop) 861254225Speter break; /* NOTE BREAK OUT */ 862254225Speter 863254225Speter /* no, we must deal with this character */ 864254225Speter ASSIGN(tmp, st); 865254225Speter ASSIGN(st, empty); 866254225Speter assert(c != OUT); 867254225Speter st = step(m->g, startst, stopst, tmp, 0, c, st); 868254225Speter SP("saft", st, c); 869254225Speter assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st)); 870254225Speter p++; 871254225Speter } 872254225Speter 873254225Speter return(matchp); 874254225Speter} 875254225Speter 876254225Speter 877254225Speter/* 878254225Speter - step - map set of states reachable before char to set reachable after 879254225Speter == static states step(register struct re_guts *g, sopno start, sopno stop, \ 880254225Speter == register states bef, int flag, RCHAR_T ch, register states aft); 881254225Speter == #define BOL (1) 882254225Speter == #define EOL (BOL+1) 883254225Speter == #define BOLEOL (BOL+2) 884254225Speter == #define NOTHING (BOL+3) 885254225Speter == #define BOW (BOL+4) 886254225Speter == #define EOW (BOL+5) 887254225Speter */ 888254225Speterstatic states 889254225Speterstep(g, start, stop, bef, flag, ch, aft) 890254225Speterregister struct re_guts *g; 891254225Spetersopno start; /* start state within strip */ 892254225Spetersopno stop; /* state after stop state within strip */ 893254225Speterregister states bef; /* states reachable before */ 894254225Speterint flag; /* NONCHAR flag */ 895254225SpeterRCHAR_T ch; /* character code */ 896254225Speterregister states aft; /* states already known reachable after */ 897254225Speter{ 898254225Speter register cset *cs; 899254225Speter register sop s; 900254225Speter register RCHAR_T d; 901254225Speter register sopno pc; 902254225Speter register onestate here; /* note, macros know this name */ 903254225Speter register sopno look; 904254225Speter register int i; 905254225Speter 906254225Speter for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { 907254225Speter s = g->strip[pc]; 908254225Speter d = g->stripdata[pc]; 909254225Speter switch (s) { 910254225Speter case OEND: 911254225Speter assert(pc == stop-1); 912254225Speter break; 913254225Speter case OCHAR: 914254225Speter /* only characters can match */ 915254225Speter assert(!flag || ch != d); 916254225Speter if (ch == d) 917254225Speter FWD(aft, bef, 1); 918254225Speter break; 919254225Speter case OBOL: 920254225Speter if (flag == BOL || flag == BOLEOL) 921254225Speter FWD(aft, bef, 1); 922254225Speter break; 923254225Speter case OEOL: 924254225Speter if (flag == EOL || flag == BOLEOL) 925254225Speter FWD(aft, bef, 1); 926254225Speter break; 927254225Speter case OBOW: 928254225Speter if (flag == BOW) 929254225Speter FWD(aft, bef, 1); 930254225Speter break; 931254225Speter case OEOW: 932254225Speter if (flag == EOW) 933254225Speter FWD(aft, bef, 1); 934254225Speter break; 935254225Speter case OANY: 936254225Speter if (!flag) 937254225Speter FWD(aft, bef, 1); 938254225Speter break; 939254225Speter case OANYOF: 940254225Speter cs = &g->sets[d]; 941254225Speter if (!flag && CHIN(cs, ch)) 942254225Speter FWD(aft, bef, 1); 943254225Speter break; 944254225Speter case OBACK_: /* ignored here */ 945254225Speter case O_BACK: 946254225Speter FWD(aft, aft, 1); 947254225Speter break; 948254225Speter case OPLUS_: /* forward, this is just an empty */ 949254225Speter FWD(aft, aft, 1); 950254225Speter break; 951254225Speter case O_PLUS: /* both forward and back */ 952254225Speter FWD(aft, aft, 1); 953254225Speter i = ISSETBACK(aft, d); 954254225Speter BACK(aft, aft, d); 955254225Speter if (!i && ISSETBACK(aft, d)) { 956254225Speter /* oho, must reconsider loop body */ 957254225Speter pc -= d + 1; 958254225Speter INIT(here, pc); 959254225Speter } 960254225Speter break; 961254225Speter case OQUEST_: /* two branches, both forward */ 962254225Speter FWD(aft, aft, 1); 963254225Speter FWD(aft, aft, d); 964254225Speter break; 965254225Speter case O_QUEST: /* just an empty */ 966254225Speter FWD(aft, aft, 1); 967254225Speter break; 968254225Speter case OLPAREN: /* not significant here */ 969254225Speter case ORPAREN: 970254225Speter FWD(aft, aft, 1); 971254225Speter break; 972254225Speter case OCH_: /* mark the first two branches */ 973254225Speter FWD(aft, aft, 1); 974254225Speter assert(OP(g->strip[pc+d]) == OOR2); 975254225Speter FWD(aft, aft, d); 976254225Speter break; 977254225Speter case OOR1: /* done a branch, find the O_CH */ 978254225Speter if (ISSTATEIN(aft, here)) { 979254225Speter for (look = 1; /**/; look += d) { 980254225Speter s = g->strip[pc+look]; 981254225Speter d = g->stripdata[pc+look]; 982254225Speter if (s == O_CH) 983254225Speter break; 984254225Speter assert(s == OOR2); 985254225Speter } 986254225Speter FWD(aft, aft, look); 987254225Speter } 988254225Speter break; 989254225Speter case OOR2: /* propagate OCH_'s marking */ 990254225Speter FWD(aft, aft, 1); 991254225Speter if (g->strip[pc+d] != O_CH) { 992254225Speter assert(g->strip[pc+d] == OOR2); 993254225Speter FWD(aft, aft, d); 994254225Speter } 995254225Speter break; 996254225Speter case O_CH: /* just empty */ 997254225Speter FWD(aft, aft, 1); 998254225Speter break; 999254225Speter default: /* ooooops... */ 1000254225Speter assert(nope); 1001254225Speter break; 1002254225Speter } 1003254225Speter } 1004254225Speter 1005254225Speter return(aft); 1006254225Speter} 1007254225Speter 1008254225Speter#ifdef REDEBUG 1009254225Speter/* 1010254225Speter - print - print a set of states 1011254225Speter == #ifdef REDEBUG 1012254225Speter == static void print(struct match *m, char *caption, states st, \ 1013254225Speter == int ch, FILE *d); 1014254225Speter == #endif 1015254225Speter */ 1016254225Speterstatic void 1017254225Speterprint(m, caption, st, ch, d) 1018254225Speterstruct match *m; 1019254225Speterchar *caption; 1020254225Speterstates st; 1021254225Speterint ch; 1022254225SpeterFILE *d; 1023254225Speter{ 1024254225Speter register struct re_guts *g = m->g; 1025254225Speter register int i; 1026254225Speter register int first = 1; 1027254225Speter 1028254225Speter if (!(m->eflags®_TRACE)) 1029254225Speter return; 1030254225Speter 1031254225Speter fprintf(d, "%s", caption); 1032254225Speter if (ch != '\0') 1033254225Speter fprintf(d, " %s", pchar(ch)); 1034254225Speter for (i = 0; i < g->nstates; i++) 1035254225Speter if (ISSET(st, i)) { 1036254225Speter fprintf(d, "%s%d", (first) ? "\t" : ", ", i); 1037254225Speter first = 0; 1038254225Speter } 1039254225Speter fprintf(d, "\n"); 1040254225Speter} 1041254225Speter 1042254225Speter/* 1043254225Speter - at - print current situation 1044254225Speter == #ifdef REDEBUG 1045254225Speter == static void at(struct match *m, char *title, char *start, char *stop, \ 1046254225Speter == sopno startst, sopno stopst); 1047254225Speter == #endif 1048254225Speter */ 1049254225Speterstatic void 1050254225Speterat(m, title, start, stop, startst, stopst) 1051254225Speterstruct match *m; 1052254225Speterchar *title; 1053254225Speterchar *start; 1054254225Speterchar *stop; 1055254225Spetersopno startst; 1056254225Spetersopno stopst; 1057254225Speter{ 1058254225Speter if (!(m->eflags®_TRACE)) 1059254225Speter return; 1060254225Speter 1061254225Speter printf("%s %s-", title, pchar(*start)); 1062254225Speter printf("%s ", pchar(*stop)); 1063254225Speter printf("%ld-%ld\n", (long)startst, (long)stopst); 1064254225Speter} 1065254225Speter 1066254225Speter#ifndef PCHARDONE 1067254225Speter#define PCHARDONE /* never again */ 1068254225Speter/* 1069254225Speter - pchar - make a character printable 1070254225Speter == #ifdef REDEBUG 1071254225Speter == static char *pchar(int ch); 1072254225Speter == #endif 1073254225Speter * 1074254225Speter * Is this identical to regchar() over in debug.c? Well, yes. But a 1075254225Speter * duplicate here avoids having a debugging-capable regexec.o tied to 1076254225Speter * a matching debug.o, and this is convenient. It all disappears in 1077254225Speter * the non-debug compilation anyway, so it doesn't matter much. 1078254225Speter */ 1079254225Speterstatic char * /* -> representation */ 1080254225Speterpchar(ch) 1081254225Speterint ch; 1082254225Speter{ 1083254225Speter static char pbuf[10]; 1084254225Speter 1085254225Speter if (isprint(ch) || ch == ' ') 1086254225Speter snprintf(pbuf, sizeof(pbuf), "%c", ch); 1087254225Speter else 1088254225Speter snprintf(pbuf, sizeof(pbuf), "\\%o", ch); 1089254225Speter return(pbuf); 1090254225Speter} 1091254225Speter#endif 1092254225Speter#endif 1093254225Speter 1094254225Speter#undef matcher 1095254225Speter#undef fast 1096254225Speter#undef slow 1097254225Speter#undef dissect 1098254225Speter#undef backref 1099254225Speter#undef step 1100254225Speter#undef print 1101254225Speter#undef at 1102254225Speter#undef match 1103