[net.emacs] MicroEmacs 3.7 isearch changes

richk@pogo.UUCP (Richard G. Knowles) (08/19/86)

----------------------------------------------------------------

  The following is an extensive set of changes to the user interface of
isearch.  I made them to the 3.6 version and re-applied them to the 3.7
version.  The list of changes/bug fixes is as follows:

	1-Aug-86
	- Removed command buffer reexecution; backup instead. Buffer re-
	  execution took too long when deep into multiple re-searches. 
	- Changed prompts to indicate direction
	- Added search failure prompt
	- Won't save quote command - just quoted char.  Saving the quote
	  command made it impossible to backup over it, since the ^H/^?
	  ended up being quoted themselves (with the reexecution method).
	- Keep track of last successful search string so that additional
	  search requests (same direction only) can be ignored until the
	  the bad characters are remove from the search string.
	- Won't save additional search commands if search failure since
	  nothing there to backup to.
	- Changed BELL writes to use beep routine instead

	12-Aug-86 -- to much memory usage for functionality gained so:
	- Removed command buffer altogether, ^H/^? removes last char
	  and restores cursor to position it was at when that char
	  was entered.  User must switch search direction to backup to
	  prior occurance.
        - Commented out the VMSxx character checks (I use ^V too much)

  The only major short coming I know about is that the search command
characters are hard coded to ^S/^R (and/or ^V) as well as the quote/
rubout/backspace to ^Q(or ^X)/^H/^? .  It really ought to use the
ones the user has bound instead of using hardcoded values (albeit the common
defaults)

