/*
*       Search commands.
* The functions in this file implement the
* search commands (both plain and incremental searches
* are supported) and the query-replace command.
*/
#include    "def.h"

char    replaceit ();
char    forwsrch ();
char    backsrch ();
char    readpattern ();
void    next_pat ();

extern    char    MSG_sch_str[];
extern    char    MSG_bsrc_str[];
extern    char    MSG_rpl_str[];
extern    char    MSG_pat_fnd[];
extern    char    MSG_no_srch[];
extern    char    MSG_fnd_at[];
extern    char    MSG_no_rpl[];
extern    char    MSG_1_rpl[];
extern    char    MSG_n_rpl[];
extern    char    MSG_srcing[];
extern    char    MSG_curs[];
extern    char    MSG_cmp_end[];
extern    char    MSG_cmp_term[];
extern    char    MSG_cmp_dif[];
extern    char    MSG_only_2[];
extern    char    MSG_cmping[];
extern    char    MSG_not_fnd[];
#if RUNCHK
extern    char    ERR_rdpat[];
extern    char    ERR_mask[];
extern    char    ERR_m_cl[];
#endif

#define CCHR(x)     ((x)-'@')

#define SRCH_BEGIN  (0)         /* Search sub-codes.    */
#define SRCH_FORW   (-1)
#define SRCH_BACK   (-2)
#define SRCH_PREV   (-3)
#define SRCH_NEXT   (-4)
#define SRCH_NOPR   (-5)
#define SRCH_ACCM   (-6)

typedef struct
{
	int     s_code;
	LINE * s_dotp;
	short   s_doto;
}SRCHCOM;

#define MAX_PAT 260

extern  ROW_FMT hex_s_8_fmt;
extern  ROW_FMT ascii_s_fmt;

bool    recall_flag = FALSE;
bool    read_pat_mode = FALSE;
bool    srch_mode = FALSE;
bool    rplc_mode = FALSE;
bool    dont_repeat = FALSE;    /* used to prevent toggling commands from */
/* failing in read_pattern */
static  char    srch_patb[MAX_PAT];
static  char    srch_maskb[MAX_PAT];
static  char    rplc_patb[MAX_PAT];
static  char    rplc_maskb[MAX_PAT];

static  LINE    *srch_pat = (LINE *)srch_patb;
static  LINE    *srch_mask = (LINE *)srch_maskb;
static  LINE    *cur_pat;
static  LINE    *cur_mask;
static  LINE    *rplc_pat = (LINE *)rplc_patb;
static  LINE    *rplc_mask = (LINE *)rplc_maskb;

static  int     old_srch_pat_size = 0;/* for pattern recall */
static  int     old_rplc_pat_size = 0;
static  ROW_FMT *old_fmt = &hex_s_8_fmt;

char    *cur_prompt;

int     srch_lastdir = SRCH_NOPR;/* Last search flags.   */

/*
* Search forward.
* Get a search string from the user, and search for it,
* starting at ".". If found, "." gets moved to the
* first matched character, and display does all the hard stuff.
* If not found, it just prints a message.
*/
char    forwsearch ()
{
	register char   s;
	char    buf[NCOL], buf1[NCOL];

	srch_mode = TRUE;
	rplc_mode = FALSE;
	cur_prompt = MSG_sch_str;
	if ((s = readpattern ()) != TRUE)
	{
		srch_mode = FALSE;
		eerase ();  /* clear message line */
		return (s);
	}
	if (forwsrch () == FALSE)
	{
		writ_echo (MSG_not_fnd);
		srch_mode = FALSE;
		return (FALSE);
	}
	srch_lastdir = SRCH_FORW;
	curwp -> w_flag |= WFMODE;  /* update mode line */
	curwp -> w_unit_offset = 0;
	/* build format */
	sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
	sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
	    curwp -> w_doto);
	writ_echo (buf);
	srch_mode = FALSE;
	return (TRUE);
}


