home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / search.c < prev    next >
C/C++ Source or Header  |  1998-07-01  |  19KB  |  856 lines

  1. /*
  2.  * The functions in this file implement commands that search in the forward
  3.  * and backward directions.
  4.  *  heavily modified by Paul Fox, 1990
  5.  *
  6.  * $Header: /usr/build/vile/vile/RCS/search.c,v 1.112 1998/07/01 23:34:46 Larry.Gensch Exp $
  7.  *
  8.  * original written Aug. 1986 by John M. Gamble, but I (pgf) have since
  9.  * replaced his regex stuff with Henry Spencer's regexp package.
  10.  *
  11.  */
  12.  
  13. #include    "estruct.h"
  14. #include        "edef.h"
  15.  
  16. static char const onlyonemsg[] = "Only one occurrence of pattern";
  17. static char const notfoundmsg[] = "Not found";
  18. static char const hitendmsg[] = "Search reached %s without matching pattern";
  19.  
  20. static    int    rsearch(int f, int n, int dummy, int fromscreen);
  21. static    void    nextch(MARK *pdot, int dir);
  22. static    void    savematch(MARK curpos, SIZE_T matchlen);
  23.  
  24. static void
  25. not_found_msg(int wrapok, int dir)
  26. {
  27.     if (wrapok || global_b_val(MDTERSE))
  28.         mlforce (notfoundmsg);
  29.     else
  30.         mlforce (hitendmsg, dir == FORWARD ? "bottom":"top");
  31. }
  32.  
  33. int
  34. scrforwsearch(int f, int n)
  35. {
  36.     return fsearch(f,n,FALSE,TRUE);
  37. }
  38.  
  39. int
  40. scrbacksearch(int f, int n)
  41. {
  42.     return rsearch(f,n,FALSE,TRUE);
  43. }
  44.  
  45. /*
  46.  * forwsearch -- Search forward.  Get a search string from the user, and
  47.  *    search for the string.  If found, reset the "." to be just after
  48.  *    the match string, and (perhaps) repaint the display.
  49.  */
  50.  
  51. int
  52. forwsearch(int f, int n)
  53. {
  54.     register int status;
  55.     hst_init('/');
  56.     status = fsearch(f, n, FALSE, FALSE);
  57.     hst_flush();
  58.     return status;
  59. }
  60.  
  61. /* extra args -- marking if called from globals, and should mark lines, and
  62.     fromscreen, if the searchpattern is on the screen, so we don't need to
  63.     ask for it.  */
  64. int
  65. fsearch(int f, int n, int marking, int fromscreen)
  66. {
  67.     register int status;
  68.     int wrapok;
  69.     MARK curpos;
  70.     int didmark = FALSE;
  71.     int didwrap;
  72.  
  73.     if (f && n < 0)
  74.         return rsearch(f, -n, FALSE, FALSE);
  75.  
  76.     wrapok = marking || window_b_val(curwp, MDSWRAP);
  77.  
  78.     last_srch_direc = FORWARD;
  79.  
  80.     /* Ask the user for the text of a pattern.  If the
  81.      * response is TRUE (responses other than FALSE are
  82.      * possible), search for the pattern for as long as
  83.      * n is positive (n == 0 will go through once, which
  84.      * is just fine).
  85.      *
  86.      * If "marking", then we were called to do line marking for the
  87.      *  global command.
  88.      */
  89.     if (!marking && (status = readpattern("Search: ", &pat[0],
  90.                 &gregexp, lastkey, fromscreen)) != TRUE) {
  91.         return status;
  92.     }
  93.  
  94.     ignorecase = window_b_val(curwp, MDIGNCASE);
  95.  
  96.     curpos = DOT;
  97.     scanboundry(wrapok,curpos,FORWARD);
  98.     didwrap = FALSE;
  99.     do {
  100.         nextch(&(DOT), FORWARD);
  101.         status = scanner(gregexp, FORWARD, wrapok, &didwrap);
  102.         if (status == ABORT) {
  103.             mlforce("[Aborted]");
  104.             DOT = curpos;
  105.             return status;
  106.         }
  107.         /* if found, mark the line */
  108.         if (status && marking) {
  109.             /* if we were on a match when we started, then
  110.                 scanner returns TRUE, even though it's
  111.                 on a boundary. quit if we find ourselves
  112.                 marking a line twice */
  113.             if (lismarked(DOT.l))
  114.                 break;
  115.             lsetmarked(DOT.l);
  116.             /* and, so the next nextch gets to next line */
  117.             DOT.o = llength(DOT.l);
  118.             didmark = TRUE;
  119.         }
  120.         if (!marking && didwrap) {
  121.             mlwrite("[Search wrapped past end of buffer]");
  122.             didwrap = FALSE;
  123.         }
  124.     } while ((marking || --n > 0) && status == TRUE);
  125.  
  126.     if (!marking && !status)
  127.         nextch(&(DOT),REVERSE);
  128.  
  129.     if (marking) {  /* restore dot and offset */
  130.         DOT = curpos;
  131.     } else if (status) {
  132.         savematch(DOT,gregexp->mlen);
  133.         if (samepoint(DOT,curpos)) {
  134.             mlwrite(onlyonemsg);
  135.         }
  136.     }
  137.  
  138.     /* Complain if not there.  */
  139.     if ((marking && didmark == FALSE) ||
  140.                 (!marking && status == FALSE)) {
  141.         not_found_msg(wrapok,FORWARD);
  142.         return FALSE;
  143.     }
  144.  
  145.     attrib_matches();
  146.     return TRUE;
  147. }
  148.  
  149. /*
  150.  * forwhunt -- Search forward for a previously acquired search string.
  151.  *    If found, reset the "." to be just after the match string,
  152.  *    and (perhaps) repaint the display.
  153.  */
  154.  
  155. int
  156. forwhunt(int f, int n)
  157. {
  158.     register int status;
  159.     int wrapok;
  160.     MARK curpos;
  161.     int didwrap;
  162.  
  163.     wrapok = window_b_val(curwp, MDSWRAP);
  164.  
  165.     if (n < 0)        /* search backwards */
  166.         return(backhunt(f, -n));
  167.  
  168.     /* Make sure a pattern exists */
  169.     if (pat[0] == EOS)
  170.     {
  171.         mlforce("[No pattern set]");
  172.         return FALSE;
  173.     }
  174.  
  175.     ignorecase = window_b_val(curwp, MDIGNCASE);
  176.  
  177.     /* Search for the pattern for as long as
  178.      * n is positive (n == 0 will go through once, which
  179.      * is just fine).
  180.      */
  181.     curpos = DOT;
  182.     scanboundry(wrapok,DOT,FORWARD);
  183.     didwrap = FALSE;
  184.     do {
  185.         nextch(&(DOT),FORWARD);
  186.         status = scanner(gregexp, FORWARD, wrapok, &didwrap);
  187.         if (didwrap) {
  188.             mlwrite("[Search wrapped past end of buffer]");
  189.             didwrap = FALSE;
  190.         }
  191.     } while ((--n > 0) && status == TRUE);
  192.  
  193.     /* Save away the match, or complain if not there.  */
  194.     if (status == TRUE) {
  195.         savematch(DOT,gregexp->mlen);
  196.         if (samepoint(DOT,curpos)) {
  197.             mlwrite(onlyonemsg);
  198.         }
  199.     } else if (status == FALSE) {
  200.         nextch(&(DOT),REVERSE);
  201.         not_found_msg(wrapok,FORWARD);
  202.     } else if (status == ABORT) {
  203.         mlforce("[Aborted]");
  204.         DOT = curpos;
  205.         return status;
  206.     }
  207.  
  208.     attrib_matches();
  209.     return status;
  210. }
  211.  
  212. /*
  213.  * backsearch -- Reverse search.  Get a search string from the user, and
  214.  *    search, starting at "." and proceeding toward the front of the buffer.
  215.  *    If found "." is left pointing at the first character of the pattern
  216.  *    (the last character that was matched).
  217.  */
  218. int
  219. backsearch(int f, int n)
  220. {
  221.     register int status;
  222.     hst_init('?');
  223.     status = rsearch(f, n, FALSE, FALSE);
  224.     hst_flush();
  225.     return status;
  226. }
  227.  
  228. /* ARGSUSED */
  229. static int
  230. rsearch(int f, int n, int dummy GCC_UNUSED, int fromscreen)
  231. {
  232.     register int status;
  233.     int wrapok;
  234.     MARK curpos;
  235.     int didwrap;
  236.  
  237.     if (n < 0)
  238.         return fsearch(f, -n, FALSE, fromscreen);
  239.  
  240.     wrapok = window_b_val(curwp, MDSWRAP);
  241.  
  242.     last_srch_direc = REVERSE;
  243.  
  244.     /* Ask the user for the text of a pattern.  If the
  245.      * response is TRUE (responses other than FALSE are
  246.      * possible), search for the pattern for as long as
  247.      * n is positive (n == 0 will go through once, which
  248.      * is just fine).
  249.      */
  250.     if ((status = readpattern("Reverse search: ", &pat[0],
  251.                 &gregexp, EOS, fromscreen)) == TRUE) {
  252.         ignorecase = window_b_val(curwp, MDIGNCASE);
  253.  
  254.         curpos = DOT;
  255.         scanboundry(wrapok,DOT,REVERSE);
  256.         didwrap = FALSE;
  257.         do {
  258.             nextch(&(DOT),REVERSE);
  259.             status = scanner(gregexp, REVERSE, wrapok, &didwrap);
  260.             if (didwrap) {
  261.                 mlwrite(
  262.                   "[Search wrapped past start of buffer]");
  263.                 didwrap = FALSE;
  264.             }
  265.         } while ((--n > 0) && status == TRUE);
  266.  
  267.         /* Save away the match, or complain if not there.  */
  268.         if (status == TRUE)
  269.             savematch(DOT,gregexp->mlen);
  270.             if (samepoint(DOT,curpos)) {
  271.                 mlwrite(onlyonemsg);
  272.             }
  273.         else if (status == FALSE) {
  274.             nextch(&(DOT),FORWARD);
  275.             not_found_msg(wrapok,REVERSE);
  276.         } else if (status == ABORT) {
  277.             mlforce("[Aborted]");
  278.             DOT = curpos;
  279.             return status;
  280.         }
  281.     }
  282.     attrib_matches();
  283.     return status;
  284. }
  285.  
  286. /*
  287.  * backhunt -- Reverse search for a previously acquired search string,
  288.  *    starting at "." and proceeding toward the front of the buffer.
  289.  *    If found "." is left pointing at the first character of the pattern
  290.  *    (the last character that was matched).
  291.  */
  292. int
  293. backhunt(int f, int n)
  294. {
  295.     register int status;
  296.     int wrapok;
  297.     MARK curpos;
  298.     int didwrap;
  299.  
  300.     wrapok = window_b_val(curwp, MDSWRAP);
  301.  
  302.     if (n < 0)        /* search forwards */
  303.         return(forwhunt(f, -n));
  304.  
  305.     /* Make sure a pattern exists */
  306.     if (pat[0] == EOS) {
  307.         mlforce("[No pattern set]");
  308.         return FALSE;
  309.     }
  310.  
  311.     /* Go search for it for as long as
  312.      * n is positive (n == 0 will go through once, which
  313.      * is just fine).
  314.      */
  315.  
  316.     ignorecase = window_b_val(curwp, MDIGNCASE);
  317.  
  318.     curpos = DOT;
  319.     scanboundry(wrapok,DOT,REVERSE);
  320.     didwrap = FALSE;
  321.     do {
  322.         nextch(&(DOT),REVERSE);
  323.         status = scanner(gregexp, REVERSE, wrapok, &didwrap);
  324.         if (didwrap) {
  325.             mlwrite("[Search wrapped past start of buffer]");
  326.             didwrap = FALSE;
  327.         }
  328.     } while ((--n > 0) && status == TRUE);
  329.  
  330.     /* Save away the match, or complain
  331.      * if not there.
  332.      */
  333.     if (status == TRUE) {
  334.         savematch(DOT,gregexp->mlen);
  335.         if (samepoint(DOT, curpos)) {
  336.             mlwrite(onlyonemsg);
  337.         }
  338.     } else if (status == FALSE) {
  339.         nextch(&(DOT),FORWARD);
  340.         not_found_msg(wrapok,REVERSE);
  341.     } else if (status == ABORT) {
  342.         mlforce("[Aborted]");
  343.         DOT = curpos;
  344.         return status;
  345.     }
  346.  
  347.     attrib_matches();
  348.     return status;
  349. }
  350.  
  351. /* continue searching in the same direction as previous */
  352. int
  353. consearch(int f, int n)
  354. {
  355.     if (last_srch_direc == FORWARD)
  356.         return(forwhunt(f,n));
  357.     else
  358.         return(backhunt(f,n));
  359. }
  360.  
  361. /* reverse the search direction */
  362. int
  363. revsearch(int f, int n)
  364. {
  365.     if (last_srch_direc == FORWARD)
  366.         return(backhunt(f,n));
  367.     else
  368.         return(forwhunt(f,n));
  369. }
  370.  
  371. static int
  372. testit(LINE *lp, regexp *exp, int *end, int srchlim)
  373. {
  374.     char *txt = lp->l_text;
  375.     C_NUM col = (C_NUM)(exp->startp[0] - txt) + 1;
  376.  
  377.     if (col > llength(lp))
  378.         col = llength(lp);
  379.     if (lregexec(exp, lp, col, srchlim)) {
  380.         col = (C_NUM)(exp->startp[0] - txt) + 1;
  381.         if (col > llength(lp) && !*end) {
  382.             col = llength(lp);
  383.             *end = TRUE;
  384.         }
  385.         if (col <= srchlim)
  386.             return TRUE;
  387.     }
  388.     return FALSE;
  389. }
  390.  
  391. /*
  392.  * scanner -- Search for a pattern in either direction.  If found,
  393.  *    reset the "." to be at the start or just after the match string
  394.  */
  395. int
  396. scanner(
  397. regexp    *exp,    /* the compiled expression */
  398. int    direct,    /* which way to go.*/
  399. int    wrapok,    /* ok to wrap around bottom of buffer? */
  400. int    *wrappedp)
  401. {
  402.     MARK curpos;
  403.     int found;
  404.     int wrapped = FALSE;
  405.  
  406.     if (!exp) {
  407.         mlforce("BUG: null exp");
  408.         return FALSE;
  409.     }
  410.  
  411.     /* Setup local scan pointers to global ".".
  412.      */
  413.     curpos = DOT;
  414.  
  415.     /* Scan each character until we hit the scan boundary */
  416.     for_ever {
  417.         register int startoff, srchlim;
  418.  
  419.         if (interrupted()) {
  420.             if (wrappedp)
  421.                 *wrappedp = wrapped;
  422.             return ABORT;
  423.         }
  424.  
  425.         if (sameline(curpos, scanboundpos)) {
  426.             if (scanbound_is_header) {
  427.                 /* if we're on the header, nothing can match */
  428.                 found = FALSE;
  429.                 srchlim = 0;
  430.             } else {
  431.                 if (direct == FORWARD) {
  432.                     if (wrapped) {
  433.                         startoff = curpos.o;
  434.                         srchlim = scanboundpos.o;
  435.                     } else {
  436.                         startoff = curpos.o;
  437.                         srchlim =
  438.                          (scanboundpos.o > startoff) ?
  439.                             scanboundpos.o :
  440.                             llength(curpos.l);
  441.                     }
  442.                 } else {
  443.                     if (wrapped) {
  444.                         startoff = scanboundpos.o;
  445.                         srchlim = llength(curpos.l);
  446.                     } else {
  447.                         startoff = 0;
  448.                         srchlim = scanboundpos.o + 1;
  449.                     }
  450.                 }
  451.                 found = lregexec(exp, curpos.l,
  452.                             startoff, srchlim);
  453.             }
  454.         } else {
  455.             if (direct == FORWARD) {
  456.                 startoff = curpos.o;
  457.                 srchlim = llength(curpos.l);
  458.             } else {
  459.                 startoff = 0;
  460.                 srchlim = curpos.o+1;
  461.                 if (srchlim > llength(curpos.l))
  462.                     srchlim = llength(curpos.l);
  463.             }
  464.             found = lregexec(exp, curpos.l,
  465.                         startoff, srchlim);
  466.         }
  467.         if (found) {
  468.             char *txt = curpos.l->l_text;
  469.             char *got = exp->startp[0];
  470.             C_NUM next;
  471.             C_NUM last = curpos.o;
  472.  
  473.             if (direct == REVERSE) { /* find the last one */
  474.                 int end = FALSE;
  475.                 char *tst = 0;
  476.  
  477.                 last++;
  478.                 while (testit(curpos.l, exp, &end, srchlim)) {
  479.                     got = exp->startp[0];
  480.                     /* guard against infinite loop:  "?$"
  481.                      * or "?.*"
  482.                      */
  483.                     if (tst == got)
  484.                         break;
  485.                     tst = got;
  486.                 }
  487.                 if (end)
  488.                     last++;
  489.                 if (!lregexec(exp, curpos.l,
  490.                         (int)(got - txt), srchlim)) {
  491.                     mlforce("BUG: prev. match no good");
  492.                     return FALSE;
  493.                 }
  494.             } else if (llength(curpos.l) <= 0
  495.                || last < llength(curpos.l))
  496.                 last--;
  497.             next = (C_NUM)(got - txt);
  498.             if (next != last) {
  499.                 DOT.l = curpos.l;
  500.                 DOT.o = next;
  501.                 curwp->w_flag |= WFMOVE; /* flag that we have moved */
  502.                 if (wrappedp)
  503.                     *wrappedp = wrapped;
  504.                 return TRUE;
  505.             }
  506.         } else {
  507.             if (sameline(curpos,scanboundpos) &&
  508.                             (!wrapok || wrapped))
  509.                 break;
  510.         }
  511.         if (direct == FORWARD) {
  512.             curpos.l = lforw(curpos.l);
  513.         } else {
  514.             curpos.l = lback(curpos.l);
  515.         }
  516.         if (is_header_line(curpos, curbp)) {
  517.             wrapped = TRUE;
  518.             if (sameline(curpos,scanboundpos) &&
  519.                         (!wrapok || wrapped) )
  520.                 break;
  521.             if (direct == FORWARD)
  522.                 curpos.l = lforw(curpos.l);
  523.             else
  524.                 curpos.l = lback(curpos.l);
  525.         }
  526.         if (direct == FORWARD) {
  527.             curpos.o = 0;
  528.         } else {
  529.             if ((curpos.o = llength(curpos.l)-1) < 0)
  530.                 curpos.o = 0;
  531.         }
  532.  
  533.     }
  534.  
  535.     if (wrappedp)
  536.         *wrappedp = wrapped;
  537.     return FALSE;    /* We could not find a match.*/
  538. }
  539.  
  540. #if OPT_HILITEMATCH
  541. static int hilite_suppressed;
  542. static char savepat[NPAT];
  543. static int save_igncase;
  544. static int save_magic;
  545. static BUFFER *save_curbp;
  546. static VIDEO_ATTR save_vattr;
  547.  
  548. void
  549. clobber_save_curbp(BUFFER *bp)
  550. {
  551.     if (save_curbp == bp)
  552.         save_curbp = NULL;
  553. }
  554.  
  555. /* keep track of enough state to give us a hint as to whether
  556.     we need to redo the visual matches */
  557. static int
  558. need_to_rehilite(void)
  559. {
  560.     /* save static copies of state that affects the search */
  561.  
  562.     if ((curbp->b_highlight & (HILITE_ON|HILITE_DIRTY)) ==
  563.                   (HILITE_ON|HILITE_DIRTY) ||
  564.             strcmp(pat, savepat) != 0 ||
  565.             save_igncase != ignorecase ||
  566.             save_vattr != b_val(curbp,VAL_HILITEMATCH) ||
  567.             save_magic != b_val(curbp, MDMAGIC) ||
  568.             (!hilite_suppressed && save_curbp != curbp)) {
  569.         (void)strcpy(savepat, pat);
  570.         save_igncase = ignorecase;
  571.         save_vattr = b_val(curbp,VAL_HILITEMATCH);
  572.         save_magic = b_val(curbp, MDMAGIC);
  573.         save_curbp = curbp;
  574.         return TRUE;
  575.     }
  576.     return FALSE;
  577. }
  578. #endif
  579.  
  580. #if OPT_HILITEMATCH
  581. /* ARGSUSED */
  582. int
  583. clear_match_attrs(int f GCC_UNUSED, int n GCC_UNUSED)
  584. {
  585.     int status;
  586.     MARK origdot, origmark;
  587.  
  588.     if ((curbp->b_highlight & HILITE_ON) == 0)
  589.         return TRUE;
  590.  
  591.     origdot = DOT;
  592.     origmark = MK;
  593.  
  594.     DOT.l = lforw(buf_head(curbp));
  595.     DOT.o = 0;
  596.     MK.l = lback(buf_head(curbp));
  597.     MK.o = llength(MK.l) - 1;
  598.     videoattribute = VOWN_MATCHES;
  599.     if ((status = attributeregion()) == TRUE) {
  600.         DOT = origdot;
  601.         MK = origmark;
  602.         curbp->b_highlight = 0;
  603. #if OPT_HILITEMATCH
  604.         hilite_suppressed = TRUE;
  605. #endif
  606.     }
  607.     return status;
  608. }
  609. #endif
  610.  
  611. void
  612. attrib_matches(void)
  613. {
  614. #if OPT_HILITEMATCH
  615.     MARK origdot;
  616.     int status = TRUE;
  617.     REGIONSHAPE oregionshape = regionshape;
  618.     VIDEO_ATTR vattr;
  619.  
  620.     ignorecase = window_b_val(curwp, MDIGNCASE);
  621.  
  622.     if (!need_to_rehilite())
  623.         return;
  624.  
  625.     if (pat[0] == EOS || gregexp == NULL)
  626.         return;
  627.  
  628. /* #define track_hilite 1 */
  629. #ifdef track_hilite
  630.     mlwrite("rehighlighting");
  631. #endif
  632.  
  633.     vattr = b_val(curbp,VAL_HILITEMATCH);
  634.     if (vattr == 0)
  635.         return;
  636.  
  637.     (void)clear_match_attrs(TRUE,1);
  638.  
  639.     origdot = DOT;
  640.     DOT.l = buf_head(curbp);
  641.     DOT.o = 0;
  642.  
  643.     scanboundry(FALSE,DOT,FORWARD);
  644.     do {
  645.         nextch(&(DOT),FORWARD);
  646.         status = scanner(gregexp, FORWARD, FALSE, (int *)0);
  647.         if (status != TRUE)
  648.             break;
  649.         if (vattr != VACOLOR)
  650.             videoattribute = vattr;
  651.         else {
  652.             int c;
  653.             for (c = NSUBEXP-1; c > 0; c--)
  654.                 if ( gregexp->startp[c] == gregexp->startp[0]
  655.                   && gregexp->endp[c] == gregexp->endp[0] )
  656.                     break;
  657.             if (c > NCOLORS-1)
  658.                 videoattribute = VCOLORATTR(NCOLORS-1);
  659.             else
  660.                 videoattribute = VCOLORATTR(c+1);
  661.         }
  662.         MK.l = DOT.l;
  663.         MK.o = DOT.o + gregexp->mlen;
  664.         regionshape = EXACT;
  665.         videoattribute |= VOWN_MATCHES;
  666.         status = attributeregion();
  667.     } while (status == TRUE);
  668.  
  669.     DOT = origdot;
  670.     regionshape = oregionshape;
  671.     curbp->b_highlight = HILITE_ON;  /* & ~HILITE_DIRTY */
  672.     hilite_suppressed = FALSE;
  673. #endif /* OPT_HILITEMATCH */
  674. }
  675.  
  676. void
  677. regerror(const char *s)
  678. {
  679.     mlforce("[Bad pattern: %s ]",s);
  680. }
  681.  
  682.  
  683. /*
  684.  * eq -- Compare two characters.  The "bc" comes from the buffer, "pc"
  685.  *    from the pattern.  If we are in IGNCASE mode, fold out the case.
  686.  */
  687. #if OPT_EVAL || UNUSED
  688. int
  689. eq(register int bc, register int pc)
  690. {
  691.     if (bc == pc)
  692.         return TRUE;
  693.     if (!window_b_val(curwp, MDIGNCASE))
  694.         return FALSE;
  695.     return nocase_eq(bc,pc);
  696. }
  697. #endif
  698.  
  699. /* ARGSUSED */
  700. int
  701. scrsearchpat(int f GCC_UNUSED, int n GCC_UNUSED)
  702. {
  703.     int s;
  704.     s =  readpattern("", pat, &gregexp, EOS, TRUE);
  705.     mlwrite("Search pattern is now %s", pat);
  706.     last_srch_direc = FORWARD;
  707.     return s;
  708. }
  709.  
  710. /*
  711.  * readpattern -- Read a pattern.  Stash it in apat.  If it is the
  712.  *    search string, re_comp() it.
  713.  *    Apat is not updated if the user types in an empty line.  If
  714.  *    the user typed an empty line, and there is no old pattern, it is
  715.  *    an error.  Display the old pattern, in the style of Jeff Lomicka.
  716.  *    There is some do-it-yourself control expansion.
  717.  *    An alternate termination character is passed in.
  718.  */
  719. int
  720. readpattern(
  721. const char *prompt,
  722. char    *apat,
  723. regexp    **srchexpp,
  724. int    c,
  725. int    fromscreen)
  726. {
  727.     int status;
  728.  
  729.     /* Read a pattern.  Either we get one,
  730.      * or we don't, and use the previous pattern.
  731.      * Then, if it's the search string, compile it.
  732.      */
  733.     if (fromscreen) {
  734.         status = screen_string(apat, NPAT, vl_ident);
  735.         if (status != TRUE)
  736.             return status;
  737.     } else {
  738.         /* don't expand #, %, :, and never process backslashes
  739.             since they're handled by regexp directly for the
  740.             search pattern, and in delins() for the replacement
  741.             pattern */
  742.         hst_glue(c);
  743.         status = kbd_string(prompt, apat, NPAT, c, KBD_EXPPAT|KBD_0CHAR,
  744.                     no_completion);
  745.     }
  746.      if (status == TRUE) {
  747.         if (srchexpp) {    /* If doing the search string, compile it */
  748.             FreeIfNeeded(*srchexpp);
  749.             *srchexpp = regcomp(pat, b_val(curbp, MDMAGIC));
  750.             if (!*srchexpp)
  751.                 return FALSE;
  752.         }
  753.     } else if (status == FALSE && *apat != EOS) { /* Old one */
  754.         status = TRUE;
  755.     }
  756.  
  757.     return status;
  758. }
  759.  
  760. /*
  761.  * savematch -- We found the pattern?  Let's save it away.
  762.  */
  763.  
  764. static void
  765. savematch(MARK curpos, SIZE_T matchlen)
  766. {
  767.     static    ALLOC_T    patlen = 0;    /* length of last malloc */
  768.  
  769.     /* free any existing match string */
  770.     if (patmatch == NULL || patlen < matchlen) {
  771.         FreeIfNeeded(patmatch);
  772.         /* attempt to allocate a new one */
  773.         patmatch = castalloc(char, patlen = matchlen + 20);
  774.         if (patmatch == NULL)
  775.             return;
  776.     }
  777.  
  778.     (void)strncpy(patmatch, &(curpos.l->l_text[curpos.o]), matchlen);
  779.  
  780.     /* null terminate the match string */
  781.     patmatch[matchlen] = EOS;
  782. }
  783.  
  784. void
  785. scanboundry(int wrapok, MARK dot, int dir)
  786. {
  787.     if (wrapok) {
  788.         nextch(&dot,dir);
  789.         scanboundpos = dot;
  790.         scanbound_is_header = FALSE;
  791.     } else {
  792.         scanboundpos = curbp->b_line;
  793.         scanbound_is_header = TRUE;
  794.     }
  795. }
  796.  
  797. /*
  798.  * nextch -- advance/retreat the given mark
  799.  *  will wrap, and doesn't set motion flags
  800.  */
  801. static void
  802. nextch(MARK *pdot, int dir)
  803. {
  804.     register LINE    *curline;
  805.     register int    curoff;
  806.  
  807.     curline = pdot->l;
  808.     curoff = pdot->o;
  809.     if (dir == FORWARD) {
  810.         if (curoff == llength(curline)) {
  811.             curline = lforw(curline);    /* skip to next line */
  812.             curoff = 0;
  813.         } else {
  814.             curoff++;
  815.         }
  816.     } else {
  817.         if (curoff == 0) {
  818.             curline = lback(curline);
  819.             curoff = llength(curline);
  820.         } else {
  821.             curoff--;
  822.         }
  823.     }
  824.     pdot->l = curline;
  825.     pdot->o = curoff;
  826. }
  827.  
  828.  
  829. /* simple finder -- give it a compiled regex, a direction, and it takes you
  830.     there if it can.  no wrapping allowed  */
  831. int
  832. findpat(int f, int n, regexp *exp, int direc)
  833. {
  834.     int s;
  835.     MARK savepos;
  836.  
  837.     if (!exp)
  838.         return FALSE;
  839.  
  840.     if (!f) n = 1;
  841.  
  842.     s = TRUE;
  843.     scanboundpos = curbp->b_line; /* was scanboundry(FALSE,savepos,0); */
  844.     scanbound_is_header = TRUE;
  845.     while (s == TRUE && n--) {
  846.         savepos = DOT;
  847.         s = (direc == FORWARD) ? forwchar(TRUE,1) : backchar(TRUE,1);
  848.         if (s == TRUE)
  849.             s = scanner(exp, direc, FALSE, (int *)0);
  850.     }
  851.     if (s != TRUE)
  852.         DOT = savepos;
  853.  
  854.     return s;
  855. }
  856.