home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / search.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  19KB  |  811 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.  * $Log: search.c,v $
  7.  * Revision 1.41  1992/12/07  23:31:00  foxharp
  8.  * whoops -- on second though, _don't_ do backslash processing in kbd_string,
  9.  * do it in delins()
  10.  *
  11.  * Revision 1.40  1992/12/05  13:36:14  foxharp
  12.  * tell kbd_string() to do backslash processing on the replacement pattern.
  13.  * some comment revisions, and moved rvstrcpy to file.c, where it's now
  14.  * ifdefed along with the code that calls it
  15.  *
  16.  * Revision 1.39  1992/12/04  09:14:36  foxharp
  17.  * deleted unused assigns
  18.  *
  19.  * Revision 1.38  1992/08/20  23:40:48  foxharp
  20.  * typo fixes -- thanks, eric
  21.  *
  22.  * Revision 1.37  1992/07/13  20:03:54  foxharp
  23.  * the "terse" variable is now a boolean mode
  24.  *
  25.  * Revision 1.36  1992/07/08  09:08:08  foxharp
  26.  * don't mlforce() the "onlyonemsg", and support terse on "Not found"
  27.  *
  28.  * Revision 1.35  1992/07/07  08:34:50  foxharp
  29.  * added not_found_msg(), to that non-wrapping searches give appropriate
  30.  * message.  thanks leora!
  31.  *
  32.  * Revision 1.34  1992/06/03  08:37:48  foxharp
  33.  * stop searching if we've wrapped when we hit the boundary
  34.  *
  35.  * Revision 1.33  1992/05/16  12:00:31  pgf
  36.  * prototypes/ansi/void-int stuff/microsoftC
  37.  *
  38.  * Revision 1.32  1992/03/19  23:46:24  pgf
  39.  * took out scrsearchword stuff -- macros can do it
  40.  *
  41.  * Revision 1.31  1992/03/07  10:19:17  pgf
  42.  * added Eric Krohn's srcsearchword() functions.  All of this screen search
  43.  * stuff could be done with macros if variables worked right.
  44.  *
  45.  * Revision 1.30  1992/02/17  08:54:07  pgf
  46.  * took out unused var for saber
  47.  *
  48.  * Revision 1.29  1992/01/22  16:58:20  pgf
  49.  * cleaned up nextch(), to get rid of unneeded return value
  50.  *
  51.  * Revision 1.28  1992/01/05  00:06:13  pgf
  52.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  53.  * often.  also normalized message appearance somewhat.
  54.  *
  55.  * Revision 1.27  1992/01/03  23:24:25  pgf
  56.  * try not to let curpos.o go negative during scan
  57.  *
  58.  * Revision 1.26  1991/11/16  18:34:31  pgf
  59.  * pass magic mode as flag to regcomp()
  60.  *
  61.  * Revision 1.25  1991/11/12  23:47:05  pgf
  62.  * the header line no longer matches '^.$', and
  63.  * now use lregexec exclusively
  64.  *
  65.  * Revision 1.24  1991/11/08  13:11:49  pgf
  66.  * renamed bsearch to rsearch, for lint/libc cleanliness
  67.  *
  68.  * Revision 1.23  1991/11/04  14:24:23  pgf
  69.  * don't use matchlen anymore
  70.  *
  71.  * Revision 1.22  1991/11/04  14:19:49  pgf
  72.  * cleaned up savematch, and call it correctly
  73.  *
  74.  * Revision 1.21  1991/11/03  17:33:20  pgf
  75.  * use new lregexec() routine to check for patterns in lines
  76.  *
  77.  * Revision 1.20  1991/11/01  14:38:00  pgf
  78.  * saber cleanup
  79.  *
  80.  * Revision 1.19  1991/11/01  14:10:35  pgf
  81.  * matchlen is now part of the regexp struct (mlen), and readpattern now
  82.  * takes a **regexp instead of just a flag to indicate it should compile
  83.  * the pattern
  84.  *
  85.  * Revision 1.18  1991/10/30  14:55:43  pgf
  86.  * renamed thescanner to scanner, setboundry to scanboundry
  87.  *
  88.  * Revision 1.17  1991/10/28  01:01:06  pgf
  89.  * added start offset and end offset to regexec calls
  90.  *
  91.  * Revision 1.16  1991/10/27  01:54:47  pgf
  92.  * switched to regexp from regex, and
  93.  * eliminated the old search-and-replace code that was no longer
  94.  * used, and
  95.  * added the new simple findpat() utility
  96.  *
  97.  * Revision 1.15  1991/10/24  13:05:52  pgf
  98.  * conversion to new regex package -- much faster
  99.  *
  100.  * Revision 1.14  1991/10/23  14:18:56  pgf
  101.  * made character comparisons faster with macro, and
  102.  * took out special cases for the header line -- now it really _does_
  103.  * have a -1 as its first and only character
  104.  *
  105.  * Revision 1.13  1991/09/26  13:10:32  pgf
  106.  * new arg. to kbd_string, to suppress backslash processing
  107.  *
  108.  * Revision 1.12  1991/09/19  13:40:30  pgf
  109.  * MDEXACT is now MDIGNCASE
  110.  *
  111.  * Revision 1.11  1991/08/07  12:35:07  pgf
  112.  * added RCS log messages
  113.  *
  114.  * revision 1.10
  115.  * date: 1991/08/06 15:55:24;
  116.  * fixed null l_text dereference in nextch()
  117.  * 
  118.  * revision 1.9
  119.  * date: 1991/08/06 15:25:24;
  120.  *  global/local values
  121.  * 
  122.  * revision 1.8
  123.  * date: 1991/06/25 19:53:21;
  124.  * massive data structure restructure
  125.  * 
  126.  * revision 1.7
  127.  * date: 1991/06/20 17:20:56;
  128.  * added missing status return in forwsearch()
  129.  * 
  130.  * revision 1.6
  131.  * date: 1991/06/03 12:18:46;
  132.  * ifdef'ed MAGIC for unresolved ref
  133.  * 
  134.  * revision 1.5
  135.  * date: 1991/05/31 11:23:11;
  136.  * cleaned up so forwsearch no longer depends on 3rd or 4th arg.
  137.  * 
  138.  * revision 1.4
  139.  * date: 1990/10/12 19:31:44;
  140.  * added scrsearchpat function
  141.  * 
  142.  * revision 1.3
  143.  * date: 1990/09/25 11:38:22;
  144.  * took out old ifdef BEFORE code
  145.  * 
  146.  * revision 1.2
  147.  * date: 1990/09/24 20:36:24;
  148.  * fixed core dump resulting from not checking return code of thescanner()
  149.  * for ABORT
  150.  * 
  151.  * revision 1.1
  152.  * date: 1990/09/21 10:25:59;
  153.  * initial vile RCS revision
  154.  *
  155.  * original written Aug. 1986 by John M. Gamble, but I (pgf) have since
  156.  * replaced his regex stuff with Henry Spencer's regexp package.
  157.  *
  158.  */
  159.  
  160. #include        <stdio.h>
  161. #include    "estruct.h"
  162. #include        "edef.h"
  163.  
  164. #if    LATTICE
  165. #define    void    int
  166. #endif
  167.  
  168. int    readpattern();
  169.  
  170. void savematch();
  171. void scanboundry();
  172. void nextch();
  173.  
  174. int lastdirec;
  175.  
  176. MARK scanboundpos;
  177.  
  178. char onlyonemsg[] = "Only one occurrence of pattern";
  179. char notfoundmsg[] = "Not found";
  180. char hitendmsg[] = "Search reached %s without matching pattern";
  181.  
  182. void
  183. not_found_msg(wrapok, dir)
  184. int wrapok, dir;
  185. {
  186.     if (wrapok || global_b_val(MDTERSE))
  187.         mlforce (notfoundmsg);
  188.     else
  189.         mlforce (hitendmsg, dir == FORWARD ? "BOTTOM":"TOP");
  190. }
  191.  
  192. int
  193. scrforwsearch(f,n)
  194. int f,n;
  195. {
  196.     return fsearch(f,n,FALSE,TRUE);
  197. }
  198.  
  199. int
  200. scrbacksearch(f,n)
  201. int f,n;
  202. {
  203.     return rsearch(f,n,FALSE,TRUE);
  204. }
  205.  
  206. /*
  207.  * forwsearch -- Search forward.  Get a search string from the user, and
  208.  *    search for the string.  If found, reset the "." to be just after
  209.  *    the match string, and (perhaps) repaint the display.
  210.  */
  211.  
  212. int
  213. forwsearch(f, n)
  214. int f, n;
  215. {
  216.     return fsearch(f, n, FALSE, FALSE);
  217. }
  218.  
  219. /* extra args -- marking if called from globals, and should mark lines, and
  220.     fromscreen, if the searchpattern is on the screen, so we don't need to
  221.     ask for it.  */
  222. int
  223. fsearch(f, n, marking, fromscreen)
  224. int f, n;
  225. int marking, fromscreen;
  226. {
  227.     register int status;
  228.     int wrapok;
  229.     MARK curpos;
  230.     int didmark = FALSE;
  231.  
  232.     if (f && n < 0)
  233.         return rsearch(f, -n, NULL, FALSE);
  234.  
  235.     wrapok = marking || b_val(curwp->w_bufp, MDSWRAP);
  236.  
  237.     lastdirec = 0;
  238.  
  239.     /* Ask the user for the text of a pattern.  If the
  240.      * response is TRUE (responses other than FALSE are
  241.      * possible), search for the pattern for as long as
  242.      * n is positive (n == 0 will go through once, which
  243.      * is just fine).
  244.      *
  245.      * If "marking", then we were called to do line marking for the
  246.      *  global command.
  247.      */
  248.     if (!marking && (status = readpattern("Search: ", &pat[0],
  249.                 &gregexp, lastkey, fromscreen)) != TRUE) {
  250.         return status;
  251.     }
  252.         
  253.     ignorecase = b_val(curwp->w_bufp, MDIGNCASE);
  254.             
  255.     curpos = DOT;
  256.     scanboundry(wrapok,curpos,FORWARD);
  257.     do {
  258.         nextch(&(DOT), FORWARD);
  259.         status = scanner(gregexp, FORWARD, wrapok);
  260.         if (status == ABORT) {
  261.             TTbeep();
  262.             mlforce("[Aborted]");
  263.             DOT = curpos;
  264.             return status;
  265.         }
  266.         /* if found, mark the line */
  267.         if (status && marking) {
  268.             /* if we were on a match when we started, then
  269.                 scanner returns TRUE, even though it's
  270.                 on a boundary. quit if we find ourselves
  271.                 marking a line twice */
  272.             if (lismarked(DOT.l))
  273.                 break;
  274.             lsetmarked(DOT.l);
  275.             /* and, so the next nextch gets to next line */
  276.             DOT.o = llength(DOT.l);
  277.             didmark = TRUE;
  278.         }
  279.     } while ((marking || --n > 0) && status == TRUE);
  280.     
  281.     if (!marking && !status)
  282.         nextch(&(DOT),REVERSE);
  283.         
  284.     if (marking) {  /* restore dot and offset */
  285.         DOT = curpos;
  286.     } else if (status) {
  287.         savematch(DOT,gregexp->mlen);
  288.         if (samepoint(DOT,curpos)) {
  289.             mlwrite(onlyonemsg);
  290.             TTbeep();
  291.         }
  292.     }
  293.  
  294.     /* Complain if not there.  */
  295.     if ((marking && didmark == FALSE) ||
  296.                 (!marking && status == FALSE)) {
  297.         not_found_msg(wrapok,FORWARD);
  298.         TTbeep();
  299.         return FALSE;
  300.     }
  301.     
  302.     return TRUE;
  303. }
  304.  
  305. /*
  306.  * forwhunt -- Search forward for a previously acquired search string.
  307.  *    If found, reset the "." to be just after the match string,
  308.  *    and (perhaps) repaint the display.
  309.  */
  310.  
  311. int
  312. forwhunt(f, n)
  313. int f, n;    /* default flag / numeric argument */
  314. {
  315.     register int status;
  316.     int wrapok;
  317.     MARK curpos;
  318.     
  319.     wrapok = b_val(curwp->w_bufp, MDSWRAP);
  320.  
  321.     if (n < 0)        /* search backwards */
  322.         return(backhunt(f, -n));
  323.  
  324.     /* Make sure a pattern exists, or that we didn't switch
  325.      * into MAGIC mode until after we entered the pattern.
  326.      */
  327.     if (pat[0] == '\0')
  328.     {
  329.         mlforce("[No pattern set]");
  330.         return FALSE;
  331.     }
  332.  
  333.     ignorecase = b_val(curwp->w_bufp, MDIGNCASE);
  334.             
  335.     /* Search for the pattern for as long as
  336.      * n is positive (n == 0 will go through once, which
  337.      * is just fine).
  338.      */
  339.     curpos = DOT;
  340.     scanboundry(wrapok,DOT,FORWARD);
  341.     do {
  342.         nextch(&(DOT),FORWARD);
  343.         status = scanner(gregexp, FORWARD, wrapok);
  344.     } while ((--n > 0) && status == TRUE);
  345.  
  346.     /* Save away the match, or complain if not there.  */
  347.     if (status == TRUE) {
  348.         savematch(DOT,gregexp->mlen);
  349.         if (samepoint(DOT,curpos)) {
  350.             mlwrite(onlyonemsg);
  351.             TTbeep();
  352.         }
  353.     } else if (status == FALSE) {
  354.         nextch(&(DOT),REVERSE);
  355.         not_found_msg(wrapok,FORWARD);
  356.         TTbeep();
  357.     } else if (status == ABORT) {
  358.         TTbeep();
  359.         mlforce("[Aborted]");
  360.         DOT = curpos;
  361.         return status;
  362.     }
  363.  
  364.     return status;
  365. }
  366.  
  367. /*
  368.  * backsearch -- Reverse search.  Get a search string from the user, and
  369.  *    search, starting at "." and proceeding toward the front of the buffer.
  370.  *    If found "." is left pointing at the first character of the pattern
  371.  *    (the last character that was matched).
  372.  */
  373. int
  374. backsearch(f, n)
  375. int f, n;
  376. {
  377.     return rsearch(f, n, FALSE, FALSE);
  378. }
  379.  
  380. /* ARGSUSED */
  381. int
  382. rsearch(f, n, dummy, fromscreen)
  383. int f, n;    /* default flag / numeric argument */
  384. int dummy, fromscreen;
  385. {
  386.     register int status;
  387.     int wrapok;
  388.     MARK curpos;
  389.     
  390.     if (n < 0)
  391.         return fsearch(f, -n, NULL, fromscreen);
  392.  
  393.     wrapok = b_val(curwp->w_bufp, MDSWRAP);
  394.  
  395.     lastdirec = 1;
  396.  
  397.     /* Ask the user for the text of a pattern.  If the
  398.      * response is TRUE (responses other than FALSE are
  399.      * possible), search for the pattern for as long as
  400.      * n is positive (n == 0 will go through once, which
  401.      * is just fine).
  402.      */
  403.     if ((status = readpattern("Reverse search: ", &pat[0],
  404.                 &gregexp, lastkey, fromscreen)) == TRUE) {
  405.         ignorecase = b_val(curwp->w_bufp, MDIGNCASE);
  406.             
  407.         curpos = DOT;
  408.         scanboundry(wrapok,DOT,REVERSE);
  409.         do {
  410.             nextch(&(DOT),REVERSE);
  411.             status = scanner(gregexp, REVERSE, wrapok);
  412.         } while ((--n > 0) && status == TRUE);
  413.  
  414.         /* Save away the match, or complain if not there.  */
  415.         if (status == TRUE)
  416.             savematch(DOT,gregexp->mlen);
  417.             if (samepoint(DOT,curpos)) {
  418.                 mlwrite(onlyonemsg);
  419.                 TTbeep();
  420.             }
  421.         else if (status == FALSE) {
  422.             nextch(&(DOT),FORWARD);
  423.             not_found_msg(wrapok,REVERSE);
  424.             TTbeep();
  425.         } else if (status == ABORT) {
  426.             TTbeep();
  427.             mlforce("[Aborted]");
  428.             DOT = curpos;
  429.             return status;
  430.         }
  431.     }
  432.     return(status);
  433. }
  434.  
  435. /*
  436.  * backhunt -- Reverse search for a previously acquired search string,
  437.  *    starting at "." and proceeding toward the front of the buffer.
  438.  *    If found "." is left pointing at the first character of the pattern
  439.  *    (the last character that was matched).
  440.  */
  441. int
  442. backhunt(f, n)
  443. int f, n;    /* default flag / numeric argument */
  444. {
  445.     register int status;
  446.     int wrapok;
  447.     MARK curpos;
  448.     
  449.     wrapok = b_val(curwp->w_bufp, MDSWRAP);
  450.  
  451.     if (n < 0)
  452.         return(forwhunt(f, -n));
  453.  
  454.     /* Make sure a pattern exists, or that we didn't switch
  455.      * into MAGIC mode until after we entered the pattern.
  456.      */
  457.     if (pat[0] == '\0') {
  458.         mlforce("[No pattern set]");
  459.         return FALSE;
  460.     }
  461.  
  462.     /* Go search for it for as long as
  463.      * n is positive (n == 0 will go through once, which
  464.      * is just fine).
  465.      */
  466.  
  467.     ignorecase = b_val(curwp->w_bufp, MDIGNCASE);
  468.             
  469.     curpos = DOT;
  470.     scanboundry(wrapok,DOT,REVERSE);
  471.     do {
  472.         nextch(&(DOT),REVERSE);
  473.         status = scanner(gregexp, REVERSE, wrapok);
  474.     } while ((--n > 0) && status == TRUE);
  475.  
  476.     /* Save away the match, or complain
  477.      * if not there.
  478.      */
  479.     if (status == TRUE) {
  480.         savematch(DOT,gregexp->mlen);
  481.         if (samepoint(DOT, curpos)) {
  482.             mlwrite(onlyonemsg);
  483.             TTbeep();
  484.         }
  485.     } else if (status == FALSE) {
  486.         nextch(&(DOT),FORWARD);
  487.         not_found_msg(wrapok,REVERSE);
  488.         TTbeep();
  489.     } else if (status == ABORT) {
  490.         TTbeep();
  491.         mlforce("[Aborted]");
  492.         DOT = curpos;
  493.         return status;
  494.     }
  495.  
  496.     return(status);
  497. }
  498.  
  499. /* continue searching in the same direction as previous */
  500. int
  501. consearch(f,n)
  502. int f,n;
  503. {
  504.     if (lastdirec == 0)
  505.         return(forwhunt(f,n));
  506.     else
  507.         return(backhunt(f,n));
  508. }
  509.  
  510. /* continue searching in the opposite direction as previous */
  511. int
  512. revsearch(f,n)
  513. int f,n;
  514. {
  515.     if (lastdirec == 0)
  516.         return(backhunt(f,n));
  517.     else
  518.         return(forwhunt(f,n));
  519. }
  520.  
  521.  
  522. /*
  523.  * scanner -- Search for a pattern in either direction.  If found,
  524.  *    reset the "." to be at the start or just after the match string
  525.  */
  526. int    
  527. scanner(exp, direct, wrapok)
  528. regexp    *exp;    /* the compiled expression */
  529. int    direct;    /* which way to go.*/
  530. int    wrapok;    /* ok to wrap around bottom of buffer? */
  531. {
  532.     MARK curpos;
  533.     int found, wrapped;
  534.  
  535.     if (!exp) {
  536.         mlforce("BUG: null exp");
  537.         return FALSE;
  538.     }
  539.  
  540.     /* Setup local scan pointers to global ".".
  541.      */
  542.     curpos = DOT;
  543.  
  544.     wrapped = 0;
  545.  
  546.     /* Scan each character until we hit the scan boundary */
  547.     for(;;) {
  548.         register int startoff, srchlim;
  549.  
  550.         if (interrupted) return ABORT;
  551.  
  552.         if (sameline(curpos, scanboundpos)) {
  553.             if (!wrapped) {
  554.                 startoff = (direct == FORWARD) ?
  555.                     curpos.o : 0;
  556.                 srchlim = (direct == FORWARD) ?
  557.                     ((scanboundpos.o > curpos.o)?
  558.                     scanboundpos.o:llength(curpos.l))
  559.                             : scanboundpos.o+1;
  560.             } else {
  561.                 startoff = (direct == FORWARD) ?
  562.                     curpos.o : scanboundpos.o;
  563.                 srchlim = (direct == FORWARD) ?
  564.                     scanboundpos.o : llength(curpos.l);
  565.             }
  566.         } else {
  567.             startoff = (direct == FORWARD) ? curpos.o : 0;
  568.             srchlim = (direct == FORWARD) ?
  569.                     llength(curpos.l) : curpos.o+1;
  570.         }
  571.         found = lregexec(exp, curpos.l, startoff, srchlim);
  572.         if (found) {
  573.             if (direct == REVERSE) { /* find the last one */
  574.                 char *got = exp->startp[0];
  575.                 while (lregexec(exp, curpos.l, 
  576.                         got+1-curpos.l->l_text, 
  577.                         srchlim)) {
  578.                     got = exp->startp[0];
  579.                 }
  580.                 if (!lregexec(exp, curpos.l,
  581.                         got-curpos.l->l_text,
  582.                         srchlim)) {
  583.                     dbgwrite("BUG: prev. match no good");
  584.                     return FALSE;
  585.                 }
  586.             }
  587.             DOT.l = curpos.l;
  588.             DOT.o = exp->startp[0] - curpos.l->l_text;
  589.             curwp->w_flag |= WFMOVE; /* flag that we have moved */
  590.             return TRUE;
  591.         } else {
  592.             if (sameline(curpos,scanboundpos) &&
  593.                             (!wrapok || wrapped))
  594.                 break;
  595.         }
  596.         if (direct == FORWARD) {
  597.             curpos.l = lforw(curpos.l);
  598.             curpos.o = 0;
  599.         } else {
  600.             curpos.l = lback(curpos.l);
  601.             if ((curpos.o = llength(curpos.l)-1) < 0)
  602.                 curpos.o = 0;
  603.         }
  604.         if (is_header_line(curpos, curbp)) {
  605.             wrapped++;
  606.             if (sameline(curpos,scanboundpos) &&
  607.                         (!wrapok || wrapped) )
  608.                 break;
  609.             if (direct == FORWARD) {
  610.                 curpos.l = lforw(curpos.l);
  611.             } else {
  612.                 curpos.l = lback(curpos.l);
  613.             }
  614.         }
  615.  
  616.     }
  617.  
  618.     return FALSE;    /* We could not find a match.*/
  619. }
  620.  
  621. void
  622. regerror(s)
  623. char *s;
  624. {
  625.     mlforce("[Bad pattern: %s ]",s);
  626. }
  627.  
  628.  
  629. /*
  630.  * eq -- Compare two characters.  The "bc" comes from the buffer, "pc"
  631.  *    from the pattern.  If we are in IGNCASE mode, fold out the case.
  632.  */
  633. int    
  634. eq(bc, pc)
  635. register int    bc;
  636. register int    pc;
  637. {
  638.     if (bc == pc)
  639.         return TRUE;
  640.     if (!b_val(curwp->w_bufp, MDIGNCASE))
  641.         return FALSE;
  642.     return nocase_eq(bc,pc);
  643. }
  644.  
  645. /* ARGSUSED */
  646. int
  647. scrsearchpat(f,n)
  648. int f,n;
  649. {
  650.     int s;
  651.     s =  readpattern("", pat, &gregexp, 0, TRUE);
  652.     mlwrite("Search pattern is now %s", pat);
  653.     lastdirec = 0;
  654.     return s;
  655. }
  656.  
  657. /*
  658.  * readpattern -- Read a pattern.  Stash it in apat.  If it is the
  659.  *    search string, re_comp() it.
  660.  *    Apat is not updated if the user types in an empty line.  If
  661.  *    the user typed an empty line, and there is no old pattern, it is
  662.  *    an error.  Display the old pattern, in the style of Jeff Lomicka.
  663.  *    There is some do-it-yourself control expansion.
  664.  *    An alternate termination character is passed in.
  665.  */
  666. int
  667. readpattern(prompt, apat, srchexpp, c, fromscreen)
  668. char    *prompt;
  669. char    *apat;
  670. regexp    **srchexpp;
  671. int    c;
  672. int    fromscreen;
  673. {
  674.     int status;
  675.  
  676.     /* Read a pattern.  Either we get one,
  677.      * or we don't, and use the previous pattern.
  678.      * Then, if it's the search string, make a reversed pattern.
  679.      */
  680.     if (fromscreen) {
  681.         status = screen_string(apat, NPAT, _ident);
  682.         if (status != TRUE)
  683.             return status;
  684.     } else {
  685.         /* don't expand #, %, :, and never process backslashes
  686.             since they're handled by regexp directly for the
  687.             search pattern, and in delins() for the replacement
  688.             pattern */
  689.          status = kbd_string(prompt, apat, NPAT, c, NO_EXPAND, FALSE );
  690.     }
  691.      if (status == TRUE) {
  692.         if (srchexpp) {    /* If doing the search string, compile it */
  693.             if (*srchexpp)
  694.                 free((char *)(*srchexpp));
  695.             *srchexpp = regcomp(pat, b_val(curbp, MDMAGIC));
  696.             if (!*srchexpp)
  697.                 return FALSE;
  698.         }
  699.     } else if (status == FALSE && *apat != 0) { /* Old one */
  700.         status = TRUE;
  701.     }
  702.  
  703.     return status;
  704. }
  705.  
  706. /*
  707.  * savematch -- We found the pattern?  Let's save it away.
  708.  */
  709.  
  710. void
  711. savematch(curpos,matchlen)
  712. MARK curpos;        /* last match */
  713. int matchlen;
  714. {
  715.     static    patlen = -1;    /* length of last malloc */
  716.  
  717.     /* free any existing match string */
  718.     if (patmatch == NULL || patlen < matchlen) {
  719.         if (patmatch)
  720.             free(patmatch);
  721.         /* attempt to allocate a new one */
  722.         patmatch = malloc(patlen = matchlen + 20);
  723.         if (patmatch == NULL)
  724.             return;
  725.     }
  726.  
  727.     strncpy(patmatch, &curpos.l->l_text[curpos.o], matchlen);
  728.  
  729.     /* null terminate the match string */
  730.     patmatch[matchlen] = '\0';
  731. }
  732.  
  733. void
  734. scanboundry(wrapok,dot,dir)
  735. int wrapok;
  736. MARK dot;
  737. int dir;
  738. {
  739.     if (wrapok) {
  740.         nextch(&dot,dir);
  741.         scanboundpos = dot;
  742.     } else {
  743.         scanboundpos = curbp->b_line;
  744.     }
  745. }
  746.  
  747. /*
  748.  * nextch -- advance/retreat the given mark
  749.  *  will wrap, and doesn't set motion flags
  750.  */
  751. void
  752. nextch(pdot, dir)
  753. MARK    *pdot;
  754. int    dir;
  755. {
  756.     register LINE    *curline;
  757.     register int    curoff;
  758.  
  759.     curline = pdot->l;
  760.     curoff = pdot->o;
  761.     if (dir == FORWARD) {
  762.         if (curoff == llength(curline)) {
  763.             curline = lforw(curline);    /* skip to next line */
  764.             curoff = 0;
  765.         } else {
  766.             curoff++;
  767.         }
  768.     } else {
  769.         if (curoff == 0) {
  770.             curline = lback(curline);
  771.             curoff = llength(curline);
  772.         } else {
  773.             curoff--;
  774.         }
  775.     }
  776.     pdot->l = curline;
  777.     pdot->o = curoff;
  778. }
  779.  
  780.  
  781. /* simple finder -- give it a compiled regex, a direction, and it takes you
  782.     there if it can.  no wrapping allowed  */
  783. int
  784. findpat(f,n,exp,direc)
  785. int f, n;
  786. regexp *exp;
  787. int direc;
  788. {
  789.     int s;
  790.     MARK savepos;
  791.  
  792.     if (!exp)
  793.         return FALSE;
  794.  
  795.     if (!f) n = 1;
  796.  
  797.     s = TRUE;
  798.     scanboundry(FALSE,savepos,0);
  799.     while (s == TRUE && n--) {
  800.         savepos = DOT;
  801.         s = (direc == FORWARD) ? forwchar(TRUE,1) : backchar(TRUE,1);
  802.         if (s == TRUE)
  803.             s = scanner(exp, direc, FALSE);
  804.     }
  805.     if (s != TRUE)
  806.         DOT = savepos;
  807.  
  808.     return s;
  809. }
  810.  
  811.