/*
* Reverse search.
* Get a search string from the  user, and search, starting at "."
* and proceeding toward the front of the buffer. If found "." is left
* pointing at the first character of the pattern [the last character that
* was matched].
*/
char    backsearch ()
{
	register char   s;
	char    buf[NCOL], buf1[NCOL];

	srch_mode = TRUE;
	rplc_mode = FALSE;
	cur_prompt = MSG_bsrc_str;
	if ((s = readpattern ()) != TRUE)
	{
		srch_mode = FALSE;
		eerase ();  /* clear message line */
		return (s);
	}
	if (backsrch () == FALSE)
	{
		writ_echo (MSG_not_fnd);
		srch_mode = FALSE;
		return (FALSE);
	}
	srch_lastdir = SRCH_BACK;
	curwp -> w_flag |= WFMODE;  /* update mode line */
	curwp -> w_unit_offset = 0;
	sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
	sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
	    curwp -> w_doto);
	writ_echo (buf);
	srch_mode = FALSE;
	return (TRUE);
}


/* 
* Search again, using the same search string
* and direction as the last search command. The direction
* has been saved in "srch_lastdir", so you know which way
* to go.
*/
char    searchagain ()
{
	char    buf[NCOL], buf1[NCOL];
	long    dot_pos;
	srch_mode = TRUE;
	rplc_mode = FALSE;

	dot_pos = DOT_POS(curwp);
	if (srch_lastdir == SRCH_FORW)
	{
		/* advance one unit so we don't find the same thing again */
		move_ptr (curwp, dot_pos + 1, TRUE, FALSE, FALSE);
		if (forwsrch () == FALSE)
		{    /* go back to orig pt */
			move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
			writ_echo (MSG_not_fnd);
			srch_mode = FALSE;
			return (FALSE);
		}
		curwp -> w_flag |= WFMODE;  /* update mode line */
		curwp -> w_unit_offset = 0;
		sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
		sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
		    curwp -> w_doto);
		writ_echo (buf);
		srch_mode = FALSE;
		return (TRUE);
	}
	if (srch_lastdir == SRCH_BACK)
	{
		/* step back one unit so we don't find the same thing again */
		move_ptr (curwp, dot_pos - 1, TRUE, FALSE, FALSE);
		if (backsrch () == FALSE)
		{    /* go back to orig pt */
			move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
			writ_echo (MSG_not_fnd);
			srch_mode = FALSE;
			return (FALSE);
		}
		curwp -> w_flag |= WFMODE;  /* update mode line */
		curwp -> w_unit_offset = 0;
		sprintf (buf1, MSG_pat_fnd, R_POS_FMT(curwp));
		sprintf (buf, buf1, curwp -> w_dotp -> l_file_offset +
		    curwp -> w_doto);
		writ_echo (buf);
		srch_mode = FALSE;
		return (TRUE);
	}
	writ_echo (MSG_no_srch);
	srch_mode = FALSE;
	return (FALSE);
}


/*
* Query Replace.
*   Replace strings selectively.  Does a search and replace operation.
*   A space or a comma replaces the string, a period replaces and quits,
*   an n doesn't replace, a C-G quits.
* (note typical hack to add a function with minimal code) 
*/
char    queryrepl (f, n, k)
{

	register char   s;

	srch_mode = FALSE;
	rplc_mode = TRUE;
	cur_prompt = MSG_sch_str;
	if (s = readpattern ())
	{
		replaceit ();
	}
	srch_mode = FALSE;
	rplc_mode = FALSE;
	return (s);
}


