/*
 *				T 3
 *
 * User interaction, including search mode and the magical reposition
 * routine.
 */

#include	<stdio.h>
#ifdef	vms
#include	<ctype.h>
#define	FALSE	0
#define	TRUE	1
#endif
#include	"t.h"


inquire()
/*
 * Get a byte from the terminal, return TRUE if repositioning was done
 * and saveplace() should not be called. return FALSE if exit from dopage().
 */
{
	register int	c;
	register int	value;
	register int	minus_flag;

	value = 0;
	minus_flag = FALSE;
	for (;;) {
		if (isdigit(c = kbin())) {
			value *= 10;
			value += (c - '0');
			continue;
		}
		switch (toupper(c)) {

		case '-':
			minus_flag = TRUE;
			continue;

		case '?':
		case 'H':
			helpmessage();
			scout(1, 1, NULL);
			continue;

		case 'C' - 0100:		/* For RSTS/RT11	*/
		case 'Z' - 0100:		/* CTRL/Z		*/
		case 'E':			/* E means Exit		*/
			finis++;		/* Force exit		*/
			return (FALSE);		/* Exit dopage()	*/

		case 'F':
			memptr = memory;	/* Rewind the file	*/
			memory[0].record_rfa = magic_cookie;
			memory[0].buff_offset = 0;
			memory[0].line_offset = 0;
			locate(FALSE);		/* Reposition file	*/
			return (TRUE);		/* and get another	*/

		case 'N':
		case 'X':
			breakout = TRUE;	/* Exit this file	*/
			return (FALSE);		/* Exit dopage()	*/

		case '^':			/* Upwards		*/
		case '\b':			/* Backspace		*/
		case '\n':			/* <Line-feed>		*/
			if (minus_flag)
				goto forward;
backward:		do {
				backup(FALSE);	/* Back one screen	*/
			} while (--value > 0);	/* At least once	*/
			locate(FALSE);		/* Position for		*/
			return (TRUE);		/* Next readin		*/

		case 'S':			/* Search mode		*/
			return(search());

		case 'P':			/* <Form-feed>		*/
			if (minus_flag) {	/* Reverse page skip?	*/
				do {		/* if so, back up a bit	*/
					backup(TRUE);
				} while (--value > 0);
				locate(FALSE);	/* Position for		*/
				return(TRUE);	/* Next readin		*/
			}
			if (value <= 1)		/* Tiny skip?		*/
				value = 2;	/* Always skip once	*/
			return(silence(-value, FALSE));

		case 'B':			/* file.		*/
			value = HUGE;		/* Force big skip	*/

		case ' ':			/* Space and Return	*/
		case '\r':			/* Get the next page	*/
			if (minus_flag)
				goto backward;
forward:		return (silence(value, FALSE));

/*
 * Debug only:
 */
#ifdef	UNDEFINED
		case 'M':			/* Memory dump		*/
			scerpg(1, 1); scout(0, 0, NULL);
			for (value = 0; &memory[value] <= memptr; value++) {
				fprintf(stderr, "%2d: %08x %04x %04x\n",
					value, memory[value].record_rfa,
					memory[value].buff_offset,
					memory[value].line_offset);
			}
			value = 0;
#endif
		}
	}
}

static char	*shelp1 =
"Enter a regular expression pattern, in which\r\n\
x	An ordinary character (not mentioned below) matches that character.\r\n\
'\\'	Backslash quotes any character, '\\\\' matches backslash.\r\n\
'^'	At the beginning of an expression matches the beginning of a line.\r\n\
'$'	At the end of an expression matches the end of a line.\r\n\
'.'	Matches any character except the end of the line.\r\n\
':a'	Matches any alphabetic, ':d' matches digits, ':n' matches either.\r\n\
': '	Matches spaces, tabs and other control characters.\r\n\
'*'	An expression followed by '*' matches zero or more repeats.\r\n\
'+'	An expression followed by '+' matches one or more repeats.\r\n\
'-'	An expression followed by '-' optionally matches.\r\n\
'[]'	A string enclosed in '[] matches any character in that string.\r\n\
	If the first character is '^', the match is to any character except\r\n\
	new-line and the named characters.  A range of characters may be\r\n\
	specified as \"a-z\".\r\n\
\r\n";
static char	*shelp2 =
"Regular expressions may be concatenated.  The search starts on the screen\r\n\
following that displayed.  If found, the screen containing the match will\r\n\
be displayed.  If not found, the last screen will be displayed.";

static char	sinput[81] = "";

