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