char    replaceit ()
{
	int     rcnt = 0;           /* Replacements made so far */
	int     plen;               /* length of found string   */
	int     rlen;               /* length of replace string   */
	long    abs_dot_p;          /* absolute dot position */
	long    abs_mark_p;         /* absolute mark position */
	char    buf[NCOL], buf1[NCOL];

	/* 
  * Search forward repeatedly, checking each time whether to insert
  * or not.  The "!" case makes the check always true, so it gets put
  * into a tighter loop for efficiency.
  *
  * If we change the line that is the remembered value of dot, then
  * it is possible for the remembered value to move.  This causes great
  * pain when trying to return to the non-existant line.
  *
  * possible fixes:
  * 1) put a single, relocated marker in the WINDOW structure, handled
  *    like mark.  The problem now becomes a what if two are needed...
  * 2) link markers into a list that gets updated (auto structures for
  *    the nodes)
  * 3) Expand the mark into a stack of marks and add pushmark, popmark.
  */

	plen = srch_pat -> l_used;
	rlen = rplc_pat -> l_used;

	abs_dot_p = DOT_POS(curwp); /* save current dot position */
	if (curwp->w_markp != NULL)	/* mark may not be set */
		abs_mark_p = MARK_POS(curwp);

	while (forwsrch () == TRUE)
	{
retry:
		sprintf (buf1, MSG_fnd_at, R_POS_FMT(curwp));
		sprintf (buf, buf1, DOT_POS(curwp));
		writ_echo (buf);
		curwp -> w_flag |= WFMODE;  /* update mode line */
		update ();
		switch (ttgetc ())
		{
		case 'r':
		case 'R':
		case ' ':
		case ',':
			/* update has fixedup the dot position so move to found byte */
			/* go and do the replace */
			if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
				return (FALSE);
			/* begin searching after replace string */
			move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
			rcnt++;
			break;

		case 'o':
		case 'O':
		case '.':
			if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
				return (FALSE);
			/* begin searching after replace string */
			move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
			rcnt++;
			goto stopsearch;

		case 'q':
		case 'Q':
		case CCHR ('G'):
			ctrlg (FALSE, 0, KRANDOM);
			goto stopsearch;

		case 'a':
		case 'A':
		case '!':
			do
			{
				if (lrepl_str (plen, rplc_pat, rplc_mask) == FALSE)
					return (FALSE);
				/* begin searching after replace string */
				move_ptr (curwp, (long)rlen, TRUE, FALSE, TRUE);
				rcnt++;
			}                while (forwsrch () == TRUE);
			goto stopsearch;

		case 's':
		case 'S':
		case 'n':
			/* begin searching after this byte */
			move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
			break;

		default:
			ttbeep ();
			goto retry;
		}
	}

stopsearch:
	move_ptr (curwp, abs_dot_p, TRUE, TRUE, FALSE);
	if (curwp -> w_markp != NULL)
	{
		swapmark ();
		/* insure that the mark points to the same byte as before */
		if (abs_mark_p > abs_dot_p)
			move_ptr (curwp, abs_mark_p + rlen - plen, TRUE, FALSE, FALSE);
		else
			move_ptr (curwp, abs_mark_p, TRUE, FALSE, FALSE);
		swapmark ();
	}
	curwp -> w_flag |= WFHARD;
	update ();
	if (rcnt == 0)
	{
		writ_echo (MSG_no_rpl);
	}
	else if (rcnt == 1)
	{
		writ_echo (MSG_1_rpl);
	}
	else
	{
		sprintf (buf1, MSG_n_rpl, R_POS_FMT(curwp));
		sprintf (buf, buf1, (ulong)rcnt);
		writ_echo (buf);
	}
	flush_count += rcnt;        /* jam for auto write buffers */
	return (TRUE);
}


