engine.c
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:28k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994 Henry Spencer.
  3.  * Copyright (c) 1992, 1993, 1994
  4.  * The Regents of the University of California.  All rights reserved.
  5.  *
  6.  * This code is derived from software contributed to Berkeley by
  7.  * Henry Spencer.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  * This product includes software developed by the University of
  20.  * California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  *
  37.  * @(#)engine.c 8.5 (Berkeley) 3/20/94
  38.  */
  39. /*
  40.  * The matching engine and friends.  This file is #included by regexec.c
  41.  * after suitable #defines of a variety of macros used herein, so that
  42.  * different state representations can be used without duplicating masses
  43.  * of code.
  44.  */
  45. #ifdef SNAMES
  46. #define matcher smatcher
  47. #define fast sfast
  48. #define slow sslow
  49. #define dissect sdissect
  50. #define backref sbackref
  51. #define step sstep
  52. #define print sprint
  53. #define at sat
  54. #define match smat
  55. #endif
  56. #ifdef LNAMES
  57. #define matcher lmatcher
  58. #define fast lfast
  59. #define slow lslow
  60. #define dissect ldissect
  61. #define backref lbackref
  62. #define step lstep
  63. #define print lprint
  64. #define at lat
  65. #define match lmat
  66. #endif
  67. /* another structure passed up and down to avoid zillions of parameters */
  68. struct match {
  69. struct re_guts *g;
  70. int eflags;
  71. regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
  72. char *offp; /* offsets work from here */
  73. char *beginp; /* start of string -- virtual NUL precedes */
  74. char *endp; /* end of string -- virtual NUL here */
  75. char *coldp; /* can be no match starting before here */
  76. char **lastpos; /* [nplus+1] */
  77. STATEVARS;
  78. states st; /* current states */
  79. states fresh; /* states for a fresh start */
  80. states tmp; /* temporary */
  81. states empty; /* empty set of states */
  82. };
  83. /* ========= begin header generated by ./mkh ========= */
  84. #ifdef __cplusplus
  85. extern "C" {
  86. #endif
  87. /* === engine.c === */
  88. static int matcher (struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
  89. static char *dissect (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
  90. static char *backref (struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev);
  91. static char *fast (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
  92. static char *slow (struct match *m, char *start, char *stop, sopno startst, sopno stopst);
  93. static states step (struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft);
  94. #define BOL (OUT+1)
  95. #define EOL (BOL+1)
  96. #define BOLEOL (BOL+2)
  97. #define NOTHING (BOL+3)
  98. #define BOW (BOL+4)
  99. #define EOW (BOL+5)
  100. #define CODEMAX (BOL+5) /* highest code used */
  101. #define NONCHAR(c) ((c) > CHAR_MAX)
  102. #define NNONCHAR (CODEMAX-CHAR_MAX)
  103. #ifdef REDEBUG
  104. static void print (struct match *m, char *caption, states st, int ch, FILE *d);
  105. #endif
  106. #ifdef REDEBUG
  107. static void at (struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst);
  108. #endif
  109. #ifdef REDEBUG
  110. static char *pchar (int ch);
  111. #endif
  112. #ifdef __cplusplus
  113. }
  114. #endif
  115. /* ========= end header generated by ./mkh ========= */
  116. #ifdef REDEBUG
  117. #define SP(t, s, c) print(m, t, s, c, stdout)
  118. #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
  119. #define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%sn", (str)); }
  120. #else
  121. #define SP(t, s, c) /* nothing */
  122. #define AT(t, p1, p2, s1, s2) /* nothing */
  123. #define NOTE(s) /* nothing */
  124. #endif
  125. /*
  126.  - matcher - the actual matching engine
  127.  == static int matcher(register struct re_guts *g, char *string, 
  128.  == size_t nmatch, regmatch_t pmatch[], int eflags);
  129.  */
  130. static int /* 0 success, REG_NOMATCH failure */
  131. matcher(g, string, nmatch, pmatch, eflags)
  132. register struct re_guts *g;
  133. char *string;
  134. size_t nmatch;
  135. regmatch_t pmatch[];
  136. int eflags;
  137. {
  138. register char *endp;
  139. register int i;
  140. struct match mv;
  141. register struct match *m = &mv;
  142. register char *dp;
  143. const register sopno gf = g->firststate+1; /* +1 for OEND */
  144. const register sopno gl = g->laststate;
  145. char *start;
  146. char *stop;
  147. /* simplify the situation where possible */
  148. if (g->cflags&REG_NOSUB)
  149. nmatch = 0;
  150. if (eflags&REG_STARTEND) {
  151. start = string + pmatch[0].rm_so;
  152. stop = string + pmatch[0].rm_eo;
  153. } else {
  154. start = string;
  155. stop = start + strlen(start);
  156. }
  157. if (stop < start)
  158. return(REG_INVARG);
  159. /* prescreening; this does wonders for this rather slow code */
  160. if (g->must != NULL) {
  161. for (dp = start; dp < stop; dp++)
  162. if (*dp == g->must[0] && stop - dp >= g->mlen &&
  163. memcmp(dp, g->must, (size_t)g->mlen) == 0)
  164. break;
  165. if (dp == stop) /* we didn't find g->must */
  166. return(REG_NOMATCH);
  167. }
  168. /* match struct setup */
  169. m->g = g;
  170. m->eflags = eflags;
  171. m->pmatch = NULL;
  172. m->lastpos = NULL;
  173. m->offp = string;
  174. m->beginp = start;
  175. m->endp = stop;
  176. STATESETUP(m, 4);
  177. SETUP(m->st);
  178. SETUP(m->fresh);
  179. SETUP(m->tmp);
  180. SETUP(m->empty);
  181. CLEAR(m->empty);
  182. /* this loop does only one repetition except for backrefs */
  183. for (;;) {
  184. endp = fast(m, start, stop, gf, gl);
  185. if (endp == NULL) { /* a miss */
  186. STATETEARDOWN(m);
  187. return(REG_NOMATCH);
  188. }
  189. if (nmatch == 0 && !g->backrefs)
  190. break; /* no further info needed */
  191. /* where? */
  192. assert(m->coldp != NULL);
  193. for (;;) {
  194. NOTE("finding start");
  195. endp = slow(m, m->coldp, stop, gf, gl);
  196. if (endp != NULL)
  197. break;
  198. assert(m->coldp < m->endp);
  199. m->coldp++;
  200. }
  201. if (nmatch == 1 && !g->backrefs)
  202. break; /* no further info needed */
  203. /* oh my, he wants the subexpressions... */
  204. if (m->pmatch == NULL)
  205. m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
  206. sizeof(regmatch_t));
  207. if (m->pmatch == NULL) {
  208. STATETEARDOWN(m);
  209. return(REG_ESPACE);
  210. }
  211. for (i = 1; i <= m->g->nsub; i++)
  212. m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
  213. if (!g->backrefs && !(m->eflags&REG_BACKR)) {
  214. NOTE("dissecting");
  215. dp = dissect(m, m->coldp, endp, gf, gl);
  216. } else {
  217. if (g->nplus > 0 && m->lastpos == NULL)
  218. m->lastpos = (char **)malloc((g->nplus+1) *
  219. sizeof(char *));
  220. if (g->nplus > 0 && m->lastpos == NULL) {
  221. free(m->pmatch);
  222. STATETEARDOWN(m);
  223. return(REG_ESPACE);
  224. }
  225. NOTE("backref dissect");
  226. dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
  227. }
  228. if (dp != NULL)
  229. break;
  230. /* uh-oh... we couldn't find a subexpression-level match */
  231. assert(g->backrefs); /* must be back references doing it */
  232. assert(g->nplus == 0 || m->lastpos != NULL);
  233. for (;;) {
  234. if (dp != NULL || endp <= m->coldp)
  235. break; /* defeat */
  236. NOTE("backoff");
  237. endp = slow(m, m->coldp, endp-1, gf, gl);
  238. if (endp == NULL)
  239. break; /* defeat */
  240. /* try it on a shorter possibility */
  241. #ifndef NDEBUG
  242. for (i = 1; i <= m->g->nsub; i++) {
  243. assert(m->pmatch[i].rm_so == -1);
  244. assert(m->pmatch[i].rm_eo == -1);
  245. }
  246. #endif
  247. NOTE("backoff dissect");
  248. dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
  249. }
  250. assert(dp == NULL || dp == endp);
  251. if (dp != NULL) /* found a shorter one */
  252. break;
  253. /* despite initial appearances, there is no match here */
  254. NOTE("false alarm");
  255. start = m->coldp + 1; /* recycle starting later */
  256. assert(start <= stop);
  257. }
  258. /* fill in the details if requested */
  259. if (nmatch > 0) {
  260. pmatch[0].rm_so = m->coldp - m->offp;
  261. pmatch[0].rm_eo = endp - m->offp;
  262. }
  263. if (nmatch > 1) {
  264. assert(m->pmatch != NULL);
  265. for (i = 1; i < nmatch; i++)
  266. if (i <= m->g->nsub)
  267. pmatch[i] = m->pmatch[i];
  268. else {
  269. pmatch[i].rm_so = -1;
  270. pmatch[i].rm_eo = -1;
  271. }
  272. }
  273. if (m->pmatch != NULL)
  274. free((char *)m->pmatch);
  275. if (m->lastpos != NULL)
  276. free((char *)m->lastpos);
  277. STATETEARDOWN(m);
  278. return(0);
  279. }
  280. /*
  281.  - dissect - figure out what matched what, no back references
  282.  == static char *dissect(register struct match *m, char *start, 
  283.  == char *stop, sopno startst, sopno stopst);
  284.  */
  285. static char * /* == stop (success) always */
  286. dissect(m, start, stop, startst, stopst)
  287. register struct match *m;
  288. char *start;
  289. char *stop;
  290. sopno startst;
  291. sopno stopst;
  292. {
  293. register int i;
  294. register sopno ss; /* start sop of current subRE */
  295. register sopno es; /* end sop of current subRE */
  296. register char *sp; /* start of string matched by it */
  297. register char *stp; /* string matched by it cannot pass here */
  298. register char *rest; /* start of rest of string */
  299. register char *tail; /* string unmatched by rest of RE */
  300. register sopno ssub; /* start sop of subsubRE */
  301. register sopno esub; /* end sop of subsubRE */
  302. register char *ssp; /* start of string matched by subsubRE */
  303. register char *sep; /* end of string matched by subsubRE */
  304. register char *oldssp; /* previous ssp */
  305. register char *dp;
  306. AT("diss", start, stop, startst, stopst);
  307. sp = start;
  308. for (ss = startst; ss < stopst; ss = es) {
  309. /* identify end of subRE */
  310. es = ss;
  311. switch (OP(m->g->strip[es])) {
  312. case OPLUS_:
  313. case OQUEST_:
  314. es += OPND(m->g->strip[es]);
  315. break;
  316. case OCH_:
  317. while (OP(m->g->strip[es]) != O_CH)
  318. es += OPND(m->g->strip[es]);
  319. break;
  320. }
  321. es++;
  322. /* figure out what it matched */
  323. switch (OP(m->g->strip[ss])) {
  324. case OEND:
  325. assert(nope);
  326. break;
  327. case OCHAR:
  328. sp++;
  329. break;
  330. case OBOL:
  331. case OEOL:
  332. case OBOW:
  333. case OEOW:
  334. break;
  335. case OANY:
  336. case OANYOF:
  337. sp++;
  338. break;
  339. case OBACK_:
  340. case O_BACK:
  341. assert(nope);
  342. break;
  343. /* cases where length of match is hard to find */
  344. case OQUEST_:
  345. stp = stop;
  346. for (;;) {
  347. /* how long could this one be? */
  348. rest = slow(m, sp, stp, ss, es);
  349. assert(rest != NULL); /* it did match */
  350. /* could the rest match the rest? */
  351. tail = slow(m, rest, stop, es, stopst);
  352. if (tail == stop)
  353. break; /* yes! */
  354. /* no -- try a shorter match for this one */
  355. stp = rest - 1;
  356. assert(stp >= sp); /* it did work */
  357. }
  358. ssub = ss + 1;
  359. esub = es - 1;
  360. /* did innards match? */
  361. if (slow(m, sp, rest, ssub, esub) != NULL) {
  362. dp = dissect(m, sp, rest, ssub, esub);
  363. assert(dp == rest);
  364. } else /* no */
  365. assert(sp == rest);
  366. sp = rest;
  367. break;
  368. case OPLUS_:
  369. stp = stop;
  370. for (;;) {
  371. /* how long could this one be? */
  372. rest = slow(m, sp, stp, ss, es);
  373. assert(rest != NULL); /* it did match */
  374. /* could the rest match the rest? */
  375. tail = slow(m, rest, stop, es, stopst);
  376. if (tail == stop)
  377. break; /* yes! */
  378. /* no -- try a shorter match for this one */
  379. stp = rest - 1;
  380. assert(stp >= sp); /* it did work */
  381. }
  382. ssub = ss + 1;
  383. esub = es - 1;
  384. ssp = sp;
  385. oldssp = ssp;
  386. for (;;) { /* find last match of innards */
  387. sep = slow(m, ssp, rest, ssub, esub);
  388. if (sep == NULL || sep == ssp)
  389. break; /* failed or matched null */
  390. oldssp = ssp; /* on to next try */
  391. ssp = sep;
  392. }
  393. if (sep == NULL) {
  394. /* last successful match */
  395. sep = ssp;
  396. ssp = oldssp;
  397. }
  398. assert(sep == rest); /* must exhaust substring */
  399. assert(slow(m, ssp, sep, ssub, esub) == rest);
  400. dp = dissect(m, ssp, sep, ssub, esub);
  401. assert(dp == sep);
  402. sp = rest;
  403. break;
  404. case OCH_:
  405. stp = stop;
  406. for (;;) {
  407. /* how long could this one be? */
  408. rest = slow(m, sp, stp, ss, es);
  409. assert(rest != NULL); /* it did match */
  410. /* could the rest match the rest? */
  411. tail = slow(m, rest, stop, es, stopst);
  412. if (tail == stop)
  413. break; /* yes! */
  414. /* no -- try a shorter match for this one */
  415. stp = rest - 1;
  416. assert(stp >= sp); /* it did work */
  417. }
  418. ssub = ss + 1;
  419. esub = ss + OPND(m->g->strip[ss]) - 1;
  420. assert(OP(m->g->strip[esub]) == OOR1);
  421. for (;;) { /* find first matching branch */
  422. if (slow(m, sp, rest, ssub, esub) == rest)
  423. break; /* it matched all of it */
  424. /* that one missed, try next one */
  425. assert(OP(m->g->strip[esub]) == OOR1);
  426. esub++;
  427. assert(OP(m->g->strip[esub]) == OOR2);
  428. ssub = esub + 1;
  429. esub += OPND(m->g->strip[esub]);
  430. if (OP(m->g->strip[esub]) == OOR2)
  431. esub--;
  432. else
  433. assert(OP(m->g->strip[esub]) == O_CH);
  434. }
  435. dp = dissect(m, sp, rest, ssub, esub);
  436. assert(dp == rest);
  437. sp = rest;
  438. break;
  439. case O_PLUS:
  440. case O_QUEST:
  441. case OOR1:
  442. case OOR2:
  443. case O_CH:
  444. assert(nope);
  445. break;
  446. case OLPAREN:
  447. i = OPND(m->g->strip[ss]);
  448. assert(0 < i && i <= m->g->nsub);
  449. m->pmatch[i].rm_so = sp - m->offp;
  450. break;
  451. case ORPAREN:
  452. i = OPND(m->g->strip[ss]);
  453. assert(0 < i && i <= m->g->nsub);
  454. m->pmatch[i].rm_eo = sp - m->offp;
  455. break;
  456. default: /* uh oh */
  457. assert(nope);
  458. break;
  459. }
  460. }
  461. assert(sp == stop);
  462. return(sp);
  463. }
  464. /*
  465.  - backref - figure out what matched what, figuring in back references
  466.  == static char *backref(register struct match *m, char *start, 
  467.  == char *stop, sopno startst, sopno stopst, sopno lev);
  468.  */
  469. static char * /* == stop (success) or NULL (failure) */
  470. backref(m, start, stop, startst, stopst, lev)
  471. register struct match *m;
  472. char *start;
  473. char *stop;
  474. sopno startst;
  475. sopno stopst;
  476. sopno lev; /* PLUS nesting level */
  477. {
  478. register int i;
  479. register sopno ss; /* start sop of current subRE */
  480. register char *sp; /* start of string matched by it */
  481. register sopno ssub; /* start sop of subsubRE */
  482. register sopno esub; /* end sop of subsubRE */
  483. register char *ssp; /* start of string matched by subsubRE */
  484. register char *dp;
  485. register size_t len;
  486. register int hard;
  487. register sop s;
  488. register regoff_t offsave;
  489. register cset *cs;
  490. AT("back", start, stop, startst, stopst);
  491. sp = start;
  492. /* get as far as we can with easy stuff */
  493. hard = 0;
  494. for (ss = startst; !hard && ss < stopst; ss++)
  495. switch (OP(s = m->g->strip[ss])) {
  496. case OCHAR:
  497. if (sp == stop || *sp++ != (char)OPND(s))
  498. return(NULL);
  499. break;
  500. case OANY:
  501. if (sp == stop)
  502. return(NULL);
  503. sp++;
  504. break;
  505. case OANYOF:
  506. cs = &m->g->sets[OPND(s)];
  507. if (sp == stop || !CHIN(cs, *sp++))
  508. return(NULL);
  509. break;
  510. case OBOL:
  511. if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
  512. (sp < m->endp && *(sp-1) == 'n' &&
  513. (m->g->cflags&REG_NEWLINE)) )
  514. { /* yes */ }
  515. else
  516. return(NULL);
  517. break;
  518. case OEOL:
  519. if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
  520. (sp < m->endp && *sp == 'n' &&
  521. (m->g->cflags&REG_NEWLINE)) )
  522. { /* yes */ }
  523. else
  524. return(NULL);
  525. break;
  526. case OBOW:
  527. if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
  528. (sp < m->endp && *(sp-1) == 'n' &&
  529. (m->g->cflags&REG_NEWLINE)) ||
  530. (sp > m->beginp &&
  531. !ISWORD(*(sp-1))) ) &&
  532. (sp < m->endp && ISWORD(*sp)) )
  533. { /* yes */ }
  534. else
  535. return(NULL);
  536. break;
  537. case OEOW:
  538. if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
  539. (sp < m->endp && *sp == 'n' &&
  540. (m->g->cflags&REG_NEWLINE)) ||
  541. (sp < m->endp && !ISWORD(*sp)) ) &&
  542. (sp > m->beginp && ISWORD(*(sp-1))) )
  543. { /* yes */ }
  544. else
  545. return(NULL);
  546. break;
  547. case O_QUEST:
  548. break;
  549. case OOR1: /* matches null but needs to skip */
  550. ss++;
  551. s = m->g->strip[ss];
  552. do {
  553. assert(OP(s) == OOR2);
  554. ss += OPND(s);
  555. } while (OP(s = m->g->strip[ss]) != O_CH);
  556. /* note that the ss++ gets us past the O_CH */
  557. break;
  558. default: /* have to make a choice */
  559. hard = 1;
  560. break;
  561. }
  562. if (!hard) { /* that was it! */
  563. if (sp != stop)
  564. return(NULL);
  565. return(sp);
  566. }
  567. ss--; /* adjust for the for's final increment */
  568. /* the hard stuff */
  569. AT("hard", sp, stop, ss, stopst);
  570. s = m->g->strip[ss];
  571. switch (OP(s)) {
  572. case OBACK_: /* the vilest depths */
  573. i = OPND(s);
  574. assert(0 < i && i <= m->g->nsub);
  575. if (m->pmatch[i].rm_eo == -1)
  576. return(NULL);
  577. assert(m->pmatch[i].rm_so != -1);
  578. len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
  579. assert(stop - m->beginp >= len);
  580. if (sp > stop - len)
  581. return(NULL); /* not enough left to match */
  582. ssp = m->offp + m->pmatch[i].rm_so;
  583. if (memcmp(sp, ssp, len) != 0)
  584. return(NULL);
  585. while (m->g->strip[ss] != SOP(O_BACK, i))
  586. ss++;
  587. return(backref(m, sp+len, stop, ss+1, stopst, lev));
  588. case OQUEST_: /* to null or not */
  589. dp = backref(m, sp, stop, ss+1, stopst, lev);
  590. if (dp != NULL)
  591. return(dp); /* not */
  592. return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
  593. case OPLUS_:
  594. assert(m->lastpos != NULL);
  595. assert(lev+1 <= m->g->nplus);
  596. m->lastpos[lev+1] = sp;
  597. return(backref(m, sp, stop, ss+1, stopst, lev+1));
  598. case O_PLUS:
  599. if (sp == m->lastpos[lev]) /* last pass matched null */
  600. return(backref(m, sp, stop, ss+1, stopst, lev-1));
  601. /* try another pass */
  602. m->lastpos[lev] = sp;
  603. dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
  604. if (dp == NULL)
  605. return(backref(m, sp, stop, ss+1, stopst, lev-1));
  606. else
  607. return(dp);
  608. case OCH_: /* find the right one, if any */
  609. ssub = ss + 1;
  610. esub = ss + OPND(s) - 1;
  611. assert(OP(m->g->strip[esub]) == OOR1);
  612. for (;;) { /* find first matching branch */
  613. dp = backref(m, sp, stop, ssub, esub, lev);
  614. if (dp != NULL)
  615. return(dp);
  616. /* that one missed, try next one */
  617. if (OP(m->g->strip[esub]) == O_CH)
  618. return(NULL); /* there is none */
  619. esub++;
  620. assert(OP(m->g->strip[esub]) == OOR2);
  621. ssub = esub + 1;
  622. esub += OPND(m->g->strip[esub]);
  623. if (OP(m->g->strip[esub]) == OOR2)
  624. esub--;
  625. else
  626. assert(OP(m->g->strip[esub]) == O_CH);
  627. }
  628. case OLPAREN: /* must undo assignment if rest fails */
  629. i = OPND(s);
  630. assert(0 < i && i <= m->g->nsub);
  631. offsave = m->pmatch[i].rm_so;
  632. m->pmatch[i].rm_so = sp - m->offp;
  633. dp = backref(m, sp, stop, ss+1, stopst, lev);
  634. if (dp != NULL)
  635. return(dp);
  636. m->pmatch[i].rm_so = offsave;
  637. return(NULL);
  638. case ORPAREN: /* must undo assignment if rest fails */
  639. i = OPND(s);
  640. assert(0 < i && i <= m->g->nsub);
  641. offsave = m->pmatch[i].rm_eo;
  642. m->pmatch[i].rm_eo = sp - m->offp;
  643. dp = backref(m, sp, stop, ss+1, stopst, lev);
  644. if (dp != NULL)
  645. return(dp);
  646. m->pmatch[i].rm_eo = offsave;
  647. return(NULL);
  648. default: /* uh oh */
  649. assert(nope);
  650. break;
  651. }
  652. /* "can't happen" */
  653. assert(nope);
  654. /* NOTREACHED */
  655. return(NULL);
  656. }
  657. /*
  658.  - fast - step through the string at top speed
  659.  == static char *fast(register struct match *m, char *start, 
  660.  == char *stop, sopno startst, sopno stopst);
  661.  */
  662. static char * /* where tentative match ended, or NULL */
  663. fast(m, start, stop, startst, stopst)
  664. register struct match *m;
  665. char *start;
  666. char *stop;
  667. sopno startst;
  668. sopno stopst;
  669. {
  670. register states st = m->st;
  671. register states fresh = m->fresh;
  672. register states tmp = m->tmp;
  673. register char *p = start;
  674. register int c = (start == m->beginp) ? OUT : *(start-1);
  675. register int lastc; /* previous c */
  676. register int flagch;
  677. register int i;
  678. register char *coldp; /* last p after which no match was underway */
  679. CLEAR(st);
  680. SET1(st, startst);
  681. st = step(m->g, startst, stopst, st, NOTHING, st);
  682. ASSIGN(fresh, st);
  683. SP("start", st, *p);
  684. coldp = NULL;
  685. for (;;) {
  686. /* next character */
  687. lastc = c;
  688. c = (p == m->endp) ? OUT : *p;
  689. if (EQ(st, fresh))
  690. coldp = p;
  691. /* is there an EOL and/or BOL between lastc and c? */
  692. flagch = '';
  693. i = 0;
  694. if ( (lastc == 'n' && m->g->cflags&REG_NEWLINE) ||
  695. (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
  696. flagch = BOL;
  697. i = m->g->nbol;
  698. }
  699. if ( (c == 'n' && m->g->cflags&REG_NEWLINE) ||
  700. (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
  701. flagch = (flagch == BOL) ? BOLEOL : EOL;
  702. i += m->g->neol;
  703. }
  704. if (i != 0) {
  705. for (; i > 0; i--)
  706. st = step(m->g, startst, stopst, st, flagch, st);
  707. SP("boleol", st, c);
  708. }
  709. /* how about a word boundary? */
  710. if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
  711. (c != OUT && ISWORD(c)) ) {
  712. flagch = BOW;
  713. }
  714. if ( (lastc != OUT && ISWORD(lastc)) &&
  715. (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
  716. flagch = EOW;
  717. }
  718. if (flagch == BOW || flagch == EOW) {
  719. st = step(m->g, startst, stopst, st, flagch, st);
  720. SP("boweow", st, c);
  721. }
  722. /* are we done? */
  723. if (ISSET(st, stopst) || p == stop)
  724. break; /* NOTE BREAK OUT */
  725. /* no, we must deal with this character */
  726. ASSIGN(tmp, st);
  727. ASSIGN(st, fresh);
  728. assert(c != OUT);
  729. st = step(m->g, startst, stopst, tmp, c, st);
  730. SP("aft", st, c);
  731. assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
  732. p++;
  733. }
  734. assert(coldp != NULL);
  735. m->coldp = coldp;
  736. if (ISSET(st, stopst))
  737. return(p+1);
  738. else
  739. return(NULL);
  740. }
  741. /*
  742.  - slow - step through the string more deliberately
  743.  == static char *slow(register struct match *m, char *start, 
  744.  == char *stop, sopno startst, sopno stopst);
  745.  */
  746. static char * /* where it ended */
  747. slow(m, start, stop, startst, stopst)
  748. register struct match *m;
  749. char *start;
  750. char *stop;
  751. sopno startst;
  752. sopno stopst;
  753. {
  754. register states st = m->st;
  755. register states empty = m->empty;
  756. register states tmp = m->tmp;
  757. register char *p = start;
  758. register int c = (start == m->beginp) ? OUT : *(start-1);
  759. register int lastc; /* previous c */
  760. register int flagch;
  761. register int i;
  762. register char *matchp; /* last p at which a match ended */
  763. AT("slow", start, stop, startst, stopst);
  764. CLEAR(st);
  765. SET1(st, startst);
  766. SP("sstart", st, *p);
  767. st = step(m->g, startst, stopst, st, NOTHING, st);
  768. matchp = NULL;
  769. for (;;) {
  770. /* next character */
  771. lastc = c;
  772. c = (p == m->endp) ? OUT : *p;
  773. /* is there an EOL and/or BOL between lastc and c? */
  774. flagch = '';
  775. i = 0;
  776. if ( (lastc == 'n' && m->g->cflags&REG_NEWLINE) ||
  777. (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
  778. flagch = BOL;
  779. i = m->g->nbol;
  780. }
  781. if ( (c == 'n' && m->g->cflags&REG_NEWLINE) ||
  782. (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
  783. flagch = (flagch == BOL) ? BOLEOL : EOL;
  784. i += m->g->neol;
  785. }
  786. if (i != 0) {
  787. for (; i > 0; i--)
  788. st = step(m->g, startst, stopst, st, flagch, st);
  789. SP("sboleol", st, c);
  790. }
  791. /* how about a word boundary? */
  792. if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
  793. (c != OUT && ISWORD(c)) ) {
  794. flagch = BOW;
  795. }
  796. if ( (lastc != OUT && ISWORD(lastc)) &&
  797. (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
  798. flagch = EOW;
  799. }
  800. if (flagch == BOW || flagch == EOW) {
  801. st = step(m->g, startst, stopst, st, flagch, st);
  802. SP("sboweow", st, c);
  803. }
  804. /* are we done? */
  805. if (ISSET(st, stopst))
  806. matchp = p;
  807. if (EQ(st, empty) || p == stop)
  808. break; /* NOTE BREAK OUT */
  809. /* no, we must deal with this character */
  810. ASSIGN(tmp, st);
  811. ASSIGN(st, empty);
  812. assert(c != OUT);
  813. st = step(m->g, startst, stopst, tmp, c, st);
  814. SP("saft", st, c);
  815. assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
  816. p++;
  817. }
  818. return(matchp);
  819. }
  820. /*
  821.  - step - map set of states reachable before char to set reachable after
  822.  == static states step(register struct re_guts *g, sopno start, sopno stop, 
  823.  == register states bef, int ch, register states aft);
  824.  == #define BOL (OUT+1)
  825.  == #define EOL (BOL+1)
  826.  == #define BOLEOL (BOL+2)
  827.  == #define NOTHING (BOL+3)
  828.  == #define BOW (BOL+4)
  829.  == #define EOW (BOL+5)
  830.  == #define CODEMAX (BOL+5) // highest code used
  831.  == #define NONCHAR(c) ((c) > CHAR_MAX)
  832.  == #define NNONCHAR (CODEMAX-CHAR_MAX)
  833.  */
  834. static states
  835. step(g, start, stop, bef, ch, aft)
  836. register struct re_guts *g;
  837. sopno start; /* start state within strip */
  838. sopno stop; /* state after stop state within strip */
  839. register states bef; /* states reachable before */
  840. int ch; /* character or NONCHAR code */
  841. register states aft; /* states already known reachable after */
  842. {
  843. register cset *cs;
  844. register sop s;
  845. register sopno pc;
  846. register onestate here; /* note, macros know this name */
  847. register sopno look;
  848. register int i;
  849. for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
  850. s = g->strip[pc];
  851. switch (OP(s)) {
  852. case OEND:
  853. assert(pc == stop-1);
  854. break;
  855. case OCHAR:
  856. /* only characters can match */
  857. assert(!NONCHAR(ch) || ch != (char)OPND(s));
  858. if (ch == (char)OPND(s))
  859. FWD(aft, bef, 1);
  860. break;
  861. case OBOL:
  862. if (ch == BOL || ch == BOLEOL)
  863. FWD(aft, bef, 1);
  864. break;
  865. case OEOL:
  866. if (ch == EOL || ch == BOLEOL)
  867. FWD(aft, bef, 1);
  868. break;
  869. case OBOW:
  870. if (ch == BOW)
  871. FWD(aft, bef, 1);
  872. break;
  873. case OEOW:
  874. if (ch == EOW)
  875. FWD(aft, bef, 1);
  876. break;
  877. case OANY:
  878. if (!NONCHAR(ch))
  879. FWD(aft, bef, 1);
  880. break;
  881. case OANYOF:
  882. cs = &g->sets[OPND(s)];
  883. if (!NONCHAR(ch) && CHIN(cs, ch))
  884. FWD(aft, bef, 1);
  885. break;
  886. case OBACK_: /* ignored here */
  887. case O_BACK:
  888. FWD(aft, aft, 1);
  889. break;
  890. case OPLUS_: /* forward, this is just an empty */
  891. FWD(aft, aft, 1);
  892. break;
  893. case O_PLUS: /* both forward and back */
  894. FWD(aft, aft, 1);
  895. i = ISSETBACK(aft, OPND(s));
  896. BACK(aft, aft, OPND(s));
  897. if (!i && ISSETBACK(aft, OPND(s))) {
  898. /* oho, must reconsider loop body */
  899. pc -= OPND(s) + 1;
  900. INIT(here, pc);
  901. }
  902. break;
  903. case OQUEST_: /* two branches, both forward */
  904. FWD(aft, aft, 1);
  905. FWD(aft, aft, OPND(s));
  906. break;
  907. case O_QUEST: /* just an empty */
  908. FWD(aft, aft, 1);
  909. break;
  910. case OLPAREN: /* not significant here */
  911. case ORPAREN:
  912. FWD(aft, aft, 1);
  913. break;
  914. case OCH_: /* mark the first two branches */
  915. FWD(aft, aft, 1);
  916. assert(OP(g->strip[pc+OPND(s)]) == OOR2);
  917. FWD(aft, aft, OPND(s));
  918. break;
  919. case OOR1: /* done a branch, find the O_CH */
  920. if (ISSTATEIN(aft, here)) {
  921. for (look = 1;
  922. OP(s = g->strip[pc+look]) != O_CH;
  923. look += OPND(s))
  924. assert(OP(s) == OOR2);
  925. FWD(aft, aft, look);
  926. }
  927. break;
  928. case OOR2: /* propagate OCH_'s marking */
  929. FWD(aft, aft, 1);
  930. if (OP(g->strip[pc+OPND(s)]) != O_CH) {
  931. assert(OP(g->strip[pc+OPND(s)]) == OOR2);
  932. FWD(aft, aft, OPND(s));
  933. }
  934. break;
  935. case O_CH: /* just empty */
  936. FWD(aft, aft, 1);
  937. break;
  938. default: /* ooooops... */
  939. assert(nope);
  940. break;
  941. }
  942. }
  943. return(aft);
  944. }
  945. #ifdef REDEBUG
  946. /*
  947.  - print - print a set of states
  948.  == #ifdef REDEBUG
  949.  == static void print(struct match *m, char *caption, states st, 
  950.  == int ch, FILE *d);
  951.  == #endif
  952.  */
  953. static void
  954. print(m, caption, st, ch, d)
  955. struct match *m;
  956. char *caption;
  957. states st;
  958. int ch;
  959. FILE *d;
  960. {
  961. register struct re_guts *g = m->g;
  962. register int i;
  963. register int first = 1;
  964. if (!(m->eflags&REG_TRACE))
  965. return;
  966. fprintf(d, "%s", caption);
  967. if (ch != '')
  968. fprintf(d, " %s", pchar(ch));
  969. for (i = 0; i < g->nstates; i++)
  970. if (ISSET(st, i)) {
  971. fprintf(d, "%s%d", (first) ? "t" : ", ", i);
  972. first = 0;
  973. }
  974. fprintf(d, "n");
  975. }
  976. /* 
  977.  - at - print current situation
  978.  == #ifdef REDEBUG
  979.  == static void at(struct match *m, char *title, char *start, char *stop, 
  980.  == sopno startst, sopno stopst);
  981.  == #endif
  982.  */
  983. static void
  984. at(m, title, start, stop, startst, stopst)
  985. struct match *m;
  986. char *title;
  987. char *start;
  988. char *stop;
  989. sopno startst;
  990. sopno stopst;
  991. {
  992. if (!(m->eflags&REG_TRACE))
  993. return;
  994. printf("%s %s-", title, pchar(*start));
  995. printf("%s ", pchar(*stop));
  996. printf("%ld-%ldn", (long)startst, (long)stopst);
  997. }
  998. #ifndef PCHARDONE
  999. #define PCHARDONE /* never again */
  1000. /*
  1001.  - pchar - make a character printable
  1002.  == #ifdef REDEBUG
  1003.  == static char *pchar(int ch);
  1004.  == #endif
  1005.  *
  1006.  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
  1007.  * duplicate here avoids having a debugging-capable regexec.o tied to
  1008.  * a matching debug.o, and this is convenient.  It all disappears in
  1009.  * the non-debug compilation anyway, so it doesn't matter much.
  1010.  */
  1011. static char * /* -> representation */
  1012. pchar(ch)
  1013. int ch;
  1014. {
  1015. static char pbuf[10];
  1016. if (isprint(ch) || ch == ' ')
  1017. snprintf(pbuf, sizeof(pbuf), "%c", ch);
  1018. else
  1019. snprintf(pbuf, sizeof(pbuf), "\%o", ch);
  1020. return(pbuf);
  1021. }
  1022. #endif
  1023. #endif
  1024. #undef matcher
  1025. #undef fast
  1026. #undef slow
  1027. #undef dissect
  1028. #undef backref
  1029. #undef step
  1030. #undef print
  1031. #undef at
  1032. #undef match