int
search()
/*
 * Get the pattern, compile it and do the search
 */
{
	for (;;) {
		scerln(1, 1);
		if (vt100)
			scout(0, 0, "\233#5");	/* Single wide, high	*/
		scout(0, 0, "Search pattern: ");
		enter(1, 17, sinput, sizeof sinput);
		if (sinput[0] == '?') {
			scerpg(2, 1);
			scout(2, 1, shelp1);
			scout(0, 0, shelp2);
			continue;
		}
		else if (sinput[0] == EOS) {
			/*
			 * Null line means a change of mind.
			 */
			return(silence(0, FALSE));
		}
		else if (rxcomp(sinput))
			break;
		else {
			scerpg(2, 1);
			scout(0, 0, rx_pattern);
			scout(3, 1, "Enter \"?<return>\" for help");
			continue;
		}
	}
	return(silence(32767, TRUE));
}

enter(row, col, out_buf, out_size)
int		row;
int		col;
char		*out_buf;
int		out_size;
/*
 * Read from the terminal, echoing as needed.  Write data to out_buf.
 * Handle rubout, etc.  Note: CTRL/C and CTRL/Z exit with a null
 * string in out_buf.  If out_buf is not equal to "" on entry,
 * the contents will be displayed (as a default).  If the user
 * then types <return> (without anything else preceeding), the
 * default text will be returned.
 */
{
	register char		*op;
	register char		c;
	register char		*otop;

	op = out_buf;
	otop = &out_buf[out_size - 1];
	if (*op == EOS) {
		scerln(row, col);
	}
	else {
		scout(row, col, op);
		scout(row, col, "");
	}
	for (;;) {
		scout(0, 0, NULL);
		if ((c = (kbin() & 0177)) < ' ') {
			switch (c) {
			case '\0':
			case 'C'-0100:
					scerpg(1, 1);
					exit(0);
			case 'U'-0100:
					op = out_buf;
					*op = EOS;
					scerln(row, col);
					continue;

			case 'Z'-0100:
					scerln(row, col);
					scout(0, 0, "^Z");
					scout(0, 0, NULL);
					out_buf[0] = EOS;
					return;

			case '\r':
			case '\n':
					return;

			default:
					continue;
			}
		}
		else if (c == '\177') {
			if (op > out_buf) {
				*--op = EOS;;
				scout(0, 0, "\b \b");
			}
		}
		else if (op < otop) {
			if (op == out_buf)
				scerln(row, col);
			*op++ = c;
			*op = EOS;
			scout(0, 0, &op[-1]);
		}
		else {
			/*
			 * No room, ignore it
			 */
		}
	}
}

int
silence(value, rxflag)
int		value;
/*
 * Silently skip forward the indicated number of pages (does nothing
 * if abs(value) is <= 1).  Note that this algorithm must functionally
 * duplicate dopage().  If we're at the end of the file, back up
 * to the start of the (last page to be output) and return TRUE
 * to supress "locate the new page".
 *
 * If value is < 0, the skip is to the abs(value)'th form feed.
 * If the regular expression search succeeds, it sets the row/column
 * for the next printout.
 */
{
	register int		row;
	register char		*tp;
	register int		howmany;
	int			formflag;
	int			old;		/* For skip printout	*/
	int			next;		/* For skip printout	*/
	char			*place;		/* Rxgrep value		*/
	extern char		*rxgrep();
	extern char		*getline();

	if ((formflag = (value < 0)))
		value = -value;
	if (iseof > 0) {
		locate(TRUE);		/* Restart on this page		*/
		return (TRUE);
	}
	/*
	 * Note that this code is executed only if value is > 1.
	 * I.e., if we are to skip over at least one page.
	 */
	old = 10;
	next = 10;
	for (howmany = 1; howmany < value;) {
		if (howmany >= next) {
			sprintf(temptext, "Skipped %d pages", howmany);
			midmsg();
			scout(1, 1, textline);
			scerln(0, 0);
			scout(0, 0, NULL);
			row = old;			/* Temp		*/
			old = next;		
			next += row;			/* Fibonacci	*/
		}
		saveplace();
		for (row = 1; row <= linesperscreen; row++) {
			if ((tp = getline()) == NULL) {
				break;		/* We shouldn't be here	*/
			}
			if (rxflag
			     && (place = rxgrep(tp, rx_pattern)) != NULL) {
				locate(FALSE);
				cursrow = row;
				row = 0;	/* It's column now	*/
				while (tp <= place) {
					if (*tp++ == '\t')
						row = (row + 8) & ~7;
					else	row++;
				}
				curscol = row;
				goto gotcha;
			}
			else if (row == 1 && (*tp == EOS || *tp == '\f')) {
				row--;		/* white space is	*/
				continue;	/* skipped at page top	*/
			}
			else if (*tp == '\f')	/* Mid-page form-feed?	*/
				break;		/* Yep, page is done	*/
		}
		if (!formflag || *tp == '\f')
			howmany++;
		if (iseof > 0) {
			/*
			 * Here if we've just skipped to the bottom
			 * of the last visible page.
			 */
			locate(FALSE);		/* To top of this page	*/
			if (howmany >= 10)
				scerpg(1, 1);
			return (TRUE);		/* and don't saveplace	*/
		}
	}
gotcha:
	if (howmany >= 10)
		scerpg(1, 1);
	return (FALSE);
}