/*
* This routine does the real work of a
* forward search. The pattern is sitting in the external
* variable "srch_pat" the mask if in "srch_mask".
* If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
char    forwsrch ()
{
	register    LINE    *save_dotp, *save2_dotp;
	register    int     save_doto, save2_doto;
	register    D8      *pat_ptr, *mask_ptr;
	register    int     i, j, pat_cnt;
	register    D8      first_pat, first_mask;
	char        buf[NCOL], buf1[NCOL];

	save_dotp = curwp -> w_dotp;    /* save dot position for later */
	save_doto = curwp -> w_doto;
	pat_ptr = srch_pat -> l_text;
	mask_ptr = srch_mask -> l_text;
	pat_cnt = srch_pat -> l_used;
	first_mask = mask_ptr[0];
	first_pat = pat_ptr[0] | first_mask;
	j =  (int)DOT_POS(curwp) & 0xffff;

	do 
	{
		if ((j++ & 0x2ff) == 0)
		{
			sprintf (buf1, MSG_srcing, R_POS_FMT(curwp));
			sprintf (buf, buf1, DOT_POS(curwp));
			writ_echo (buf);
			/* check if we should quit */
			if (ttkeyready ())
			{
				if (ttgetc () == CTL_G)
					break;
			}
		}
		if (first_pat == 
		    ((DOT_CHAR(curwp) | first_mask) & 0xff))
		{
			save2_dotp = curwp -> w_dotp;    /* save dot position for later */
			save2_doto = curwp -> w_doto;
			for (i = 1; i < pat_cnt; i++)
			{
				if (!move_ptr (curwp, 1L, TRUE, FALSE, TRUE) ||
				    ((pat_ptr[i] & ~mask_ptr[i]) != 
				    (DOT_CHAR(curwp) & ~mask_ptr[i])))
				{   /* not found */
					curwp -> w_dotp = save2_dotp;  /* restore dot position */
					curwp -> w_doto = save2_doto;
					break;
				}
			}
			if (i == pat_cnt)   /* found */
			{   /* move back to the first matching unit */
				move_ptr (curwp, -(long)pat_cnt + 1, TRUE, FALSE, TRUE);
				wind_on_dot (curwp);
				return (TRUE);
			}
		}
	}    while (move_ptr (curwp, 1L, TRUE, FALSE, TRUE));

	curwp -> w_dotp = save_dotp;  /* restore dot position */
	curwp -> w_doto = save_doto;
	return (FALSE);
}


/*
* This routine does the real work of a
* backward search. The pattern is sitting in the external
* variable "srch_pat". If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
char    backsrch ()
{
	register    LINE    *save_dotp, *save_p;
	register    LPOS    save_doto, save_o;
	register    D8      *pat_ptr, *mask_ptr;
	register    int     i, j, pat_cnt;
	register    char    first_pat, first_mask;
	char        buf[NCOL], buf1[NCOL];

	save_dotp = curwp -> w_dotp;    /* save dot position for later */
	save_doto = curwp -> w_doto;
	pat_ptr = srch_pat -> l_text;
	mask_ptr = srch_mask -> l_text;
	pat_cnt = srch_pat -> l_used;
	first_mask = mask_ptr[0];
	first_pat = pat_ptr[0] | first_mask;
	j =  (int)DOT_POS(curwp) & 0xffff;

	do 
	{
		/* check if we should quit */
		if (ttkeyready ())
		{
			if (ttgetc () == CTL_G)
				break;
		}
		if ((j-- & 0x2ff) == 0)
		{
			sprintf (buf1, MSG_srcing, R_POS_FMT(curwp));
			sprintf (buf, buf1, DOT_POS(curwp));
			writ_echo (buf);
		}
		if (first_pat == 
		    (curwp -> w_dotp -> l_text[curwp -> w_doto] | first_mask))
		{

			save_p = curwp -> w_dotp;
			save_o = curwp -> w_doto;
			for (i = 1; i < pat_cnt; i++)
			{
				if (!move_ptr (curwp, 1L, TRUE, FALSE, TRUE) ||
				    ((pat_ptr[i] & ~mask_ptr[i]) != 
				    (DOT_CHAR(curwp) & ~mask_ptr[i])))
				{   /* not found */
					curwp -> w_dotp = save_p;   /* restore ptr to continue */

					curwp -> w_doto = save_o;
					break;
				}
			}
			if (i == pat_cnt)   /* found */
			{   /* move back to the first matching unit */
				move_ptr (curwp, -(long)pat_cnt + 1, TRUE, FALSE, TRUE);
				wind_on_dot (curwp);
				return (TRUE);
			}
		}
	}    while (move_ptr (curwp, -1L, TRUE, FALSE, TRUE));

	curwp -> w_dotp = save_dotp;  /* restore dot position */
	curwp -> w_doto = save_doto;
	return (FALSE);
}