------------- shell archive of isearch.c below here ----------------
# This is a shar archive.
# Remove everything above this line.
# Run the file through sh, not csh.
# (type `sh isearch.shar.1')
# If you do not see the message
#	`isearch.shar.1 completed!'
# then the file was incomplete.
echo extracting - isearch.c
sed 's/^X//' > isearch.c << 'FRIDAY_NIGHT'
X/*
X * The functions in this file implement commands that perform incremental
X * searches in the forward and backward directions.  This "ISearch" command
X * is intended to emulate the same command from the original EMACS 
X * implementation (ITS).  Contains references to routines internal to
X * SEARCH.C.
X *
X * REVISION HISTORY:
X *
X *	D. R. Banks 9-May-86
X *	- added ITS EMACSlike ISearch
X *
X *	R. G. Knowles 1-Aug-86
X *	- Removed command buffer reexecution; backup instead. Buffer re-
X *	  execution took too long when deep into multiple re-searches. 
X *	- Changed prompts to indicate direction
X *	- Added search failure prompt
X *	- Won't save quote command - just quoted char.  Saving the quote
X *	  command made it impossible to backup over it, since the ^H/^?
X *	  ended up being quoted themselves (with the reexecution method).
X *	- Keep track of last successful search string so that additional
X *	  search requests (same direction only) can be ignored until the
X *	  the bad characters are remove from the search string.
X *	- Won't save additional search commands if search failure since
X *	  nothing there to backup to.
X *	- Changed BELL writes to use beep routine instead
X *
X *	12-Aug-86 -- to much memory usage for functionality gained so:
X *	- Removed command buffer altogether, ^H/^? removes last char
X *	  and restores cursor to position it was at when that char
X *	  was entered.  User must switch search direction to backup to
X *	  prior occurance.
X *	- Commented out the VMSxx character checks
X *
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X/*	string search input parameters	*/
X
X#define	PTBEG	1	/* leave the point at the beginning on search */
X#define	PTEND	2	/* leave the point at the end on search */
X
Xextern int forscan();			/* Handy search routine */
Xextern int eq();			/* Compare chars, match case */
X
X/* A couple of "own" variables for re-eat */
X
Xint	(*saved_get_char)();		/* Get character routine */
Xint	eaten_char = -1;		/* Re-eaten char */
X
X/* A couple more "own" variables for the command string */
X
XLINE *	curline_after_char[NPAT];	/* Current line after command       */
Xint	curoff_after_char[NPAT];	/* Current offset after command     */
Xint	first_bad_char;			/* save position of char failed on  */
Xint	oldstatus;			/* status of previous search	    */
X
X/* Some character constants within ISearch */
X
X#define	IS_ABORT	0x07	/* Abort the isearch			    */
X#define IS_BACKSP	0x08	/* Delete previous char			    */
X#define	IS_TAB		0x09	/* Tab character (allowed search char)	    */
X#define IS_NEWLINE	0x0D	/* New line from keyboard (Carriage return) */
X#define	IS_QUOTE	0x11	/* Quote next character			    */
X#define IS_REVERSE	0x12	/* Search backward			    */
X#define	IS_FORWARD	0x13	/* Search forward			    */
X#define	IS_VMSQUOTE	0x16	/* VMS quote character			    */
X#define	IS_VMSFORW	0x18	/* Search forward for VMS		    */
X#define	IS_QUIT		0x1B	/* Exit the search			    */
X#define	IS_RUBOUT	0x7F	/* Delete previous character		    */
X
X/*
X * Subroutine to do incremental reverse search.  It actually uses the
X * same code as the normal incremental search, as both can go both ways.
X */
X 
Xint risearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	      */
X    int  curoff;			/* Current offset on entry	      */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X
X    /* Make sure the search doesn't match where we already are:		      */
X
X    backchar(TRUE, 1);			/* Back up a character		      */
X
X    if (!(isearch(f, -n)))		/* Call ISearch backwards	      */
X    {					/* If error in search:		      */
X	curwp->w_dotp = curline;	/* Reset the line pointer	      */
X	curwp->w_doto = curoff;		/*  and the offset to original value  */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		      */
X	update();			/* And force an update		      */
X	mlwrite ("[search failed]");	/* Say we died			      */
X    } else mlerase ();			/* If happy, just erase the cmd line  */
X}
X
X/* Again, but for the forward direction */
X
Xint fisearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	      */
X    int  curoff;			/* Current offset on entry	      */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X
X    /* do the search */
X
X    if (!(isearch(f, n)))		/* Call ISearch forwards	      */
X    {					/* If error in search:		      */
X	curwp->w_dotp = curline;	/* Reset the line pointer	      */
X	curwp->w_doto = curoff;		/*  and the offset to original value  */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		      */
X	update();			/* And force an update		      */
X	mlwrite ("[search failed]");	/* Say we died			      */
X    } else mlerase ();			/* If happy, just erase the cmd line  */
X}
X
X/*
X * Subroutine to do an incremental search.  In general, this works similarly
X * to the older micro-emacs search function, except that the search happens
X * as each character is typed, with the screen and cursor updated with each
X * new search character.
X *
X * While searching forward, each successive character will leave the cursor
X * at the end of the entire matched string.  Typing a Control-S or Control-X
X * will cause the next occurrence of the string to be searched for (where the
X * next occurrence does NOT overlap the current occurrence).  A Control-R will
X * change to a backwards search, ESC will terminate the search and Control-G
X * will abort the search.  Rubout will back up to the previous match of the
X * string, or if the starting point is reached first, it will delete the
X * last character from the search string.
X *
X * While searching backward, each successive character will leave the cursor
X * at the beginning of the matched string.  Typing a Control-R will search
X * backward for the next occurrence of the string.  Control-S or Control-X
X * will revert the search to the forward direction.  In general, the reverse
X * incremental search is just like the forward incremental search inverted.
X *
X * In all cases, if the search fails, the user will be feeped, and the search
X * will stall until the pattern string is edited back into something that
X * exists (or until the search is aborted).
X */
X 
Xisearch(f, n)
X{
X    int			status;		/* Search status */
X    int			col;		/* curr prompt column */
X    int			scol;		/* initial prompt column */
X    int			tcol, t2col;	/* temporary prompt column */
X    register int	cpos;		/* character number in search string  */
X    register int	c;		/* current input character */
X    char		pat_save[NPAT];	/* Saved copy of the old pattern str  */
X    LINE		*curline;	/* Current line on entry	      */
X    int			curoff;		/* Current offset on entry	      */
X    int			init_direction;	/* The initial search direction	      */
X
X    /* Initialize starting conditions */
X
X    strncpy (pat_save, pat, NPAT);	/* Save the old pattern string	      */
X    curline = curwp->w_dotp;		/* Save the current line pointer      */
X    curoff  = curwp->w_doto;		/* Save the current offset	      */
X    init_direction = n;			/* Save the initial search direction  */
X
X    /* ask the user for the text of a pattern */
X    if (n >= 0)
X    {
X        scol = promptpattern("I-Search: ");	/* Prompt, remember the col   */
X    }
X    else
X    {
X        scol = promptpattern("R-Search: ");	/* Prompt, remember the col   */
X    }
X    
X    col    = scol;				/* keyboard echo starts here  */
X    cpos   = 0;					/* Start afresh		      */
X    status = TRUE;				/* Assume everything's cool   */
X    oldstatus = TRUE;				/* Assume everything's cool   */
X
X    /*
X       Get the first character in the pattern.  If we get an initial Control-S
X       or Control-R, re-use the old search string and find the first occurrence
X     */
X
X    c = get_char();				/* Get the first character    */
X    if ((c == IS_FORWARD) ||
X        (c == IS_REVERSE) ||
X        (c == IS_VMSFORW))			/* Reuse old search string?   */
X    {
X    	for (cpos = 0; pat[cpos] != 0; cpos++)	/* Yup, find the length	      */
X    	    col = echochar(pat[cpos],col);	/*  and re-echo the string    */
X	if (c == IS_REVERSE) {			/* forward search?	      */
X	    n = -1;				/* No, search in reverse      */
X	    backchar (TRUE, 1);			/* Be defensive about EOB     */
X	} else
X	    n = 1;				/* Yes, search forward	      */
X	status = scanmore(pat,n,status);	/* Do the search	      */
X	display_status(status);			/* Indicate results	      */
X        if (!status)
X	    (*term.t_beep)();			/* It failed		      */
X	c = get_char ();			/* Get another character      */
X    }
X
X    /* Top of the per character loop */
X        	
X    for (;;)					/* ISearch per character loop */
X    {
X	/* Check for magic characters first: */
X	/* Most cases here change the search */
X
X	switch (c)				/* dispatch on the input char */
X	{
X	  case IS_ABORT:			/* If abort search request    */
X	    return(FALSE);			/* Quit searching again	      */
X
X	  case IS_REVERSE:			/* If backward search	      */
X	  case IS_FORWARD:			/* If forward search	      */
X/*	  case IS_VMSFORW:	*/		/*  of either flavor	      */
X	    if (c == IS_REVERSE)		/* If reverse search	      */
X	    {
X		if (n != -1)			/* and wasn't before	      */
X		{
X		    status = TRUE;		/* Switched so must look again*/
X		    n = -1;			/* Set the reverse direction  */
X    		    movecursor(term.t_nrow,0);	/* Position the cursor	      */
X		    (*term.t_putchar)('R');	/* Change prompt	      */
X		}
X	    }
X	    else				/* Otherwise, forward search  */
X	    	if (n != 1)			/* and wasn't before.	      */
X		{
X		    status = TRUE;		/* Switched so must look again*/
X		    n = 1;			/* Set forward direction      */
X    		    movecursor(term.t_nrow,0);	/* Position the cursor	      */
X		    (*term.t_putchar)('I');	/* Change prompt	      */
X		}
X	    if (status)
X	    {
X	        status = scanmore(pat,n,status);/* Start the search again     */
X		display_status (status);
X	    }
X	    if (!status)
X		(*term.t_beep)();		/* It failed (again?)!	      */
X	    c = get_char ();			/* Get the next char	      */
X	    continue;				/* Go continue with the search*/
X
X	  case IS_QUIT:				/* Want to quit searching?    */
X	    return (TRUE);			/* Quit searching now	      */
X
X	  case IS_NEWLINE:			/* Carriage return	      */
X	    c = '\n';				/* Make it a new line	      */
X	    break;				/* Make sure we use it	      */
X
X	  case IS_QUOTE:			/* Quote character	      */
X/*	  case IS_VMSQUOTE:	*/		/*  of either variety	      */
X	    c = get_char ();			/* Get the next char	      */
X	    break;
X
X	  case IS_TAB:				/* Generically allowed	      */
X	  case '\n':				/*  controlled characters     */
X	    break;				/* Make sure we use it	      */
X
X	  case IS_BACKSP:			/* If a backspace:            */
X	  case IS_RUBOUT:			/*  or if a Rubout:	      */
X	    if (cpos <= 0)			/* Anything to delete?	      */
X	    	return (TRUE);			/* No, just exit	      */
X
X	    if (--cpos < first_bad_char)
X	    {
X		first_bad_char = -1;
X	        status = TRUE;
X	        display_status (status);
X	    }
X	    pat[cpos] = '\0';
X	    tcol = col;
X	    col  = scol;
X	    for (cpos = 0; pat[cpos] != 0; cpos++)	/* re-echo search     */
X		col = echochar(pat[cpos],col);		/*   string.	      */
X	    for (t2col=col; t2col < tcol ; )		/* delete any extra   */
X		t2col = echochar(' ',t2col);		/*   string.	      */
X						/* Reset the line pointer and */
X	    curwp->w_dotp = curline_after_char[cpos];
X						/*   the offset to prev pos   */
X	    curwp->w_doto = curoff_after_char[cpos];
X	
X	    curwp->w_flag |= WFMOVE;		/* Say we've moved	      */
X	    c = get_char ();			/* Get the next char	      */
X	    continue;				/* and try again	      */
X
X
X	  /* Presumably a quasi-normal character comes here */
X
X	  default:				/* All other chars    	      */
X	    if (c < ' ')			/* Is it printable?	      */
X	    {					/* Nope.		      */
X		re_eat (c);			/* Re-eat the char	      */
X		return (TRUE);			/* And return the last status */
X	    }
X	}  /* Switch */
X
X	/* I guess we got something to search for, so search for it	      */
X
X					/* save cursor pos of last result so  */
X	curline_after_char[cpos] = curwp->w_dotp;
X					/*   we can quickly return there when */
X	curoff_after_char[cpos]  = curwp->w_doto;
X					/*   backing up with BS or RUB        */
X	pat[cpos++] = c;			/* put the char in the buffer */
X	if (cpos >= NPAT)			/* too many chars in string?  */
X	{					/* Yup.  Complain about it    */
X	    mlwrite("? Search string too long");
X	    return(TRUE);			/* Return an error	      */
X	}
X	pat[cpos] = 0;				/* null terminate the buffer  */
X	col = echochar(c,col);			/* Echo the character	      */
X	if (!status) {				/* If we lost last time	      */
X	    (*term.t_beep)();			/* Feep again		      */
X	} else					/* Otherwise, we must have won*/
X	    if (!(status = checknext(c,pat,n,status))) /* See if match or     */
X	    	if (!(status = scanmore(pat,n,TRUE)))  /*  find the next match    */
X	    	{
X	    	    first_bad_char = cpos;	/* remember where we went bad */
X		    display_status (status);
X		    (*term.t_beep)();
X		}
X
X	c = get_char ();			/* Get the next char	      */
X    } /* for {;;} */
X}
X
X/*
X * Routine to visually indicate the state of the search by overwritting
X * the prompt with FAIL when in a failure mode.
X */
X 
Xdisplay_status (status)
Xint status;
X{
X    if (status != oldstatus)
X    {
X	oldstatus = status;
X	movecursor(term.t_nrow,2);
X    	if (status)
X    	{
X	    (*term.t_putchar)('S');
X	    (*term.t_putchar)('e');
X	    (*term.t_putchar)('a');
X	    (*term.t_putchar)('r');
X	    (*term.t_putchar)('c');
X	    (*term.t_putchar)('h');
X	}
X	else
X	{
X	    (*term.t_putchar)('S');
X	    (*term.t_putchar)(' ');
X	    (*term.t_putchar)('F');
X	    (*term.t_putchar)('A');
X	    (*term.t_putchar)('I');
X	    (*term.t_putchar)('L');
X	}
X    }
X}
X
X/*
X * Trivial routine to insure that the next character in the search string is
X * still true to whatever we're pointing to in the buffer.  This routine will
X * not attempt to move the "point" if the match fails, although it will 
X * implicitly move the "point" if we're forward searching, and find a match,
X * since that's the way forward isearch works.
X *
X * If the compare fails, we return FALSE and assume the caller will call
X * scanmore or something.
X */
X
Xint checknext (chr, patrn, dir, sts)/* Check next character in search string */
Xchar	chr;			/* Next char to look for		 */
Xchar	*patrn;			/* The entire search string (incl chr)   */
Xint	dir;			/* Search direction			 */
Xint	sts;			/* Search status			 */
X{
X    register LINE *curline;		/* current line during scan	      */
X    register int curoff;		/* position within current line	      */
X    register int buffchar;		/* character at current position      */
X    int status;				/* how well things go		      */
X
X    if (!sts) return(FALSE);		/* Don't try unless ok so far	      */
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure     */
X    curoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    if (dir > 0)			/* If searching forward		      */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		      */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	      */
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	      */
X	    curoff = 0;			/* Start at the beginning of the line */
X	    buffchar = '\n';		/* And say the next char is NL	      */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	      */
X	if (status = eq(buffchar, chr))	/* Is it what we're looking for?      */
X	{
X	    curwp->w_dotp = curline;	/* Yes, set the buffer's point	      */
X	    curwp->w_doto = curoff;	/*  to the matched character	      */
X	    curwp->w_flag |= WFMOVE;	/* Say that we've moved		      */
X	}
X	return (status);		/* And return the status	      */
X    } else				/* Else, if reverse search:	      */
X	return (match_pat (patrn));	/* See if we're in the right place    */
X}
X
X/*
X * This hack will search for the next occurrence of <pat> in the buffer, either
X * forward or backward.  It is called with the status of the prior search
X * attempt, so that it knows not to bother if it didn't work last time.  If
X * we can't find any more matches, "point" is left where it was before.  If
X * we do find a match, "point" will be at the end of the matched string for
X * forward searches and at the beginning of the matched string for reverse
X * searches.
X */
X 
Xint scanmore(patrn,dir,sts)	/* search forward or back for a pattern	      */
Xchar	*patrn;			/* string to scan for			      */
Xint	dir;			/* direction to search			      */
Xint	sts;			/* previous search status		      */
X{
X    if ((sts) &&		/* don't try unless successful last time      */
X        (patrn[0] != '\0'))	/* and there is something to search for	      */
X    {
X    	if (dir < 0)				/* reverse search?	      */
X	    sts = bakscan(patrn);		/* Yes, call our hacky routine*/
X	else
X	    sts = forscan(patrn,PTEND);		/* Nope. Go forward	      */
X    }
X    else
X	(*term.t_beep)();			/* Feep if search fails       */
X
X    return(sts);				/* else, don't even try	      */
X}
X
X/*
X * The following is a minimal implementation of the reverse of "forscan".
X * We aren't using the routine in SEARCH.C because it likes to type stuff,
X * but the real solution is probably to fix that instead of duplicate the
X * code here like we're doing.  On the other hand, we don't want to touch
X * more modules than we have to for this first round ...
X *
X * This always leaves "." at the beginning of the matched pattern string
X */
X
Xint bakscan (patrn)		/* Scan backwards for a match		      */
Xchar	*patrn;			/* Search string to be matched		      */
X{
X    LINE *initline;			/* initial line pointer before scan   */
X    int initoff;			/* position within initial line	      */
X
X    /* Remember "point" on entry: */
X
X    initline = curwp->w_dotp;		/* Get the current line structure     */
X    initoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    /*
X     * Loop here, stepping the cursor until we match or until we reach the top
X     * of the buffer
X     */
X
X    while (backchar(TRUE, 1))			/* As long as there're chars  */
X	if (match_pat (patrn))			/* See if we match	      */
X	    return (TRUE);			/* Yep.  Stop'er right here   */
X    curwp->w_dotp = initline;			/* Top of buffer, just reset  */
X    curwp->w_doto = initoff;			/*   to original "point"      */
X    curwp->w_flag |= WFMOVE;			/* In case backchar moved us  */
X    return (FALSE);				/* And return failure	      */
X}
X
X/*
X * The following is a worker subroutine used by the reverse search.  It
X * compares the pattern string with the characters at "." for equality. If
X * any characters mismatch, it will return FALSE.
X *
X * This isn't used for forward searches, because forward searches leave "."
X * at the end of the search string (instead of in front), so all that needs to
X * be done is match the last char input.
X */
X
Xint match_pat (patrn)	/* See if the pattern string matches string at "."   */
Xchar	*patrn;		/* String to match to buffer			     */
X{
X    register int  i;			/* Generic loop index/offset	      */
X    register int buffchar;		/* character at current position      */
X    register LINE *curline;		/* current line during scan	      */
X    register int curoff;		/* position within current line	      */
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure     */
X    curoff  = curwp->w_doto;		/* Get the offset within that line    */
X
X    /* top of per character compare loop: */
X
X    for (i = 0; i < strlen(patrn); i++)	/* Loop for all characters in patrn   */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		      */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	      */
X	    curoff = 0;			/* Start at the beginning of the line */
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	      */
X	    buffchar = '\n';		/* And say the next char is NL	      */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	      */
X	if (!eq(buffchar, patrn[i]))	/* Is it what we're looking for?      */
X	    return (FALSE);		/* Nope, just punt it then	      */
X    }
X    return (TRUE);			/* Everything matched? Let's celebrate*/
X}
X
X/* Routine to prompt for I-Search string. */
X
Xint promptpattern(prompt)
Xchar *prompt;
X{
X    register int s;
X    char tpat[NPAT+20];
X
X    strcpy(tpat, prompt);		/* copy prompt to output string */
X    strcat(tpat, " [");			/* build new prompt string */
X    expandp(pat, &tpat[strlen(tpat)], NPAT/2);	/* add old pattern */
X    strcat(tpat, "]<ESC>: ");
X
X    /* check to see if we are executing a command line */
X    if (!clexec) {
X	mlwrite(tpat);
X    }
X    return(strlen(tpat));
X}
X
X/* routine to echo i-search characters */
X
Xint echochar(c,col)
Xint	c;	/* character to be echoed */
Xint	col;	/* column to be echoed in */
X{
X    movecursor(term.t_nrow,col);		/* Position the cursor	      */
X    if ((c < ' ') || (c == 0x7F))		/* Control character?	      */
X    {
X	switch (c)				/* Yes, dispatch special cases*/
X	{
X	  case '\n':				/* Newline		      */
X	    (*term.t_putchar)('<');
X	    (*term.t_putchar)('N');
X	    (*term.t_putchar)('L');
X	    (*term.t_putchar)('>');
X	    col += 3;
X	    break;
X
X	  case '\t':				/* Tab			      */
X	    (*term.t_putchar)('<');
X	    (*term.t_putchar)('T');
X	    (*term.t_putchar)('A');
X	    (*term.t_putchar)('B');
X	    (*term.t_putchar)('>');
X	    col += 4;
X	    break;
X
X	  case 0x7F:				/* Rubout:		      */
X	    (*term.t_putchar)('^');		/* Output a funny looking     */
X	    (*term.t_putchar)('?');		/*  indication of Rubout      */
X	    col++;				/* Count the extra char       */
X	    break;
X
X	  default:				/* Vanilla control char       */
X	    (*term.t_putchar)('^');		/* Yes, output prefix	      */
X    	    (*term.t_putchar)(c+0x40);		/* Make it "^X"		      */
X	    col++;				/* Count this char	      */
X	}
X    } else
X	(*term.t_putchar)(c);			/* Otherwise, output raw char */
X    (*term.t_flush)();				/* Flush the output	      */
X    return(++col);				/* return the new column no   */
X}
X
X/*
X * Routine to get the next character from the input stream.  If we're reading
X * from the real terminal, force a screen update before we get the char. 
X * Otherwise, we must be re-executing the command string, so just return the
X * next character.
X */
X
Xint get_char ()
X{
X    int	c;				/* A place to get a character	      */
X
X    update();				/* Pretty up the screen		      */
X    c = (*term.t_getchar)();		/* Get the next character	      */
X    return (c);				/* Return the character		      */
X}
X
X/*
X * Hacky routine to re-eat a character.  This will save the character to be
X * re-eaten by redirecting the input call to a routine here.  Hack, etc.
X */
X
X/* Come here on the next term.t_getchar call: */
X
Xint un_eat()
X{
X    char c;
X    term.t_getchar = saved_get_char;	/* restore the routine address	      */
X    c = eaten_char;			/* Get the re-eaten char	      */
X    eaten_char = -1;			/* Clear the old char		      */
X    return (c);				/* and return the last char	      */
X}
X
Xint re_eat(c)
Xchar	c;
X{
X    if (eaten_char != -1)		/* If we've already been here	      */
X	return (NULL);			/* Don't do it again		      */
X    eaten_char = c;			/* Else, save the char for later      */
X    saved_get_char = term.t_getchar;	/* Save the char get routine	      */
X    term.t_getchar = un_eat;		/* Replace it with ours		      */
X}
FRIDAY_NIGHT
echo isearch.shar.1 completed!
# That's all folks!




-------------------------------------------------------------------
Richard G. Knowles           tektronix!pogo!richk
Tektronix, Inc
Del. Sta. 63-356
P.O. Box 1000
Wilsonville, Or 97070