home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / jove / part07 / re.c next >
Encoding:
C/C++ Source or Header  |  1987-02-03  |  16.8 KB  |  883 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. /* search package */
  9.  
  10. #include "jove.h"
  11. #include "ctype.h"
  12.  
  13. #define NALTS    16    /* number of alternate search strings */
  14.  
  15. char    searchstr[128],
  16.     compbuf[256],        /* global default compbuf */
  17.     rep_search[128],    /* replace search string */
  18.     rep_str[128],        /* contains replacement string */
  19.     *cur_compb,        /* usually points at compbuf */
  20.     REbuf[LBSIZE],        /* points at line we're scanning */
  21.     *alternates[NALTS];
  22.  
  23. int    REdirection;
  24.  
  25. int    CaseIgnore = 0,
  26.     WrapScan = 0,
  27.     UseRE = 0;
  28.  
  29. private char    CaseEquiv[] = {
  30.     '\000',    '\001',    '\002',    '\003',    '\004',    '\005',    '\006',    '\007',
  31.     '\010',    '\011',    '\012',    '\013',    '\014',    '\015',    '\016',    '\017',
  32.     '\020',    '\021',    '\022',    '\023',    '\024',    '\025',    '\026',    '\027',
  33.     '\030',    '\031',    '\032',    '\033',    '\034',    '\035',    '\036',    '\037',
  34.     '\040',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
  35.     '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
  36.     '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
  37.     '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
  38.     '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
  39.     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
  40.     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
  41.     'X',    'Y',    'Z',    '[',    '\\',    ']',    '^',    '_',
  42.     '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
  43.     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
  44.     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
  45.     'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
  46. };
  47.  
  48. #define cind_cmp(a, b)    (CaseEquiv[a] == CaseEquiv[b])
  49.  
  50. private int    REpeekc;
  51. private char    *REptr;
  52.  
  53. private
  54. REgetc()
  55. {
  56.     int    c;
  57.  
  58.     if ((c = REpeekc) != -1)
  59.         REpeekc = -1;
  60.     else if (*REptr)
  61.         c = *REptr++;
  62.     else
  63.         c = 0;
  64.  
  65.     return c;
  66. }
  67.  
  68. #define STAR     01    /* Match any number of last RE. */
  69. #define AT_BOL    2    /* ^ */
  70. #define AT_EOL    4    /* $ */
  71. #define AT_BOW    6    /* \< */
  72. #define AT_EOW    8    /* \> */
  73. #define OPENP    10    /* \( */
  74. #define CLOSEP    12    /* \) */
  75. #define CURLYB    14    /* \{ */
  76.  
  77. #define NOSTR    14    /* Codes <= NOSTR can't be *'d. */
  78.  
  79. #define ANYC    NOSTR+2        /* . */
  80. #define NORMC    ANYC+2        /* normal character */
  81. #define CINDC    NORMC+2        /* case independent character */
  82. #define ONE_OF    CINDC+2        /* [xxx] */
  83. #define NONE_OF    ONE_OF+2    /* [^xxx] */
  84. #define BACKREF    NONE_OF+2    /* \# */
  85. #define EOP    BACKREF+2    /* end of pattern */
  86.  
  87. #define NPAR    9    /* [1-9] */
  88. private int    nparens;
  89. private char    *comp_p,
  90.         **alt_p,
  91.         **alt_endp;
  92.  
  93. REcompile(pattern, re, into_buf, alt_bufp)
  94. char    *pattern,
  95.     *into_buf,
  96.     **alt_bufp;
  97. {
  98.     REptr = pattern;
  99.     REpeekc = -1;
  100.     comp_p = cur_compb = into_buf;
  101.     alt_p = alt_bufp;
  102.     alt_endp = alt_p + NALTS;
  103.     *alt_p++ = comp_p;
  104.     nparens = 0;
  105.     (void) do_comp(re ? OKAY_RE : NORM);
  106.     *alt_p = 0;
  107. }
  108.  
  109. /* compile the pattern into an internal code */
  110.  
  111. private
  112. do_comp(kind)
  113. {
  114.     char    *last_p,
  115.         *chr_cnt = 0;
  116.     int    parens[NPAR],
  117.         *parenp,
  118.         c,
  119.         ret_code;
  120.  
  121.     parenp = parens;
  122.     last_p = 0;
  123.     ret_code = 1;
  124.  
  125.     while (c = REgetc()) {
  126.         if (comp_p > &cur_compb[(sizeof compbuf) - 4])
  127. toolong:        complain("Search string too long/complex.");
  128.         if (c != '*')
  129.             last_p = comp_p;
  130.  
  131.         if (kind == NORM && index(".[*", c) != 0)
  132.             goto defchar;
  133.         switch (c) {
  134.         case '\\':
  135.             switch (c = REgetc()) {
  136.             case 0:
  137.                 complain("Premature end of pattern.");
  138.  
  139.             case '{':
  140.                 {
  141.                     char    *wcntp;        /* word count */
  142.  
  143.                     *comp_p++ = CURLYB;
  144.                     wcntp = comp_p;
  145.                     *comp_p++ = 0;
  146.                     for (;;) {
  147.                         int    comp_val;
  148.                         char    *comp_len;
  149.  
  150.                         comp_len = comp_p++;
  151.                         comp_val = do_comp(IN_CB);
  152.                         *comp_len = comp_p - comp_len;
  153.                         (*wcntp)++;
  154.                         if (comp_val == 0)
  155.                             break;
  156.                     }
  157.                     break;
  158.                 }
  159.  
  160.             case '}':
  161.                 if (kind != IN_CB)
  162.                     complain("Unexpected \}.");
  163.                 ret_code = 0;
  164.                 goto outahere;
  165.  
  166.             case '(':
  167.                 if (nparens >= NPAR)
  168.                     complain("Too many ('s; max is %d.", NPAR);
  169.                 *comp_p++ = OPENP;
  170.                 *comp_p++ = nparens;
  171.                 *parenp++ = nparens++;
  172.                 break;
  173.  
  174.             case ')':
  175.                 if (parenp == parens)
  176.                     complain("Too many )'s.");
  177.                 *comp_p++ = CLOSEP;
  178.                 *comp_p++ = *--parenp;
  179.                 break;
  180.  
  181.             case '|':
  182.                 if (alt_p >= alt_endp)
  183.                     complain("Too many alternates; max %d.", NALTS);
  184.                 *comp_p++ = EOP;
  185.                 *alt_p++ = comp_p;
  186.                 nparens = 0;
  187.                 break;
  188.  
  189.             case '1':
  190.             case '2':
  191.             case '3':
  192.             case '4':
  193.             case '5':
  194.             case '6':
  195.             case '7':
  196.             case '8':
  197.             case '9':
  198.                 *comp_p++ = BACKREF;
  199.                 *comp_p++ = c - '1';
  200.                 break;
  201.  
  202.             case '<':
  203.                 *comp_p++ = AT_BOW;
  204.                 break;
  205.  
  206.             case '>':
  207.                 *comp_p++ = AT_EOW;
  208.                 break;
  209.  
  210.             default:
  211.                 goto defchar;
  212.             }
  213.             break;
  214.  
  215.         case ',':
  216.             if (kind != IN_CB)
  217.                 goto defchar;
  218.             goto outahere;
  219.  
  220.         case '.':
  221.             *comp_p++ = ANYC;
  222.             break;
  223.  
  224.         case '^':
  225.             if (comp_p == cur_compb || comp_p[-1] == EOP) {
  226.                 *comp_p++ = AT_BOL;
  227.                 break;
  228.             }
  229.             goto defchar;
  230.  
  231.         case '$':
  232.             if ((REpeekc = REgetc()) != 0 && REpeekc != '\\')
  233.                 goto defchar;
  234.             *comp_p++ = AT_EOL;
  235.             break;
  236.  
  237.         case '[':
  238.             {
  239.                 int    chrcnt;
  240.  
  241.                 *comp_p++ = ONE_OF;
  242.             if (comp_p + 16 >= &cur_compb[(sizeof compbuf)])
  243.                 goto toolong;
  244.                 bzero(comp_p, 16);
  245.                 if ((REpeekc = REgetc()) == '^') {
  246.                     *last_p = NONE_OF;
  247.                     /* Get it for real this time. */
  248.                     (void) REgetc();
  249.                 }
  250.                 chrcnt = 1;
  251.                 while ((c = REgetc()) != ']' && c != 0) {
  252.                     if (c == '\\')
  253.                         c = REgetc();
  254.                 else if ((REpeekc = REgetc()) == '-') {
  255.                     int    c2;
  256.  
  257.                     (void) REgetc();     /* reread '-' */
  258.                     c2 = REgetc();
  259.                     while (c < c2) {
  260.                         comp_p[c/8] |= (1 << (c%8));
  261.                         c++;
  262.                     }
  263.                 }
  264.                 comp_p[c/8] |= (1 << (c%8));
  265.                     chrcnt++;
  266.                 }
  267.                 if (c == 0)
  268.                     complain("Missing ].");
  269.                 if (chrcnt == 1)
  270.                     complain("Empty [].");
  271.                 comp_p += 16;
  272.                 break;
  273.             }
  274.  
  275.         case '*':
  276.             if (last_p == 0 || *last_p <= NOSTR)
  277.                 goto defchar;
  278.             if (chr_cnt) {
  279.                 char    lastc = chr_cnt[*chr_cnt];
  280.  
  281.                 comp_p = chr_cnt + *chr_cnt;
  282.                 (*chr_cnt)--;
  283.                 *comp_p++ = chr_cnt[-1] | STAR;
  284.                 *comp_p++ = lastc;
  285.             } else
  286.                 *last_p |= STAR;
  287.             break;
  288.  
  289.         default:
  290. defchar:        if (chr_cnt)
  291.                 (*chr_cnt)++;    /* increment the count */
  292.             else {
  293.                 *comp_p++ = (CaseIgnore) ? CINDC : NORMC;
  294.                 chr_cnt = comp_p++;
  295.                 *chr_cnt = 1;   /* last_p[1] = 1; */
  296.             }
  297.             *comp_p++ = c;
  298.             continue;
  299.         }
  300.         chr_cnt = FALSE;
  301.     }
  302. outahere:
  303.     /* End of pattern, let's do some error checking. */
  304.     if (parenp != parens)
  305.         complain("Unmatched ()'s.");
  306.     if (kind == IN_CB && c == 0)    /* End of pattern with \}. */
  307.         complain("Missing \}.");
  308.     *comp_p++ = EOP;
  309.  
  310.     return ret_code;
  311. }
  312.  
  313. private char    *pstrtlst[NPAR],    /* index into REbuf */
  314.         *pendlst[NPAR],
  315.         *REbolp,
  316.         *locs,
  317.         *loc1,
  318.         *loc2;
  319.  
  320. int    REbom,
  321.     REeom,        /* beginning and end of match */
  322.     REalt_num;    /* if alternatives, which one matched? */
  323.  
  324. private
  325. backref(n, linep)
  326. register char    *linep;
  327. {
  328.     register char    *backsp,
  329.             *backep;
  330.  
  331.     backsp = pstrtlst[n];
  332.     backep = pendlst[n];
  333.     while (*backsp++ == *linep++)
  334.         if (backsp >= backep)
  335.             return 1;
  336.     return 0;
  337. }
  338.  
  339. private
  340. member(comp_p, c, af)
  341. register char    *comp_p;
  342. register int    c,
  343.         af;
  344. {
  345.     if (c == 0)
  346.         return 0;    /* try to match EOL always fails */
  347.     if (comp_p[c/8] & (1 << (c%8)))
  348.         return af;
  349.     return !af;
  350. }
  351.  
  352. private
  353. REmatch(linep, comp_p)
  354. register char    *linep,
  355.         *comp_p;
  356. {
  357.     char    *first_p = linep;
  358.     register int    n;
  359.  
  360.     for (;;) switch (*comp_p++) {
  361.     case NORMC:
  362.         n = *comp_p++;
  363.         while (--n >= 0)
  364.             if (*linep++ != *comp_p++)
  365.                 return 0;
  366.         continue;
  367.  
  368.     case CINDC:    /* case independent comparison */
  369.         n = *comp_p++;
  370.         while (--n >= 0)
  371.             if (!cind_cmp(*linep++, *comp_p++))
  372.                 return 0;
  373.         continue;
  374.  
  375.     case EOP:
  376.         loc2 = linep;
  377.         REeom = (loc2 - REbolp);
  378.         return 1;    /* Success! */
  379.  
  380.     case AT_BOL:
  381.         if (linep == REbolp)
  382.             continue;
  383.         return 0;
  384.  
  385.     case AT_EOL:
  386.         if (*linep == 0)
  387.             continue;
  388.         return 0;
  389.  
  390.     case ANYC:
  391.         if (*linep++ != 0)
  392.             continue;
  393.         return 0;
  394.  
  395.     case AT_BOW:
  396.         if (ismword(*linep) && (linep == REbolp || !ismword(linep[-1])))
  397.             continue;
  398.         return 0;
  399.  
  400.     case AT_EOW:
  401.         if ((*linep == 0 || !ismword(*linep)) &&
  402.             (linep != REbolp && ismword(linep[-1])))
  403.             continue;
  404.         return 0;
  405.  
  406.     case ONE_OF:
  407.     case NONE_OF:
  408.         if (member(comp_p, *linep++, comp_p[-1] == ONE_OF)) {
  409.             comp_p += 16;
  410.             continue;
  411.         }
  412.         return 0;
  413.  
  414.     case OPENP:
  415.         pstrtlst[*comp_p++] = linep;
  416.         continue;
  417.  
  418.     case CLOSEP:
  419.         pendlst[*comp_p++] = linep;
  420.         continue;
  421.  
  422.     case BACKREF:
  423.         if (pstrtlst[n = *comp_p++] == 0) {
  424.             s_mess("\\%d was not specified.", n + 1);
  425.             return 0;
  426.         }
  427.         if (backref(n, linep)) {
  428.             linep += pendlst[n] - pstrtlst[n];
  429.             continue;
  430.         }
  431.         return 0;
  432.  
  433.     case CURLYB:
  434.         {
  435.             int    wcnt,
  436.                 any;
  437.  
  438.             wcnt = *comp_p++;
  439.             any = 0;
  440.  
  441.             while (--wcnt >= 0) {
  442.                 if (any == 0)
  443.                     any = REmatch(linep, comp_p + 1);
  444.                 comp_p += *comp_p;
  445.             }
  446.             if (any == 0)
  447.                 return 0;
  448.             linep = loc2;
  449.             continue;
  450.         }
  451.  
  452.     case ANYC | STAR:
  453.         first_p = linep;
  454.         while (*linep++)
  455.             ;
  456.         goto star;
  457.  
  458.     case NORMC | STAR:
  459.         first_p = linep;
  460.         while (*comp_p == *linep++)
  461.             ;
  462.         comp_p++;
  463.         goto star;
  464.  
  465.     case CINDC | STAR:
  466.         first_p = linep;
  467.         while (cind_cmp(*comp_p, *linep++))
  468.             ;
  469.         comp_p++;
  470.         goto star;
  471.  
  472.     case ONE_OF | STAR:
  473.     case NONE_OF | STAR:
  474.         first_p = linep;
  475.         while (member(comp_p, *linep++, comp_p[-1] == (ONE_OF | STAR)))
  476.             ;
  477.         comp_p += 16;
  478.         goto star;
  479.  
  480.     case BACKREF | STAR:
  481.         first_p = linep;
  482.         n = *comp_p++;
  483.         while (backref(n, linep))
  484.             linep += pendlst[n] - pstrtlst[n];
  485.         while (linep >= first_p) {
  486.             if (REmatch(linep, comp_p))
  487.                 return 1;
  488.             linep -= pendlst[n] - pstrtlst[n];
  489.         }
  490.         continue;
  491.  
  492. star:        do {
  493.             linep--;
  494.             if (linep < locs)
  495.                 break;
  496.             if (REmatch(linep, comp_p))
  497.                 return 1;
  498.         } while (linep > first_p);
  499.         return 0;
  500.  
  501.     default:
  502.         complain("RE error match (%d).", comp_p[-1]);
  503.     }
  504.     /* NOTREACHED. */
  505. }
  506.  
  507. private
  508. REreset()
  509. {
  510.     register int    i;
  511.  
  512.     for (i = 0; i < NPAR; i++)
  513.         pstrtlst[i] = pendlst[i] = 0;
  514. }
  515.  
  516. /* Index LINE at OFFSET, the compiled EXPR, with alternates ALTS.  If
  517.    lbuf_okay is nonzero it's okay to use linebuf if LINE is the current
  518.    line.  This should save lots of time in things like paren matching in
  519.    LISP mode.  Saves all that copying from linebuf to REbuf.  substitute()
  520.    is the guy who calls re_lindex with lbuf_okay as 0, since the substitution
  521.    gets placed in linebuf ... doesn't work too well when the source and
  522.    destination strings are the same.  I hate all these arguments!
  523.  
  524.    This code is cumbersome, repetetive for reasons of efficiency.  Fast
  525.    search is a must as far as I am concerned. */
  526.  
  527. re_lindex(line, offset, expr, alts, lbuf_okay)
  528. Line    *line;
  529. char    *expr,
  530.     **alts;
  531. {
  532.     int    isquick;
  533.     register int    firstc,
  534.             c;
  535.     register char    *resp;
  536.  
  537.     REreset();
  538.     if (lbuf_okay) {
  539.         REbolp = lbptr(line);
  540.         if (offset == -1)
  541.             offset = strlen(REbolp);    /* arg! */
  542.     } else {
  543.         REbolp = ltobuf(line, REbuf);
  544.         if (offset == -1) {    /* Reverse search, find end of line. */
  545.             extern int    Jr_Len;
  546.  
  547.             offset = Jr_Len;    /* Just Read Len. */
  548.         }
  549.     }
  550.     resp = REbolp;
  551.     isquick = ((expr[0] == NORMC || expr[0] == CINDC) &&
  552.            (alternates[1] == 0));
  553.     if (isquick) {
  554.         firstc = expr[2];
  555.         if (expr[0] == CINDC)
  556.             firstc = CaseEquiv[firstc];
  557.     }
  558.     locs = REbolp + offset;
  559.  
  560.     if (REdirection == FORWARD) {
  561.         do {
  562.         char    **altp = alts;
  563.  
  564.         if (isquick) {
  565.             if (expr[0] == NORMC)
  566.                 while ((c = *locs++) != 0 && c != firstc)
  567.                     ;
  568.             else
  569.                 while (((c = *locs++) != 0) &&
  570.                     (CaseEquiv[c] != firstc))
  571.                     ;
  572.             if (*--locs == 0)
  573.                 break;
  574.         }
  575.         REalt_num = 1;
  576.         while (*altp) {
  577.             if (REmatch(locs, *altp++)) {
  578.                 loc1 = locs;
  579.                 REbom = loc1 - REbolp;
  580.                 return 1;
  581.             }
  582.             REalt_num++;
  583.         }
  584.         } while (*locs++);
  585.     } else {
  586.         do {
  587.         char    **altp = alts;
  588.  
  589.         if (isquick) {
  590.             if (expr[0] == NORMC) {
  591.                 while (locs >= REbolp && *locs-- != firstc)
  592.                     ;
  593.                 if (*++locs != firstc)
  594.                     break;
  595.             } else {
  596.                 while (locs >= REbolp && CaseEquiv[*locs--] != firstc)
  597.                     ;
  598.                 if (CaseEquiv[*++locs] != firstc)
  599.                     break;
  600.             }
  601.         }
  602.         REalt_num = 1;
  603.         while (*altp) {
  604.             if (REmatch(locs, *altp++)) {
  605.                 loc1 = locs;
  606.                 REbom = loc1 - REbolp;
  607.                 return 1;
  608.             }
  609.             REalt_num++;
  610.         }
  611.         } while (--locs >= resp);
  612.     }
  613.  
  614.     return 0;
  615. }
  616.  
  617. int    okay_wrap = 0;    /* Do a wrap search ... not when we're
  618.                parsing errors ... */
  619.  
  620. Bufpos *
  621. dosearch(pattern, dir, re)
  622. char    *pattern;
  623. {
  624.     Bufpos    *pos;
  625.  
  626.     if (bobp() && eobp())    /* Can't match!  There's no buffer. */
  627.         return 0;
  628.  
  629.     REcompile(pattern, re, compbuf, alternates);
  630.  
  631.     pos = docompiled(dir, compbuf, alternates);
  632.     return pos;
  633. }
  634.  
  635. Bufpos *
  636. docompiled(dir, expr, alts)
  637. char    *expr,
  638.     **alts;
  639. {
  640.     static Bufpos    ret;
  641.     register Line    *lp;
  642.     register int    offset;
  643.     int    we_wrapped = 0;
  644.  
  645.     lsave();
  646.     /* Search now lsave()'s so it doesn't make any assumptions on
  647.        whether the the contents of curline/curchar are in linebuf.
  648.        Nowhere does search write all over linebuf.  However, we have to
  649.        be careful about what calls we make here, because many of them
  650.        assume (and rightly so) that curline is in linebuf. */
  651.  
  652.     REdirection = dir;
  653.     lp = curline;
  654.     offset = curchar;
  655.     if (dir == BACKWARD) {
  656.         if (bobp()) {
  657.             if (okay_wrap && WrapScan)
  658.                 goto doit;
  659.             return 0;
  660.         }
  661.         /* here we simulate BackChar() */
  662.         if (bolp()) {
  663.             lp = lp->l_prev;
  664.             offset = strlen(lbptr(lp));
  665.         } else
  666.             --offset;
  667.     } else if ((dir == FORWARD) &&
  668.            (lbptr(lp)[offset] == '\0') &&
  669.            !lastp(lp)) {
  670.         lp = lp->l_next;
  671.         offset = 0;
  672.     }
  673.  
  674.     do {
  675.         if (re_lindex(lp, offset, expr, alts, YES))
  676.             break;
  677. doit:        lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
  678.         if (lp == 0) {
  679.             if (okay_wrap && WrapScan) {
  680.                 lp = (dir == FORWARD) ?
  681.                      curbuf->b_first : curbuf->b_last;
  682.                 we_wrapped++;
  683.             } else
  684.                  break;
  685.         }
  686.         if (dir == FORWARD)
  687.             offset = 0;
  688.         else
  689.             offset = -1;    /* signals re_lindex ... */
  690.     } while (lp != curline);
  691.  
  692.     if (lp == curline && we_wrapped)
  693.         lp = 0;
  694.     if (lp == 0)
  695.         return 0;
  696.     ret.p_line = lp;
  697.     ret.p_char = (dir == FORWARD) ? REeom : REbom;
  698.     return &ret;
  699. }
  700.  
  701. private char *
  702. insert(off, endp, which)
  703. char    *off,
  704.     *endp;
  705. {
  706.     register char    *pp;
  707.     register int    n;
  708.  
  709.     n = pendlst[which] - pstrtlst[which];
  710.     pp = pstrtlst[which];
  711.     while (--n >= 0) {
  712.         *off++ = *pp++;
  713.         if (off >= endp)
  714.             len_error(ERROR);
  715.     }
  716.     return off;
  717. }
  718.  
  719. /* Perform the substitution.  If DELP is nonzero the matched string is
  720.    deleted, i.e., the substitution string is not inserted. */
  721.  
  722. re_dosub(tobuf, delp)
  723. char    *tobuf;
  724. {
  725.     register char    *tp,
  726.             *rp,
  727.             *repp;
  728.     int    c;
  729.     char    *endp;
  730.  
  731.     tp = tobuf;
  732.     endp = tp + LBSIZE;
  733.     rp = REbuf;
  734.     repp = rep_str;
  735.  
  736.     while (rp < loc1)
  737.         *tp++ = *rp++;
  738.  
  739.     if (!delp) while (c = *repp++) {
  740.         if (c == '\\') {
  741.             if ((c = *repp++) == '\0') {
  742.                 *tp++ = '\\';
  743.                   goto endchk;
  744.             } else if ((c = *repp++) >= '1' && c <= nparens + '1') {
  745.                 tp = insert(tp, endp, c - '1');
  746.                 continue;
  747.             }
  748.         }
  749.         *tp++ = c;
  750. endchk:        if (tp >= endp)
  751.             len_error(ERROR);
  752.     }
  753.     rp = loc2;
  754.     loc2 = REbuf + max(1, tp - tobuf);
  755.     REeom = loc2 - REbuf;
  756.     /* At least one character past the match, to prevent an infinite
  757.        number of replacements in the same position, e.g.,
  758.        replace "^" with "". */
  759.     while (*tp++ = *rp++)
  760.         if (tp >= endp)
  761.             len_error(ERROR);
  762. }
  763.  
  764. putmatch(which, buf, size)
  765. char    *buf;
  766. {
  767.     *(insert(buf, buf + size, which - 1)) = 0;
  768. }
  769.  
  770. setsearch(str)
  771. char    *str;
  772. {
  773.     strcpy(searchstr, str);
  774. }
  775.  
  776. char *
  777. getsearch()
  778. {
  779.     return searchstr;
  780. }
  781.  
  782. RErecur()
  783. {
  784.     char    sbuf[sizeof searchstr],
  785.         cbuf[sizeof compbuf],
  786.         repbuf[sizeof rep_str],
  787.         *altbuf[NALTS];
  788.     int    npars;
  789.     Mark    *m = MakeMark(curline, REbom, FLOATER);
  790.  
  791.     message("Type C-X C-C to continue with query replace.");
  792.  
  793.     npars = nparens;
  794.     byte_copy(compbuf, cbuf, sizeof compbuf);
  795.     byte_copy(searchstr, sbuf, sizeof searchstr);
  796.     byte_copy(rep_str, repbuf, sizeof rep_str);
  797.     byte_copy((char *) alternates, (char *) altbuf, sizeof alternates);
  798.     Recur();
  799.     nparens = npars;
  800.     byte_copy(cbuf, compbuf, sizeof compbuf);
  801.     byte_copy(sbuf, searchstr, sizeof searchstr);
  802.     byte_copy(repbuf, rep_str, sizeof rep_str);
  803.     byte_copy((char *) altbuf, (char *) alternates, sizeof alternates);
  804.     if (!exp_p)
  805.         ToMark(m);
  806.     DelMark(m);
  807. }
  808.  
  809. ForSearch()
  810. {
  811.     search(FORWARD, UseRE, YES);
  812. }
  813.  
  814. RevSearch()
  815. {
  816.     search(BACKWARD, UseRE, YES);
  817. }
  818.  
  819. FSrchND()
  820. {
  821.     search(FORWARD, UseRE, NO);
  822. }
  823.  
  824. RSrchND()
  825. {
  826.     search(BACKWARD, UseRE, NO);
  827. }
  828.  
  829. private
  830. search(dir, re, setdefault)
  831. {
  832.     Bufpos    *newdot;
  833.     char    *s;
  834.  
  835.     s = ask(searchstr, ProcFmt);
  836.     if (setdefault)
  837.         setsearch(s);
  838.     okay_wrap = YES;
  839.     newdot = dosearch(s, dir, re);
  840.     okay_wrap = NO;
  841.     if (newdot == 0) {
  842.         if (WrapScan)
  843.             complain("No \"%s\" in buffer.", s);
  844.         else
  845.             complain("No \"%s\" found to %s.", s,
  846.                  (dir == FORWARD) ? "bottom" : "top");
  847.     }
  848.     PushPntp(newdot->p_line);
  849.     SetDot(newdot);
  850. }
  851.  
  852. /* Do we match PATTERN at OFFSET in BUF? */
  853.  
  854. LookingAt(pattern, buf, offset)
  855. char    *pattern,
  856.     *buf;
  857. {
  858.     register char    **alt = alternates;
  859.  
  860.     REcompile(pattern, 1, compbuf, alternates);
  861.     REreset();
  862.     locs = buf + offset;
  863.     REbolp = buf;
  864.  
  865.     while (*alt)
  866.         if (REmatch(locs, *alt++))
  867.             return 1;
  868.     return 0;
  869. }
  870.  
  871. look_at(expr)
  872. char    *expr;
  873. {
  874.     REcompile(expr, 0, compbuf, alternates);
  875.     REreset();
  876.     locs = linebuf + curchar;
  877.     REbolp = linebuf;
  878.     if (REmatch(locs, alternates[0]))
  879.         return 1;
  880.     return 0;
  881. }
  882.  
  883.