/*
* Read a pattern.
* Display and edit in the form of the current window.
* Slide the displayed line back and forth when the cursor hits a boundary.
* Manage the mask buffer. When a '*' (wild card) is entered mask all
* bits in that unit and display all '?'s.
*/
char    readpattern ()
{
	int     cod, mask_cod, curs_pos, curs_pos1, prt_siz, i, doto, loff;
	WINDOW  srch_wind, *save_wind;
	BUFFER  srch_buf, *save_buf;
	LINE    head_line;
	char    disp_buf[120],
	mask_buf[120],
	buf1[NCOL],
	siz_prompt2,
	r_type,
	first_time,
	u_off,
	stat;


	save_wind = curwp;          /* save current window for later */
	save_buf = curbp;       /* save current buffer for later */

	curwp = &srch_wind;         /* search window is current window during
						                                   search */
	curbp = &srch_buf;
	cur_pat = srch_pat;         /* set global variables for LINE finctions */
	cur_mask = srch_mask;

	recall_flag = FALSE;
	first_time = TRUE;
	read_pat_mode = TRUE;
	curwp -> w_wndp = NULL;
	curwp -> w_bufp = curbp;
	curwp -> w_linep = cur_pat;
	curwp -> w_loff = 0;
	curwp -> w_dotp = cur_pat;
	curwp -> w_doto = 0;
	curwp -> w_unit_offset = 0;
	curwp -> w_toprow = 24;
	curwp -> w_ntrows = 1;
	curwp -> w_intel_mode = save_wind -> w_intel_mode;
	curwp -> w_disp_shift = 0;
	if (R_TYPE(save_wind) == TEXT)
		curwp -> w_fmt_ptr = &ascii_s_fmt;
	else
		curwp -> w_fmt_ptr = save_wind -> w_fmt_ptr -> r_srch_fmt;

	srch_buf.b_bufp = NULL;
	srch_buf.b_linep = &head_line;
	srch_buf.b_unit_offset = 0;    /* unit offset   pvr */
	srch_buf.b_markp = NULL;
	srch_buf.b_marko = 0;
	srch_buf.b_flag = 0;
	srch_buf.b_nwnd = 1;
	srch_buf.b_fname[0] = 0;
	srch_buf.b_bname[0] = 0;

	head_line.l_fp = cur_pat;
	head_line.l_bp = cur_pat;
	head_line.l_file_offset = 0;    /* pvr */
	head_line.l_used = 0;
	head_line.l_size = 0;

	cur_pat -> l_fp = &head_line;
	cur_pat -> l_bp = &head_line;
	cur_pat -> l_size = 266;    /* leave some extra past 256 */
	cur_pat -> l_used = 0;
	cur_pat -> l_file_offset = 0;

	cur_mask -> l_fp = &head_line;
	cur_mask -> l_bp = &head_line;
	cur_mask -> l_size = 266;   /* leave some extra past 256 */
	cur_mask -> l_used = 0;
	cur_mask -> l_file_offset = 0;

	rplc_pat -> l_fp = &head_line;
	rplc_pat -> l_bp = &head_line;
	rplc_pat -> l_size = 266;    /* leave some extra past 256 */
	rplc_pat -> l_used = 0;
	rplc_pat -> l_file_offset = 0;

	rplc_mask -> l_fp = &head_line;
	rplc_mask -> l_bp = &head_line;
	rplc_mask -> l_size = 266;   /* leave some extra past 256 */
	rplc_mask -> l_used = 0;
	rplc_mask -> l_file_offset = 0;

	sprintf (buf1, MSG_curs, cur_prompt, R_BYTE_FMT(curwp),
	    R_BYTE_FMT(curwp), R_BYTE_FMT(curwp));
	sprintf (disp_buf, buf1, curwp -> w_doto,
	    curwp -> w_fmt_ptr -> r_chr_per_u - curwp -> w_unit_offset - 1,
	    curwp -> w_dotp -> l_used);

	siz_prompt2 = strlen (disp_buf); /* save prompt length for later */

	for (i = siz_prompt2; i < NCOL; i++)    /* clear rest of buffer */
		disp_buf [i] = ' ';

	writ_echo (disp_buf);

	r_type = R_TYPE(curwp);

	while (TRUE)
	{
		/* position cursor */
		curs_pos = curwp -> w_doto - curwp -> w_loff;
		if (curwp -> w_fmt_ptr -> r_size == 1)
		{
			curs_pos >>= 1;
		}
		else if (curwp -> w_fmt_ptr -> r_size == 3)
		{
			curs_pos >>= 2;
		}
		curs_pos1 = curwp -> w_fmt_ptr -> r_positions[curs_pos] + 
		    curwp -> w_unit_offset + siz_prompt2;
		ttmove (nrow - 1, curs_pos1);
		ttflush ();

		cod = getkey ();

		if (cod == 0x014D)  /* check for return */
		{
			if ((rplc_mode == TRUE) && (cur_prompt == MSG_sch_str))
			{
				next_pat ();
				dont_repeat = FALSE;    /* fix up */
				goto next_loop;
			}
			else
			{
				old_srch_pat_size = srch_pat -> l_used; /* save for restore */
				if (rplc_mode == TRUE)
					old_rplc_pat_size = rplc_pat -> l_used;

				old_fmt = curwp -> w_fmt_ptr;
				curwp = save_wind;  /* restore current window */
				curbp = save_buf;  /* restore current buffer */
				read_pat_mode = FALSE;
				return (TRUE);
			}
		}

		if ((cod >= ' ') && (cod < 0x7f))
		{
			if ((r_type == ASCII) || (r_type == EBCDIC))
			{
				mask_cod = '9'; /* use 9 as dummy char that will get through */
			}
			else if (r_type == DECIMAL)
			{
				mask_cod = '0'; /* clear mask byte */
			}
			else if (cod == '?')
			{
				cod = '0';
				switch (r_type)
				{
				case OCTAL:
					if (curwp -> w_unit_offset == 0)    /* if first char */
					{
						if (R_SIZE(curwp) == WORDS)
							mask_cod = '1';
						else
							mask_cod = '3';
					}
					else
						mask_cod = '7';
					break;

				case HEX:
					mask_cod = 'F';
					break;

				case BINARY:
					mask_cod = '1';
					break;
#if RUNCHK
				default:
					printf (ERR_rdpat);
					break;
#endif
				}
			}
			else
			{
				mask_cod = '0';
			}
		}
		else
			mask_cod = cod;     /* must be control; do the same to the mask */

		/* save current dot and window positions */
		doto = curwp -> w_doto;
		u_off = curwp -> w_unit_offset;
		loff = curwp -> w_loff;
		stat = execute (cod, FALSE, 1);

		if (stat == ABORT)
		{
			old_srch_pat_size = srch_pat -> l_used; /* save for restore */
			if (rplc_mode == TRUE)
				old_rplc_pat_size = rplc_pat -> l_used;
			old_fmt = curwp -> w_fmt_ptr;
			curwp = save_wind;  /* restore current window */
			curbp = save_buf;  /* restore current buffer */
			read_pat_mode = FALSE;
			return (FALSE);
		}

		/* If key is recall then reset the size variables */
		if (first_time)
		{
			first_time = FALSE;
			if (recall_flag)
			{
				srch_pat -> l_used = old_srch_pat_size;
				srch_mask -> l_used = old_srch_pat_size;
				rplc_pat -> l_used = old_rplc_pat_size;
				rplc_mask -> l_used = old_rplc_pat_size;
				curwp -> w_fmt_ptr = old_fmt;
				recall_flag = FALSE;
			}
		}

		/* if it was a toggling command, don't do it again */
		if (!dont_repeat &&
		    (stat == TRUE))
		{
			head_line.l_fp = cur_mask;   /* point to mask */
			head_line.l_bp = cur_mask;
			curwp -> w_linep = cur_mask;
			curwp -> w_dotp = cur_mask;
			curwp -> w_loff = loff;
			curwp -> w_doto = doto;
			curwp -> w_unit_offset = u_off;
			execute (mask_cod, FALSE, 1);

			head_line.l_fp = cur_pat;    /* restore pointers */
			head_line.l_bp = cur_pat;
			curwp -> w_linep = cur_pat;
			curwp -> w_dotp = cur_pat;
		}
		else
			dont_repeat = FALSE;

		/* limit at 256 bytes */
		if (cur_pat -> l_used >= 256)
		{
			cur_mask -> l_used = 255;
			cur_pat -> l_used = 255;
			if (curwp -> w_doto >= 256)
			{
				move_ptr (curwp, 255L, TRUE, TRUE, FALSE);  /* last position */
			}
		}

		/* if buffer is size locked then replace pattern must be the */
		/* same size as the search pattern */
		if (rplc_mode && (save_buf -> b_flag & BFSLOCK))
		{
			rplc_pat -> l_used = srch_pat -> l_used;
			rplc_mask -> l_used = srch_pat -> l_used;
		}

		r_type = R_TYPE(curwp);
#if RUNCHK
		/* check that the pattern and the mask are the same size */
		if (cur_pat -> l_used != cur_mask -> l_used)
		{
			printf (ERR_mask, cur_pat -> l_used, cur_mask -> l_used);
		}

		/* check that in ascii mode the byte that will be set to zero */
		/* is the dummy char 9 */
		/*        if (((r_type == ASCII) &&
            (cur_mask -> l_text[curwp -> w_doto - 1] != '9'))
            ||
            ((r_type == EBCDIC) &&
            (cur_mask -> l_text[curwp -> w_doto - 1] != to_ebcdic('9'))))
            printf (ERR_m_cl);
*/
#endif
		if (((r_type == ASCII) ||
		    (r_type == EBCDIC)) &&
		    ((cod >= ' ') && (cod < 0x7f)))
			cur_mask -> l_text[doto] = 0; /* clear mask byte */

next_loop:
		sprintf (buf1, MSG_curs, cur_prompt, R_BYTE_FMT(curwp),
		    R_BYTE_FMT(curwp), R_BYTE_FMT(curwp));
		sprintf (disp_buf, buf1, curwp -> w_doto,
		    curwp -> w_fmt_ptr -> r_chr_per_u - curwp -> w_unit_offset - 1,
		    curwp -> w_dotp -> l_used);

		siz_prompt2 = strlen (disp_buf); /* save prompt length for later */

		for (i = siz_prompt2; i < NCOL; i++)
		{
			disp_buf [i] = ' ';
			mask_buf [i] = ' ';
		}

		if ((curbp -> b_flag & BFSLOCK) &&
		    (rplc_pat -> l_used != srch_pat -> l_used))
		{
			rplc_pat -> l_used = srch_pat -> l_used;
			/* if dot is past the end then move it back, replace string only */
			if (DOT_POS(curwp) > srch_pat -> l_used)
				move_ptr (curwp, (long)srch_pat -> l_used, TRUE, TRUE, FALSE);
		}

		wind_on_dot (curwp);

		/* figure number of bytes to convert to text */
		if ((cur_pat -> l_used - curwp -> w_loff) <
		    (prt_siz = curwp -> w_fmt_ptr -> r_bytes))
			prt_siz = cur_pat -> l_used - curwp -> w_loff;

		bin_to_text (&cur_pat -> l_text[curwp -> w_loff],
		    &disp_buf[siz_prompt2],
		    prt_siz, curwp -> w_fmt_ptr);

		/* change any char to a ? if any bit is set in the mask buffer */
		if ((r_type != ASCII) && (r_type != EBCDIC))
		{
			/* print the contents of the mask to a invisible buffer */
			bin_to_text (&cur_mask -> l_text[curwp -> w_loff],
			    &mask_buf[siz_prompt2],
			    prt_siz, curwp -> w_fmt_ptr);

			for (i = siz_prompt2; (disp_buf[i] != 0) && (i < NCOL); i++)
			{
				if ((mask_buf[i] != '0') &&
				    (mask_buf[i] != ' '))
					disp_buf[i] = '?';
			}
		}
		else
		{
			for (i = 0; i < prt_siz; i++)
			{
				if (cur_mask -> l_text[curwp -> w_loff + i] != 0)
					disp_buf[i + siz_prompt2] = '?';
			}
		}
		writ_echo (disp_buf);
	}
	return (TRUE);
}

