home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2879 / search.c
Encoding:
C/C++ Source or Header  |  1991-02-28  |  29.3 KB  |  984 lines

  1. /*
  2. *       Search commands.
  3. * The functions in this file implement the
  4. * search commands (both plain and incremental searches
  5. * are supported) and the query-replace command.
  6. */
  7. #include    "def.h"
  8.  
  9. char    replaceit ();
  10. char    forwsrch ();
  11. char    backsrch ();
  12. char    readpattern ();
  13. void    next_pat ();
  14.  
  15. extern    char    MSG_sch_str[];
  16. extern    char    MSG_bsrc_str[];
  17. extern    char    MSG_rpl_str[];
  18. extern    char    MSG_pat_fnd[];
  19. extern    char    MSG_no_srch[];
  20. extern    char    MSG_fnd_at[];
  21. extern    char    MSG_no_rpl[];
  22. extern    char    MSG_1_rpl[];
  23. extern    char    MSG_n_rpl[];
  24. extern    char    MSG_srcing[];
  25. extern    char    MSG_curs[];
  26. extern    char    MSG_cmp_end[];
  27. extern    char    MSG_cmp_term[];
  28. extern    char    MSG_cmp_dif[];
  29. extern    char    MSG_only_2[];
  30. extern    char    MSG_cmping[];
  31. extern    char    MSG_not_fnd[];
  32. #if RUNCHK
  33. extern    char    ERR_rdpat[];
  34. extern    char    ERR_mask[];
  35. extern    char    ERR_m_cl[];
  36. #endif
  37.  
  38. #include    "lintfunc.dec"
  39. #define CCHR(x)     ((x)-'@')
  40.  
  41. #define SRCH_BEGIN  (0)         /* Search sub-codes.    */
  42. #define SRCH_FORW   (-1)
  43. #define SRCH_BACK   (-2)
  44. #define SRCH_PREV   (-3)
  45. #define SRCH_NEXT   (-4)
  46. #define SRCH_NOPR   (-5)
  47. #define SRCH_ACCM   (-6)
  48.  
  49. typedef struct
  50. {
  51.     int     s_code;
  52.             LINE * s_dotp;
  53.     short   s_doto;
  54. }SRCHCOM;
  55.  
  56. #define MAX_PAT 260
  57.  
  58. extern  ROW_FMT hex_s_8_fmt;
  59. extern  ROW_FMT ascii_s_fmt;
  60.  
  61. bool    recall_flag = FALSE;
  62. bool    read_pat_mode = FALSE;
  63. bool    srch_mode = FALSE;
  64. bool    rplc_mode = FALSE;
  65. bool    dont_repeat = FALSE;    /* used to prevent toggling commands from */
  66.                                 /* failing in read_pattern */
  67. static  char    srch_patb[MAX_PAT];
  68. static  char    srch_maskb[MAX_PAT];
  69. static  char    rplc_patb[MAX_PAT];
  70. static  char    rplc_maskb[MAX_PAT];
  71.  
  72. static  LINE    *srch_pat = (LINE *)srch_patb;
  73. static  LINE    *srch_mask = (LINE *)srch_maskb;
  74. static  LINE    *cur_pat;
  75. static  LINE    *cur_mask;
  76. static  LINE    *rplc_pat = (LINE *)rplc_patb;
  77. static  LINE    *rplc_mask = (LINE *)rplc_maskb;
  78.  
  79. static  int     old_srch_pat_size = 0;/* for pattern recall */
  80. static  int     old_rplc_pat_size = 0;
  81. static  ROW_FMT *old_fmt = &hex_s_8_fmt;
  82.  
  83.         char    *cur_prompt;
  84.  
  85. static  SRCHCOM cmds[NSRCH];
  86. static int  cip;
  87.  
  88. int     srch_lastdir = SRCH_NOPR;/* Last search flags.   */
  89.  
  90. /*
  91. * Search forward.
  92. * Get a search string from the user, and search for it,
  93. * starting at ".". If found, "." gets moved to the
  94. * first matched character, and display does all the hard stuff.
  95. * If not found, it just prints a message.
  96. */
  97. char    forwsearch ()
  98. {
  99.     register char   s;
  100.     char    buf[80], buf1[30];
  101.  
  102.     srch_mode = TRUE;
  103.     rplc_mode = FALSE;
  104.     cur_prompt = MSG_sch_str;
  105.     if ((s = readpattern ()) != TRUE)
  106.         {
  107.         srch_mode = FALSE;
  108.         eerase ();  /* clear message line */
  109.         return (s);
  110.         }
  111.     if (forwsrch () == FALSE)
  112.         {
  113.         writ_echo (MSG_not_fnd);
  114.         srch_mode = FALSE;
  115.         return (FALSE);
  116.         }
  117.     srch_lastdir = SRCH_FORW;
  118.     curwp -> w_flag |= WFMODE;  /* update mode line */
  119.     curwp -> w_unit_offset = 0;
  120.     /* build format */
  121.     sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
  122.     sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
  123.                 curwp -> w_doto);
  124.     writ_echo (buf);
  125.     srch_mode = FALSE;
  126.     return (TRUE);
  127. }
  128.  
  129.  
  130. /*
  131. * Reverse search.
  132. * Get a search string from the  user, and search, starting at "."
  133. * and proceeding toward the front of the buffer. If found "." is left
  134. * pointing at the first character of the pattern [the last character that
  135. * was matched].
  136. */
  137. char    backsearch ()
  138. {
  139.     register char   s;
  140.     char    buf[80], buf1[30];
  141.  
  142.     srch_mode = TRUE;
  143.     rplc_mode = FALSE;
  144.     cur_prompt = MSG_bsrc_str;
  145.     if ((s = readpattern ()) != TRUE)
  146.         {
  147.         srch_mode = FALSE;
  148.         eerase ();  /* clear message line */
  149.         return (s);
  150.         }
  151.     if (backsrch () == FALSE)
  152.         {
  153.         writ_echo (MSG_not_fnd);
  154.         srch_mode = FALSE;
  155.         return (FALSE);
  156.         }
  157.     srch_lastdir = SRCH_BACK;
  158.     curwp -> w_flag |= WFMODE;  /* update mode line */
  159.     curwp -> w_unit_offset = 0;
  160.     sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
  161.     sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
  162.                 curwp -> w_doto);
  163.     writ_echo (buf);
  164.     srch_mode = FALSE;
  165.     return (TRUE);
  166. }
  167.  
  168.  
  169. /* 
  170. * Search again, using the same search string
  171. * and direction as the last search command. The direction
  172. * has been saved in "srch_lastdir", so you know which way
  173. * to go.
  174. */
  175. char    searchagain ()
  176. {
  177.     char    buf[80], buf1[30];
  178.     long    dot_pos;
  179.     srch_mode = TRUE;
  180.     rplc_mode = FALSE;
  181.  
  182.     dot_pos = DOT_POS(curwp);
  183.     if (srch_lastdir == SRCH_FORW)
  184.         {
  185.         /* advance one unit so we don't find the same thing again */
  186.         move_ptr (curwp, dot_pos + 1, TRUE, FALSE, FALSE);
  187.         if (forwsrch () == FALSE)
  188.             {    /* go back to orig pt */
  189.             move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
  190.             writ_echo (MSG_not_fnd);
  191.             srch_mode = FALSE;
  192.             return (FALSE);
  193.             }
  194.         curwp -> w_flag |= WFMODE;  /* update mode line */
  195.         curwp -> w_unit_offset = 0;
  196.         sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
  197.         sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
  198.                     curwp -> w_doto);
  199.         writ_echo (buf);
  200.         srch_mode = FALSE;
  201.         return (TRUE);
  202.         }
  203.     if (srch_lastdir == SRCH_BACK)
  204.         {
  205.         /* step back one unit so we don't find the same thing again */
  206.         move_ptr (curwp, dot_pos - 1, TRUE, FALSE, FALSE);
  207.         if (backsrch () == FALSE)
  208.             {    /* go back to orig pt */
  209.             move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
  210.             writ_echo (MSG_not_fnd);
  211.             srch_mode = FALSE;
  212.             return (FALSE);
  213.             }
  214.         curwp -> w_flag |= WFMODE;  /* update mode line */
  215.         curwp -> w_unit_offset = 0;
  216.         sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
  217.         sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
  218.                     curwp -> w_doto);
  219.         writ_echo (buf);
  220.         srch_mode = FALSE;
  221.         return (TRUE);
  222.         }
  223.     writ_echo (MSG_no_srch);
  224.     srch_mode = FALSE;
  225.     return (FALSE);
  226. }
  227.  
  228.  
  229. /*
  230. * Query Replace.
  231. *   Replace strings selectively.  Does a search and replace operation.
  232. *   A space or a comma replaces the string, a period replaces and quits,
  233. *   an n doesn't replace, a C-G quits.
  234. * (note typical hack to add a function with minimal code) 
  235. */
  236. char    queryrepl (f, n, k)
  237. {
  238.  
  239.     register char   s;
  240.  
  241.     srch_mode = FALSE;
  242.     rplc_mode = TRUE;
  243.     cur_prompt = MSG_sch_str;
  244.     if (s = readpattern ())
  245.         {
  246.         replaceit ();
  247.         }
  248.     srch_mode = FALSE;
  249.     rplc_mode = FALSE;
  250.     return (s);
  251. }
  252.  
  253.  
  254. char    replaceit ()
  255. {
  256.     register int    s;
  257.     int     rcnt = 0;           /* Replacements made so far */
  258.     int     plen;               /* length of found string   */
  259.     int     rlen;               /* length of replace string   */
  260.     long    abs_dot_p;          /* absolute dot position */
  261.     long    abs_mark_p;         /* absolute mark position */
  262.     char    buf[80], buf1[80];
  263.  
  264.  /* 
  265.   * Search forward repeatedly, checking each time whether to insert
  266.   * or not.  The "!" case makes the check always true, so it gets put
  267.   * into a tighter loop for efficiency.
  268.   *
  269.   * If we change the line that is the remembered value of dot, then
  270.   * it is possible for the remembered value to move.  This causes great
  271.   * pain when trying to return to the non-existant line.
  272.   *
  273.   * possible fixes:
  274.   * 1) put a single, relocated marker in the WINDOW structure, handled
  275.   *    like mark.  The problem now becomes a what if two are needed...
  276.   * 2) link markers into a list that gets updated (auto structures for
  277.   *    the nodes)
  278.   * 3) Expand the mark into a stack of marks and add pushmark, popmark.
  279.   */
  280.  
  281.     plen = srch_pat -> l_used;
  282.     rlen = rplc_pat -> l_used;
  283.  
  284.     abs_dot_p = DOT_POS(curwp); /* save current dot position */
  285.     abs_mark_p = MARK_POS(curwp);
  286.  
  287.     while (forwsrch () == TRUE)
  288.         {
  289. retry: 
  290.         sprintf (buf1, MSG_fnd_at, R_POS_FMT(curwp));
  291.         sprintf (buf, buf1, DOT_POS(curwp));
  292.         writ_echo (buf);
  293.         curwp -> w_flag |= WFMODE;  /* update mode line */
  294.         update ();
  295.         switch (ttgetc ())
  296.             {
  297.             case 'r':
  298.             case 'R':
  299.             case ' ': 
  300.             case ',': 
  301.                 /* update has fixedup the dot position so move to found byte */
  302.                 /* go and do the replace */
  303.                 if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
  304.                     return (FALSE);
  305.                 /* begin searching after replace string */
  306.                 move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
  307.                 rcnt++;
  308.                 break;
  309.  
  310.             case 'o':
  311.             case 'O':
  312.             case '.': 
  313.                 if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
  314.                     return (FALSE);
  315.                 /* begin searching after replace string */
  316.                 move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
  317.                 rcnt++;
  318.                 goto stopsearch;
  319.  
  320.             case 'q':
  321.             case 'Q':
  322.             case CCHR ('G'): 
  323.                 ctrlg (FALSE, 0, KRANDOM);
  324.                 goto stopsearch;
  325.  
  326.             case 'a':
  327.             case 'A':
  328.             case '!': 
  329.                 do
  330.                     {
  331.                     if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
  332.                         return (FALSE);
  333.                     /* begin searching after replace string */
  334.                     move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
  335.                     rcnt++;
  336.                     }
  337.                 while (forwsrch () == TRUE);
  338.                 goto stopsearch;
  339.  
  340.             case 's':
  341.             case 'S':
  342.             case 'n': 
  343.                 /* begin searching after this byte */
  344.                 move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
  345.                 break;
  346.  
  347.             default:
  348.                 ttbeep ();
  349.                 goto retry;
  350.             }
  351.         }
  352.  
  353. stopsearch: 
  354.     move_ptr (curwp, abs_dot_p, TRUE, TRUE, FALSE);
  355.     if (curwp -> w_markp != NULL)
  356.         {
  357.         swapmark ();
  358.         /* insure that the mark points to the same byte as before */
  359.         if (abs_mark_p > abs_dot_p)
  360.             move_ptr (curwp, abs_mark_p + rlen - plen, TRUE, FALSE, FALSE);
  361.         else
  362.             move_ptr (curwp, abs_mark_p, TRUE, FALSE, FALSE);
  363.         swapmark ();
  364.         }
  365.     curwp -> w_flag |= WFHARD;
  366.     update ();
  367.     if (rcnt == 0)
  368.         {
  369.         writ_echo (MSG_no_rpl);
  370.         }
  371.     else if (rcnt == 1)
  372.         {
  373.         writ_echo (MSG_1_rpl);
  374.         }
  375.     else
  376.         {
  377.         sprintf (buf1, MSG_n_rpl, R_POS_FMT(curwp));
  378.         sprintf (buf, buf1, (ulong)rcnt);
  379.         writ_echo (buf);
  380.         }
  381.     flush_count += rcnt;        /* jam for auto write buffers */
  382.     return (TRUE);
  383. }
  384.  
  385.  
  386. /*
  387. * This routine does the real work of a
  388. * forward search. The pattern is sitting in the external
  389. * variable "srch_pat" the mask if in "srch_mask".
  390. * If found, dot is updated, the window system
  391. * is notified of the change, and TRUE is returned. If the
  392. * string isn't found, FALSE is returned.
  393. */
  394. char    forwsrch ()
  395. {
  396.     register    LINE    *save_dotp, *save2_dotp;
  397.     register    int     save_doto, save2_doto;
  398.     register    char    *pat_ptr, *mask_ptr;
  399.     register    int     i, j, pat_cnt;
  400.     register    char    first_pat, first_mask;
  401.     char        buf[80], buf1[40];
  402.  
  403.     save_dotp = curwp -> w_dotp;    /* save dot position for later */
  404.     save_doto = curwp -> w_doto;
  405.     pat_ptr = srch_pat -> l_text;
  406.     mask_ptr = srch_mask -> l_text;
  407.     pat_cnt = srch_pat -> l_used;
  408.     first_mask = mask_ptr[0];
  409.     first_pat = pat_ptr[0] | first_mask;
  410.     j =  (int)DOT_POS(curwp) & 0xffff;
  411.  
  412.     do 
  413.     {
  414.         if ((j++ & 0x2ff) == 0)
  415.         {
  416.             sprintf (buf1, MSG_srcing, R_POS_FMT(curwp));
  417.             sprintf (buf, buf1, DOT_POS(curwp));
  418.             writ_echo (buf);
  419.             /* check if we should quit */
  420.             if (ttkeyready ())
  421.             {
  422.                 ttgetc ();  /* through away char that was struck */
  423.                 break;
  424.             }
  425.         }   
  426.         if (first_pat == 
  427.             ((DOT_CHAR(curwp) | first_mask) & 0xff))
  428.         {
  429.             save2_dotp = curwp -> w_dotp;    /* save dot position for later */
  430.             save2_doto = curwp -> w_doto;
  431.             for (i = 1; i < pat_cnt; i++)
  432.             {
  433.                 if (!move_ptr (curwp, 1L, TRUE, FALSE, TRUE) ||
  434.                     ((pat_ptr[i] & ~mask_ptr[i]) != 
  435.                     (DOT_CHAR(curwp) & ~mask_ptr[i])))
  436.                 {   /* not found */
  437.                     curwp -> w_dotp = save2_dotp;  /* restore dot position */
  438.                     curwp -> w_doto = save2_doto;
  439.                     break;
  440.                 }
  441.             }
  442.             if (i == pat_cnt)   /* found */
  443.             {   /* move back to the first matching unit */
  444.                 move_ptr (curwp, -(long)pat_cnt + 1, TRUE, FALSE, TRUE);
  445.                 wind_on_dot (curwp);
  446.                 return (TRUE);
  447.             }
  448.         }
  449.     }
  450.     while (move_ptr (curwp, 1L, TRUE, FALSE, TRUE));
  451.  
  452.     curwp -> w_dotp = save_dotp;  /* restore dot position */
  453.     curwp -> w_doto = save_doto;
  454.     return (FALSE);
  455. }
  456.  
  457.  
  458. /*
  459. * This routine does the real work of a
  460. * backward search. The pattern is sitting in the external
  461. * variable "srch_pat". If found, dot is updated, the window system
  462. * is notified of the change, and TRUE is returned. If the
  463. * string isn't found, FALSE is returned.
  464. */
  465. char    backsrch ()
  466. {
  467.     register    LINE    *save_dotp, *save_p;
  468.     register    int     save_doto, save_o;
  469.     register    char    *pat_ptr, *mask_ptr;
  470.     register    int     i, j, pat_cnt;
  471.     register    char    first_pat, first_mask;
  472.     char        buf[80], buf1[40];
  473.  
  474.     save_dotp = curwp -> w_dotp;    /* save dot position for later */
  475.     save_doto = curwp -> w_doto;
  476.     pat_ptr = srch_pat -> l_text;
  477.     mask_ptr = srch_mask -> l_text;
  478.     pat_cnt = srch_pat -> l_used;
  479.     first_mask = mask_ptr[0];
  480.     first_pat = pat_ptr[0] | first_mask;
  481.     j =  (int)DOT_POS(curwp) & 0xffff;
  482.  
  483.     do 
  484.     {
  485.         /* check if we should quit */
  486.         if (ttkeyready ())
  487.         {
  488.             ttgetc ();  /* through away char that was struck */
  489.             break;
  490.         }
  491.         if ((j-- & 0x2ff) == 0)
  492.         {
  493.             sprintf (buf1, MSG_srcing, R_POS_FMT(curwp));
  494.             sprintf (buf, buf1, DOT_POS(curwp));
  495.             writ_echo (buf);
  496.         }   
  497.         if (first_pat == 
  498.             (curwp -> w_dotp -> l_text[curwp -> w_doto] | first_mask))
  499.         {
  500.  
  501.             save_p = curwp -> w_dotp; 
  502.             save_o = curwp -> w_doto;
  503.             for (i = 1; i < pat_cnt; i++)
  504.             {
  505.                 if (!move_ptr (curwp, 1L, TRUE, FALSE, TRUE) ||
  506.                    ((pat_ptr[i] & ~mask_ptr[i]) != 
  507.                    (DOT_CHAR(curwp) & ~mask_ptr[i])))
  508.                 {   /* not found */
  509.                     curwp -> w_dotp = save_p;   /* restore ptr to continue */ 
  510.                     curwp -> w_doto = save_o;
  511.                     break;
  512.                 }
  513.             }
  514.             if (i == pat_cnt)   /* found */
  515.             {   /* move back to the first matching unit */
  516.                 move_ptr (curwp, -(long)pat_cnt + 1, TRUE, FALSE, TRUE);
  517.                 wind_on_dot (curwp);
  518.                 return (TRUE);
  519.             }
  520.         }
  521.     }
  522.     while (move_ptr (curwp, -1L, TRUE, FALSE, TRUE));
  523.  
  524.     curwp -> w_dotp = save_dotp;  /* restore dot position */
  525.     curwp -> w_doto = save_doto;
  526.     return (FALSE);
  527. }
  528.  
  529. /*
  530. * Read a pattern.
  531. * Display and edit in the form of the current window.
  532. * Slide the displayed line back and forth when the cursor hits a boundary.
  533. * Manage the mask buffer. When a '*' (wild card) is entered mask all
  534. * bits in that unit and display all '?'s.
  535. */
  536. char    readpattern ()
  537. {
  538.     int     cod, mask_cod, curs_pos, curs_pos1, prt_siz, i, doto, loff;
  539.     WINDOW  srch_wind, *save_wind;
  540.     BUFFER  srch_buf, *save_buf;
  541.     LINE    head_line, *line_ptr1, *line_ptr2;
  542.     char    disp_buf[120],
  543.             mask_buf[120],
  544.             buf1[80],
  545.             siz_prompt2,
  546.             r_type,
  547.             first_time,
  548.             u_off,
  549.             stat;
  550.  
  551.  
  552.     save_wind = curwp;          /* save current window for later */
  553.     save_buf = curbp;       /* save current buffer for later */
  554.  
  555.     curwp = &srch_wind;         /* search window is current window during
  556.                                    search */
  557.     curbp = &srch_buf;
  558.     cur_pat = srch_pat;         /* set global variables for LINE finctions */
  559.     cur_mask = srch_mask;
  560.  
  561.     recall_flag = FALSE;
  562.     first_time = TRUE;
  563.     read_pat_mode = TRUE;
  564.     curwp -> w_wndp = NULL;
  565.     curwp -> w_bufp = curbp;
  566.     curwp -> w_linep = cur_pat;
  567.     curwp -> w_loff = 0;
  568.     curwp -> w_dotp = cur_pat;
  569.     curwp -> w_doto = 0;
  570.     curwp -> w_unit_offset = 0;
  571.     curwp -> w_toprow = 24;
  572.     curwp -> w_ntrows = 1;
  573.     curwp -> w_intel_mode = save_wind -> w_intel_mode;
  574.     curwp -> w_disp_shift = 0;
  575.     if (R_TYPE(save_wind) == TEXT)
  576.         curwp -> w_fmt_ptr = &ascii_s_fmt;
  577.     else
  578.         curwp -> w_fmt_ptr = save_wind -> w_fmt_ptr -> r_srch_fmt;
  579.  
  580.     srch_buf.b_bufp = NULL;
  581.     srch_buf.b_linep = &head_line;
  582.     srch_buf.b_unit_offset = 0;    /* unit offset   pvr */
  583.     srch_buf.b_markp = NULL;
  584.     srch_buf.b_marko = 0;
  585.     srch_buf.b_flag = 0;
  586.     srch_buf.b_nwnd = 1;
  587.     srch_buf.b_fname[0] = 0;
  588.     srch_buf.b_bname[0] = 0;
  589.  
  590.     head_line.l_fp = cur_pat;
  591.     head_line.l_bp = cur_pat;
  592.     head_line.l_file_offset = 0;    /* pvr */
  593.     head_line.l_used = 0;
  594.     head_line.l_size = 0;
  595.         
  596.     cur_pat -> l_fp = &head_line;
  597.     cur_pat -> l_bp = &head_line;
  598.     cur_pat -> l_size = 266;    /* leave some extra past 256 */
  599.     cur_pat -> l_used = 0;
  600.     cur_pat -> l_file_offset = 0;
  601.  
  602.     cur_mask -> l_fp = &head_line;
  603.     cur_mask -> l_bp = &head_line;
  604.     cur_mask -> l_size = 266;   /* leave some extra past 256 */
  605.     cur_mask -> l_used = 0;
  606.     cur_mask -> l_file_offset = 0;
  607.  
  608.     rplc_pat -> l_fp = &head_line;
  609.     rplc_pat -> l_bp = &head_line;
  610.     rplc_pat -> l_size = 266;    /* leave some extra past 256 */
  611.     rplc_pat -> l_used = 0;
  612.     rplc_pat -> l_file_offset = 0;
  613.  
  614.     rplc_mask -> l_fp = &head_line;
  615.     rplc_mask -> l_bp = &head_line;
  616.     rplc_mask -> l_size = 266;   /* leave some extra past 256 */
  617.     rplc_mask -> l_used = 0;
  618.     rplc_mask -> l_file_offset = 0;
  619.  
  620.     sprintf (buf1, MSG_curs, cur_prompt, R_BYTE_FMT(curwp),
  621.                  R_BYTE_FMT(curwp), R_BYTE_FMT(curwp));
  622.     sprintf (disp_buf, buf1, curwp -> w_doto,
  623.         curwp -> w_fmt_ptr -> r_chr_per_u - curwp -> w_unit_offset - 1,
  624.         curwp -> w_dotp -> l_used);
  625.  
  626.     siz_prompt2 = strlen (disp_buf); /* save prompt length for later */
  627.  
  628.     for (i = siz_prompt2; i < NCOL; i++)    /* clear rest of buffer */
  629.         disp_buf [i] = ' ';
  630.  
  631.     writ_echo (disp_buf);
  632.  
  633.     r_type = R_TYPE(curwp);
  634.  
  635.     while (TRUE)
  636.         {
  637.         /* position cursor */
  638.         curs_pos = curwp -> w_doto - curwp -> w_loff;
  639.         if (curwp -> w_fmt_ptr -> r_size == 1)
  640.             {
  641.             curs_pos >>= 1;
  642.             }
  643.         else if (curwp -> w_fmt_ptr -> r_size == 3)
  644.             {
  645.             curs_pos >>= 2;
  646.             }
  647.         curs_pos1 = curwp -> w_fmt_ptr -> r_positions[curs_pos] + 
  648.                     curwp -> w_unit_offset + siz_prompt2;
  649.         ttmove (nrow - 1, curs_pos1);
  650.         ttflush ();
  651.         
  652.         cod = getkey ();
  653.  
  654.         if (cod == 0x014D)  /* check for return */
  655.             {
  656.             if ((rplc_mode == TRUE) && (cur_prompt == MSG_sch_str))
  657.                 {
  658.                 next_pat ();
  659.                 dont_repeat = FALSE;    /* fix up */
  660.                 goto next_loop;
  661.                 }
  662.             else
  663.                 {
  664.                 old_srch_pat_size = srch_pat -> l_used; /* save for restore */
  665.                 if (rplc_mode == TRUE)
  666.                    old_rplc_pat_size = rplc_pat -> l_used;
  667.  
  668.                 old_fmt = curwp -> w_fmt_ptr;
  669.                 curwp = save_wind;  /* restore current window */
  670.                 curbp = save_buf;  /* restore current buffer */
  671.                 read_pat_mode = FALSE;
  672.                 return (TRUE);
  673.                 }
  674.             }
  675.  
  676.         if ((cod >= ' ') && (cod < 0x7f)) 
  677.             {
  678.             if ((r_type == ASCII) || (r_type == EBCDIC))
  679.                 {
  680.                 mask_cod = '9'; /* use 9 as dummy char that will get through */
  681.                 }
  682.             else if (r_type == DECIMAL)
  683.                 {
  684.                 mask_cod = '0'; /* clear mask byte */
  685.                 }
  686.             else if (cod == '?')
  687.                 {
  688.                 cod = '0';
  689.                 switch (r_type)
  690.                     {
  691.                     case OCTAL:
  692.                         if (curwp -> w_unit_offset == 0)    /* if first char */
  693.                             {
  694.                             if (R_SIZE(curwp) == WORDS)
  695.                                 mask_cod = '1';
  696.                             else
  697.                                 mask_cod = '3';
  698.                             }
  699.                         else
  700.                             mask_cod = '7';
  701.                         break;
  702.     
  703.                     case HEX:
  704.                         mask_cod = 'F';
  705.                         break;
  706.     
  707.                     case BINARY:
  708.                         mask_cod = '1';
  709.                         break;
  710. #if RUNCHK
  711.                     default:
  712.                         printf (ERR_rdpat);
  713.                         break;
  714. #endif
  715.                     }
  716.                 }
  717.             else
  718.                 {
  719.                 mask_cod = '0';
  720.                 }        
  721.             }
  722.         else
  723.             mask_cod = cod;     /* must be control; do the same to the mask */
  724.  
  725.         /* save current dot and window positions */
  726.         doto = curwp -> w_doto;
  727.         u_off = curwp -> w_unit_offset;
  728.         loff = curwp -> w_loff;
  729.         stat = execute (cod, FALSE, 1);
  730.  
  731.         if (stat == ABORT)
  732.             {
  733.             old_srch_pat_size = srch_pat -> l_used; /* save for restore */
  734.             if (rplc_mode == TRUE)
  735.                old_rplc_pat_size = rplc_pat -> l_used;
  736.             old_fmt = curwp -> w_fmt_ptr;
  737.             curwp = save_wind;  /* restore current window */
  738.             curbp = save_buf;  /* restore current buffer */
  739.             read_pat_mode = FALSE;
  740.             return (FALSE);
  741.             }
  742.  
  743.        /* If key is recall then reset the size variables */
  744.         if (first_time)
  745.             {
  746.             first_time = FALSE;
  747.             if (recall_flag)
  748.                 {
  749.                 srch_pat -> l_used = old_srch_pat_size;
  750.                 srch_mask -> l_used = old_srch_pat_size;
  751.                 rplc_pat -> l_used = old_rplc_pat_size;
  752.                 rplc_mask -> l_used = old_rplc_pat_size;
  753.                 curwp -> w_fmt_ptr = old_fmt;
  754.                 recall_flag = FALSE;
  755.                 }
  756.             }
  757.  
  758.         /* if it was a toggling command, don't do it again */
  759.         if (!dont_repeat &&
  760.             (stat == TRUE))
  761.         {
  762.             head_line.l_fp = cur_mask;   /* point to mask */
  763.             head_line.l_bp = cur_mask;
  764.             curwp -> w_linep = cur_mask;
  765.             curwp -> w_dotp = cur_mask;
  766.             curwp -> w_loff = loff;
  767.             curwp -> w_doto = doto;
  768.             curwp -> w_unit_offset = u_off;
  769.             execute (mask_cod, FALSE, 1);
  770.     
  771.             head_line.l_fp = cur_pat;    /* restore pointers */
  772.             head_line.l_bp = cur_pat;
  773.             curwp -> w_linep = cur_pat;
  774.             curwp -> w_dotp = cur_pat;
  775.         }
  776.         else
  777.             dont_repeat = FALSE;
  778.  
  779.         /* limit at 256 bytes */
  780.         if (cur_pat -> l_used >= 256)
  781.             {
  782.             cur_mask -> l_used = 255; 
  783.             cur_pat -> l_used = 255;
  784.             if (curwp -> w_doto >= 256)
  785.                 {
  786.                 move_ptr (curwp, 255L, TRUE, TRUE, FALSE);  /* last position */
  787.                 }
  788.             }
  789.  
  790.         /* if buffer is size locked then replace pattern must be the */
  791.         /* same size as the search pattern */
  792.         if (rplc_mode && (save_buf -> b_flag & BFSLOCK))
  793.             {
  794.             rplc_pat -> l_used = srch_pat -> l_used; 
  795.             rplc_mask -> l_used = srch_pat -> l_used; 
  796.             }
  797.  
  798.         r_type = R_TYPE(curwp);
  799. #if RUNCHK
  800.         /* check that the pattern and the mask are the same size */
  801.         if (cur_pat -> l_used != cur_mask -> l_used)
  802.             {
  803.             printf (ERR_mask, cur_pat -> l_used, cur_mask -> l_used); 
  804.             }   
  805.  
  806.         /* check that in ascii mode the byte that will be set to zero */
  807.         /* is the dummy char 9 */
  808. /*        if (((r_type == ASCII) &&
  809.             (cur_mask -> l_text[curwp -> w_doto - 1] != '9'))
  810.             ||
  811.             ((r_type == EBCDIC) &&
  812.             (cur_mask -> l_text[curwp -> w_doto - 1] != to_ebcdic('9'))))
  813.             printf (ERR_m_cl);
  814. */
  815. #endif
  816.         if (((r_type == ASCII) ||
  817.             (r_type == EBCDIC)) &&
  818.            ((cod >= ' ') && (cod < 0x7f))) 
  819.             cur_mask -> l_text[doto] = 0; /* clear mask byte */
  820.  
  821. next_loop:
  822.         sprintf (buf1, MSG_curs, cur_prompt, R_BYTE_FMT(curwp),
  823.                      R_BYTE_FMT(curwp), R_BYTE_FMT(curwp));
  824.         sprintf (disp_buf, buf1, curwp -> w_doto,
  825.             curwp -> w_fmt_ptr -> r_chr_per_u - curwp -> w_unit_offset - 1,
  826.             curwp -> w_dotp -> l_used);
  827.  
  828.         siz_prompt2 = strlen (disp_buf); /* save prompt length for later */
  829.  
  830.         for (i = siz_prompt2; i < NCOL; i++)
  831.             {
  832.             disp_buf [i] = ' ';
  833.             mask_buf [i] = ' ';
  834.             }
  835.  
  836.         if ((curbp -> b_flag & BFSLOCK) &&
  837.             (rplc_pat -> l_used != srch_pat -> l_used))
  838.             {
  839.             rplc_pat -> l_used = srch_pat -> l_used;
  840.             /* if dot is past the end then move it back, replace string only */
  841.             if (DOT_POS(curwp) > srch_pat -> l_used)
  842.                 move_ptr (curwp, (long)srch_pat -> l_used, TRUE, TRUE, FALSE);
  843.             }
  844.  
  845.         wind_on_dot (curwp);
  846.  
  847.         /* figure number of bytes to convert to text */
  848.         if ((cur_pat -> l_used - curwp -> w_loff) <
  849.                  (prt_siz = curwp -> w_fmt_ptr -> r_bytes))
  850.             prt_siz = cur_pat -> l_used - curwp -> w_loff;
  851.  
  852.         bin_to_text (&cur_pat -> l_text[curwp -> w_loff],
  853.                 &disp_buf[siz_prompt2],
  854.                 prt_siz, curwp -> w_fmt_ptr);
  855.  
  856.         /* change any char to a ? if any bit is set in the mask buffer */
  857.         if ((r_type != ASCII) && (r_type != EBCDIC))
  858.             {
  859.             /* print the contents of the mask to a invisible buffer */
  860.             bin_to_text (&cur_mask -> l_text[curwp -> w_loff],
  861.                     &mask_buf[siz_prompt2],
  862.                     prt_siz, curwp -> w_fmt_ptr);
  863.  
  864.             for (i = siz_prompt2; (disp_buf[i] != 0) && (i < NCOL); i++)
  865.                 {
  866.                 if ((mask_buf[i] != '0') &&
  867.                     (mask_buf[i] != ' '))
  868.                     disp_buf[i] = '?';  
  869.                 }
  870.             }
  871.         else
  872.             {
  873.             for (i = 0; i < prt_siz; i++)
  874.                 {
  875.                 if (cur_mask -> l_text[curwp -> w_loff + i] != 0)
  876.                     disp_buf[i + siz_prompt2] = '?';  
  877.                 }
  878.             }
  879.         writ_echo (disp_buf);
  880.     }
  881. }
  882.  
  883. /*
  884. *   Recall the last contents of the search string
  885. */
  886. bool    recall ()
  887.     {
  888.     recall_flag = TRUE;
  889.     return (TRUE);
  890.     }
  891.  
  892. /*
  893. *   Switch between search pattern and replace pattern and their 
  894. *   respective masks 
  895. */
  896. void    next_pat ()
  897. {
  898.     if (cur_pat == srch_pat)
  899.     {
  900.         cur_prompt = MSG_rpl_str;
  901.         cur_pat = rplc_pat; /* point to replace pattern */
  902.         cur_mask = rplc_mask;
  903.     }
  904.     else
  905.     {
  906.         cur_prompt = MSG_sch_str;
  907.         cur_pat = srch_pat;     /* point to search pattern */
  908.         cur_mask = srch_mask;
  909.     }
  910.     curwp -> w_dotp = cur_pat;
  911.     curwp -> w_linep = cur_pat;
  912.     curbp -> b_linep -> l_fp = cur_pat;
  913.     curbp -> b_linep -> l_bp = cur_pat;
  914.  
  915.     if (curwp -> w_doto > cur_pat -> l_used)
  916.         {
  917.         curwp -> w_doto = cur_pat -> l_used;
  918.         curwp -> w_unit_offset = 0;
  919.         }
  920.     if (curwp -> w_loff > cur_pat -> l_used)
  921.         curwp -> w_loff = cur_pat -> l_used;
  922.     dont_repeat = TRUE;
  923. }
  924.  
  925. /*
  926. * Compare the contents of two windows.
  927. * There must be exactly two windows displayed.
  928. * The bytes under the cursor in each window are compared and if 
  929. * a difference is found then the loop is stopped with the dot
  930. * position in each window pointing to the difference.
  931. * The two windows can be pointing at the same or different buffers.
  932. */
  933. bool    compare ()
  934.  
  935.     {
  936.     WINDOW  *wp1, *wp2;
  937.     bool    move1, move2;
  938.     int     j;  
  939.     char    *term_str = MSG_cmp_dif;
  940.     char    buf[80], buf1[60];
  941.  
  942.     if (wheadp -> w_wndp -> w_wndp != NULL)
  943.         {
  944.         writ_echo (MSG_only_2);
  945.         return (FALSE);
  946.         }
  947.         
  948.     wp1 = wheadp;
  949.     wp2 = wheadp -> w_wndp;
  950.     j =  (int)DOT_POS(curwp) & 0xffff;
  951.  
  952.     wp1 -> w_flag |= WFMOVE;
  953.     wp2 -> w_flag |= WFMOVE;
  954.  
  955.     while (DOT_CHAR(wp1) == DOT_CHAR(wp2))
  956.         {
  957.         if ((j++ & 0xff) == 0)
  958.             {
  959.             sprintf (buf1, MSG_cmping, R_POS_FMT(curwp));
  960.             sprintf (buf, buf1, DOT_POS(curwp));
  961.             writ_echo (buf);
  962.            /* check if we should quit */
  963.            if (ttkeyready ())
  964.                 {
  965.                 ttgetc ();  /* through away char that was struck */
  966.                 term_str = MSG_cmp_term;
  967.                 break;
  968.                 }
  969.             }   
  970.         move1 = move_ptr (wp1, 1L, TRUE, FALSE, TRUE);  
  971.         move2 = move_ptr (wp2, 1L, TRUE, FALSE, TRUE);  
  972.  
  973.         if (!(move1 && move2))
  974.             {
  975.             term_str = MSG_cmp_end;
  976.             break;
  977.             }
  978.         }
  979.         writ_echo (term_str);
  980.         wind_on_dot (wp1);
  981.         wind_on_dot (wp2);
  982.         return (TRUE);
  983.     }
  984.