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