/*
*   Recall the last contents of the search string
*/
bool    recall ()
{
	recall_flag = TRUE;
	return (TRUE);
}

/*
*   Switch between search pattern and replace pattern and their 
*   respective masks 
*/
void    next_pat ()
{
	if (cur_pat == srch_pat)
	{
		cur_prompt = MSG_rpl_str;
		cur_pat = rplc_pat; /* point to replace pattern */
		cur_mask = rplc_mask;
	}
	else
	{
		cur_prompt = MSG_sch_str;
		cur_pat = srch_pat;     /* point to search pattern */
		cur_mask = srch_mask;
	}
	curwp -> w_dotp = cur_pat;
	curwp -> w_linep = cur_pat;
	curbp -> b_linep -> l_fp = cur_pat;
	curbp -> b_linep -> l_bp = cur_pat;

	if (curwp -> w_doto > cur_pat -> l_used)
	{
		curwp -> w_doto = cur_pat -> l_used;
		curwp -> w_unit_offset = 0;
	}
	if (curwp -> w_loff > cur_pat -> l_used)
		curwp -> w_loff = cur_pat -> l_used;
	dont_repeat = TRUE;
}

/*
* Compare the contents of two windows.
* There must be exactly two windows displayed.
* The bytes under the cursor in each window are compared and if 
* a difference is found then the loop is stopped with the dot
* position in each window pointing to the difference.
* The two windows can be pointing at the same or different buffers.
*/
bool    compare ()

{
	WINDOW  *wp1, *wp2;
	bool    move1, move2;
	int     j;
	char    *term_str = MSG_cmp_dif;
	char    buf[NCOL], buf1[NCOL];

	if (wheadp -> w_wndp -> w_wndp != NULL)
	{
		writ_echo (MSG_only_2);
		return (FALSE);
	}

	wp1 = wheadp;
	wp2 = wheadp -> w_wndp;
	j =  (int)DOT_POS(curwp) & 0xffff;

	wp1 -> w_flag |= WFMOVE;
	wp2 -> w_flag |= WFMOVE;

	while (DOT_CHAR(wp1) == DOT_CHAR(wp2))
	{
		if ((j++ & 0xff) == 0)
		{
			sprintf (buf1, MSG_cmping, R_POS_FMT(curwp));
			sprintf (buf, buf1, DOT_POS(curwp));
			writ_echo (buf);
			/* check if we should quit */
			if (ttkeyready ())
			{
				if (ttgetc () == CTL_G)
				{
					term_str = MSG_cmp_term;
					break;
				}
			}
		}
		move1 = move_ptr (wp1, 1L, TRUE, FALSE, TRUE);
		move2 = move_ptr (wp2, 1L, TRUE, FALSE, TRUE);

		if (!(move1 && move2))
		{
			term_str = MSG_cmp_end;
			break;
		}
	}
	writ_echo (term_str);
	wind_on_dot (wp1);
	wind_on_dot (wp2);
	return (TRUE);
}
