[mod.sources] v09i041: MicroEMACS, version 3.8b, Part09/14

sources-request@mirror.TMC.COM (03/18/87)

Submitted by: ihnp4!itivax!duncan!lawrence (Daniel Lawrence)
Mod.sources: Volume 9, Issue 41
Archive-name: uemacs3.8b/Part09

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
#		"End of archive 9 (of 14)."
# Contents:  file.c isearch.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"file.c\" \(18229 characters\)
if test -f file.c ; then 
  echo shar: Will not over-write existing file \"file.c\"
else
sed "s/^X//" >file.c <<'END_OF_file.c'
X/*	FILE.C:   for MicroEMACS
X
X	The routines in this file handle the reading, writing
X	and lookup of disk files.  All of details about the
X	reading and writing of the disk are in "fileio.c".
X
X*/
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if	MEGAMAX
Xoverlay "file"
X#endif
X
X/*
X * Read a file into the current
X * buffer. This is really easy; all you do it
X * find the name of the file, and call the standard
X * "read a file into the current buffer" code.
X * Bound to "C-X C-R".
X */
Xfileread(f, n)
X{
X        register int    s;
X        char fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
X                return(s);
X        return(readin(fname, TRUE));
X}
X
X/*
X * Insert a file into the current
X * buffer. This is really easy; all you do it
X * find the name of the file, and call the standard
X * "insert a file into the current buffer" code.
X * Bound to "C-X C-I".
X */
Xinsfile(f, n)
X{
X        register int    s;
X        char fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
X                return(s);
X        return(ifile(fname));
X}
X
X/*
X * Select a file for editing.
X * Look around to see if you can find the
X * fine in another buffer; if you can find it
X * just switch to the buffer. If you cannot find
X * the file, create a new buffer, read in the
X * text, and switch to the new buffer.
X * Bound to C-X C-F.
X */
Xfilefind(f, n)
X{
X        char fname[NFILEN];	/* file user wishes to find */
X        register int s;		/* status return */
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
X                return(s);
X	return(getfile(fname, TRUE));
X}
X
Xviewfile(f, n)	/* visit a file in VIEW mode */
X{
X        char fname[NFILEN];	/* file user wishes to find */
X        register int s;		/* status return */
X	register WINDOW *wp;	/* scan for windows that need updating */
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
X                return (s);
X	s = getfile(fname, FALSE);
X	if (s) {	/* if we succeed, put it in view mode */
X		curwp->w_bufp->b_mode |= MDVIEW;
X
X		/* scan through and update mode lines of all windows */
X		wp = wheadp;
X		while (wp != NULL) {
X			wp->w_flag |= WFMODE;
X			wp = wp->w_wndp;
X		}
X	}
X	return(s);
X}
X
X#if	CRYPT
Xresetkey()	/* reset the encryption key if needed */
X
X{
X	register int s;	/* return status */
X
X	/* turn off the encryption flag */
X	cryptflag = FALSE;
X
X	/* if we are in crypt mode */
X	if (curbp->b_mode & MDCRYPT) {
X		if (curbp->b_key[0] == 0) {
X			s = setkey(FALSE, 0);
X			if (s != TRUE)
X				return(s);
X		}
X
X		/* let others know... */
X		cryptflag = TRUE;
X
X		/* and set up the key to be used! */
X		/* de-encrypt it */
X		crypt((char *)NULL, 0);
X		crypt(curbp->b_key, strlen(curbp->b_key));
X
X		/* re-encrypt it...seeding it to start */
X		crypt((char *)NULL, 0);
X		crypt(curbp->b_key, strlen(curbp->b_key));
X	}
X
X	return(TRUE);
X}
X#endif
X
Xgetfile(fname, lockfl)
X
Xchar fname[];		/* file name to find */
Xint lockfl;		/* check the file for locks? */
X
X{
X        register BUFFER *bp;
X        register LINE   *lp;
X        register int    i;
X        register int    s;
X        char bname[NBUFN];	/* buffer name to put file */
X
X        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
X                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
X			swbuffer(bp);
X                        lp = curwp->w_dotp;
X                        i = curwp->w_ntrows/2;
X                        while (i-- && lback(lp)!=curbp->b_linep)
X                                lp = lback(lp);
X                        curwp->w_linep = lp;
X                        curwp->w_flag |= WFMODE|WFHARD;
X                        mlwrite("[Old buffer]");
X                        return (TRUE);
X                }
X        }
X        makename(bname, fname);                 /* New buffer name.     */
X        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
X                s = mlreply("Buffer name: ", bname, NBUFN);
X                if (s == ABORT)                 /* ^G to just quit      */
X                        return (s);
X                if (s == FALSE) {               /* CR to clobber it     */
X                        makename(bname, fname);
X                        break;
X                }
X        }
X        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
X                mlwrite("Cannot create buffer");
X                return (FALSE);
X        }
X        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
X                curbp->b_dotp = curwp->w_dotp;
X                curbp->b_doto = curwp->w_doto;
X                curbp->b_markp = curwp->w_markp;
X                curbp->b_marko = curwp->w_marko;
X        }
X        curbp = bp;                             /* Switch to it.        */
X        curwp->w_bufp = bp;
X        curbp->b_nwnd++;
X        return(readin(fname, lockfl));          /* Read it in.          */
X}
X
X/*
X * Read file "fname" into the current
X * buffer, blowing away any text found there. Called
X * by both the read and find commands. Return the final
X * status of the read. Also called by the mainline,
X * to read in a file specified on the command line as
X * an argument. If the filename ends in a ".c", CMODE is
X * set for the current buffer.
X */
Xreadin(fname, lockfl)
X
Xchar    fname[];	/* name of file to read */
Xint	lockfl;		/* check for file locks? */
X
X{
X        register LINE   *lp1;
X        register LINE   *lp2;
X        register int    i;
X        register WINDOW *wp;
X        register BUFFER *bp;
X        register int    s;
X        register int    nbytes;
X        register int    nline;
X	register char	*sptr;		/* pointer into filename string */
X	int		lflag;		/* any lines longer than allowed? */
X        char            line[NLINE];
X
X#if	FILOCK
X	if (lockfl && lockchk(fname) == ABORT)
X		return(ABORT);
X#endif
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X        bp = curbp;                             /* Cheap.               */
X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
X                return (s);
X        bp->b_flag &= ~(BFINVS|BFCHG);
X#if	ACMODE
X	if (strlen(fname) > 1) {		/* check if a 'C' file	*/
X		sptr = fname + strlen(fname) - 2;
X		if (*sptr == '.' &&
X		   (*(sptr + 1) == 'c' || *(sptr + 1) == 'h'))
X			bp->b_mode |= MDCMOD;
X	}
X#endif
X        strcpy(bp->b_fname, fname);
X
X	/* turn off ALL keyboard translation in case we get a dos error */
X	TTkclose();
X
X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
X                goto out;
X        if (s == FIOFNF) {                      /* File not found.      */
X                mlwrite("[New file]");
X                goto out;
X        }
X        mlwrite("[Reading file]");
X        nline = 0;
X	lflag = FALSE;
X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
X            || s == FIOFUN) {
X		if (s == FIOLNG) {
X			lflag = TRUE;
X			--nline;
X		}
X                nbytes = strlen(line);
X                if ((lp1=lalloc(nbytes)) == NULL) {
X                        s = FIOERR;             /* Keep message on the  */
X                        break;                  /* display.             */
X                }
X                lp2 = lback(curbp->b_linep);
X                lp2->l_fp = lp1;
X                lp1->l_fp = curbp->b_linep;
X                lp1->l_bp = lp2;
X                curbp->b_linep->l_bp = lp1;
X                for (i=0; i<nbytes; ++i)
X                        lputc(lp1, i, line[i]);
X                ++nline;
X                if (s == FIOFUN)
X                	break;
X        }
X        ffclose();                              /* Ignore errors.       */
X	strcpy(line, "[");
X	if (lflag)
X		strcat(line, "Long lines wrapped, ");
X	if (s == FIOFUN)
X		strcat(line, "Funny line at EOF, ");
X        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
X		sprintf(&line[strlen(line)], "Read %d line", nline);
X                if (nline > 1)
X			strcat(line, "s");
X		strcat(line, "]");
X        }
X	if (s != FIOERR)
X		mlwrite(line);
X
Xout:
X	TTkopen();	/* open the keyboard again */
X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
X                if (wp->w_bufp == curbp) {
X                        wp->w_linep = lforw(curbp->b_linep);
X                        wp->w_dotp  = lforw(curbp->b_linep);
X                        wp->w_doto  = 0;
X                        wp->w_markp = NULL;
X                        wp->w_marko = 0;
X                        wp->w_flag |= WFMODE|WFHARD;
X                }
X        }
X        if (s == FIOERR || s == FIOFNF)		/* False if error.      */
X                return(FALSE);
X        return (TRUE);
X}
X
X/*
X * Take a file name, and from it
X * fabricate a buffer name. This routine knows
X * about the syntax of file names on the target system.
X * I suppose that this information could be put in
X * a better place than a line of code.
X */
Xmakename(bname, fname)
Xchar    bname[];
Xchar    fname[];
X{
X        register char   *cp1;
X        register char   *cp2;
X
X        cp1 = &fname[0];
X        while (*cp1 != 0)
X                ++cp1;
X
X#if     AMIGA
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
X                --cp1;
X#endif
X#if     VMS
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
X                --cp1;
X#endif
X#if     CPM
X        while (cp1!=&fname[0] && cp1[-1]!=':')
X                --cp1;
X#endif
X#if     MSDOS
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
X                --cp1;
X#endif
X#if     FINDER
X        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
X                --cp1;
X#endif
X#if     V7 | USG | BSD
X        while (cp1!=&fname[0] && cp1[-1]!='/')
X                --cp1;
X#endif
X        cp2 = &bname[0];
X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
X                *cp2++ = *cp1++;
X        *cp2 = 0;
X}
X
X/*
X * Ask for a file name, and write the
X * contents of the current buffer to that file.
X * Update the remembered file name and clear the
X * buffer changed flag. This handling of file names
X * is different from the earlier versions, and
X * is more compatable with Gosling EMACS than
X * with ITS EMACS. Bound to "C-X C-W".
X */
Xfilewrite(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X        char            fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
X                return (s);
X        if ((s=writeout(fname)) == TRUE) {
X                strcpy(curbp->b_fname, fname);
X                curbp->b_flag &= ~BFCHG;
X                wp = wheadp;                    /* Update mode lines.   */
X                while (wp != NULL) {
X                        if (wp->w_bufp == curbp)
X                                wp->w_flag |= WFMODE;
X                        wp = wp->w_wndp;
X                }
X        }
X        return (s);
X}
X
X/*
X * Save the contents of the current
X * buffer in its associatd file. No nothing
X * if nothing has changed (this may be a bug, not a
X * feature). Error if there is no remembered file
X * name for the buffer. Bound to "C-X C-S". May
X * get called by "C-Z".
X */
Xfilesave(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X
X	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
X		return(rdonly());	/* we are in read only mode	*/
X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
X                return (TRUE);
X        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
X                mlwrite("No file name");
X                return (FALSE);
X        }
X        if ((s=writeout(curbp->b_fname)) == TRUE) {
X                curbp->b_flag &= ~BFCHG;
X                wp = wheadp;                    /* Update mode lines.   */
X                while (wp != NULL) {
X                        if (wp->w_bufp == curbp)
X                                wp->w_flag |= WFMODE;
X                        wp = wp->w_wndp;
X                }
X        }
X        return (s);
X}
X
X/*
X * This function performs the details of file
X * writing. Uses the file management routines in the
X * "fileio.c" package. The number of lines written is
X * displayed. Sadly, it looks inside a LINE; provide
X * a macro for this. Most of the grief is error
X * checking of some sort.
X */
Xwriteout(fn)
Xchar    *fn;
X{
X        register int    s;
X        register LINE   *lp;
X        register int    nline;
X
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X	/* turn off ALL keyboard translation in case we get a dos error */
X	TTkclose();
X
X        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
X		TTkopen();
X                return (FALSE);
X        }
X	mlwrite("[Writing..]");			/* tell us were writing */
X        lp = lforw(curbp->b_linep);             /* First line.          */
X        nline = 0;                              /* Number of lines.     */
X        while (lp != curbp->b_linep) {
X                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
X                        break;
X                ++nline;
X                lp = lforw(lp);
X        }
X        if (s == FIOSUC) {                      /* No write error.      */
X                s = ffclose();
X                if (s == FIOSUC) {              /* No close error.      */
X                        if (nline == 1)
X                                mlwrite("[Wrote 1 line]");
X                        else
X                                mlwrite("[Wrote %d lines]", nline);
X                }
X        } else                                  /* Ignore close error   */
X                ffclose();                      /* if a write error.    */
X	TTkopen();
X        if (s != FIOSUC)                        /* Some sort of error.  */
X                return (FALSE);
X        return (TRUE);
X}
X
X/*
X * The command allows the user
X * to modify the file name associated with
X * the current buffer. It is like the "f" command
X * in UNIX "ed". The operation is simple; just zap
X * the name in the BUFFER structure, and mark the windows
X * as needing an update. You can type a blank line at the
X * prompt if you wish.
X */
Xfilename(f, n)
X{
X        register WINDOW *wp;
X        register int    s;
X        char            fname[NFILEN];
X
X	if (restflag)		/* don't allow this command if restricted */
X		return(resterr());
X        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
X                return (s);
X        if (s == FALSE)
X                strcpy(curbp->b_fname, "");
X        else
X                strcpy(curbp->b_fname, fname);
X        wp = wheadp;                            /* Update mode lines.   */
X        while (wp != NULL) {
X                if (wp->w_bufp == curbp)
X                        wp->w_flag |= WFMODE;
X                wp = wp->w_wndp;
X        }
X	curbp->b_mode &= ~MDVIEW;	/* no longer read only mode */
X        return (TRUE);
X}
X
X/*
X * Insert file "fname" into the current
X * buffer, Called by insert file command. Return the final
X * status of the read.
X */
Xifile(fname)
Xchar    fname[];
X{
X        register LINE   *lp0;
X        register LINE   *lp1;
X        register LINE   *lp2;
X        register int    i;
X        register BUFFER *bp;
X        register int    s;
X        register int    nbytes;
X        register int    nline;
X	int		lflag;		/* any lines longer than allowed? */
X        char            line[NLINE];
X
X        bp = curbp;                             /* Cheap.               */
X        bp->b_flag |= BFCHG;			/* we have changed	*/
X	bp->b_flag &= ~BFINVS;			/* and are not temporary*/
X        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
X                goto out;
X        if (s == FIOFNF) {                      /* File not found.      */
X                mlwrite("[No such file]");
X		return(FALSE);
X        }
X        mlwrite("[Inserting file]");
X
X#if	CRYPT
X	s = resetkey();
X	if (s != TRUE)
X		return(s);
X#endif
X	/* back up a line and save the mark here */
X	curwp->w_dotp = lback(curwp->w_dotp);
X	curwp->w_doto = 0;
X	curwp->w_markp = curwp->w_dotp;
X	curwp->w_marko = 0;
X
X        nline = 0;
X	lflag = FALSE;
X        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
X            || s == FIOFUN) {
X		if (s == FIOLNG) {
X			lflag = TRUE;
X			--nline;
X		}
X                nbytes = strlen(line);
X                if ((lp1=lalloc(nbytes)) == NULL) {
X                        s = FIOERR;             /* Keep message on the  */
X                        break;                  /* display.             */
X                }
X		lp0 = curwp->w_dotp;	/* line previous to insert */
X		lp2 = lp0->l_fp;	/* line after insert */
X
X		/* re-link new line between lp0 and lp2 */
X		lp2->l_bp = lp1;
X		lp0->l_fp = lp1;
X		lp1->l_bp = lp0;
X		lp1->l_fp = lp2;
X
X		/* and advance and write out the current line */
X		curwp->w_dotp = lp1;
X                for (i=0; i<nbytes; ++i)
X                        lputc(lp1, i, line[i]);
X                ++nline;
X                if (s == FIOFUN)
X                	break;
X        }
X        ffclose();                              /* Ignore errors.       */
X	curwp->w_markp = lforw(curwp->w_markp);
X	strcpy(line, "[");
X	if (lflag)
X		strcat(line, "Long lines wrapped, ");
X	if (s == FIOFUN)
X		strcat(line, "Funny line at EOF, ");
X        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
X		sprintf(&line[strlen(line)], "Inserted %d line", nline);
X                if (nline > 1)
X			strcat(line, "s");
X		strcat(line, "]");
X        }
X	if (s != FIOERR)
X		mlwrite(line);
Xout:
X	/* advance to the next line and mark the window for changes */
X	curwp->w_dotp = lforw(curwp->w_dotp);
X	curwp->w_flag |= WFHARD | WFMODE;
X
X	/* copy window parameters back to the buffer structure */
X	curbp->b_dotp = curwp->w_dotp;
X	curbp->b_doto = curwp->w_doto;
X	curbp->b_markp = curwp->w_markp;
X	curbp->b_marko = curwp->w_marko;
X
X        if (s == FIOERR)                        /* False if error.      */
X                return (FALSE);
X        return (TRUE);
X}
END_OF_file.c
if test 18229 -ne `wc -c <file.c`; then
    echo shar: \"file.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: Extracting \"isearch.c\" \(18764 characters\)
if test -f isearch.c ; then 
  echo shar: Will not over-write existing file \"isearch.c\"
else
sed "s/^X//" >isearch.c <<'END_OF_isearch.c'
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 *	John M. Gamble 5-Oct-86
X *	- Made iterative search use search.c's scanner() routine.
X *	  This allowed the elimination of bakscan().
X *	- Put isearch constants into esearch.h
X *	- Eliminated the passing of 'status' to scanmore() and
X *	  checknext(), since there were no circumstances where
X *	  it ever equalled FALSE.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X#include	"esearch.h"
X
X#if	ISRCH
X
Xextern int scanner();			/* Handy search routine */
Xextern int eq();			/* Compare chars, match case */
Xextern char tap[];			/* Reverse pattern array.*/
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
Xint	cmd_buff[CMDBUFLEN];		/* Save the command args here */
Xint	cmd_offset;			/* Current offset into command buff */
Xint	cmd_reexecute = -1;		/* > 0 if re-executing command */
X
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(FALSE);			/* 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(FALSE);			/* 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, META 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;		/* prompt column */
X    register int	cpos;		/* character number in search string  */
X    register int	c;		/* current input character */
X    register int	expc;		/* function expanded input char	      */
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    cmd_reexecute = -1;		/* We're not re-executing (yet?)      */
X    cmd_offset = 0;			/* Start at the beginning of the buff */
X    cmd_buff[0] = '\0';		/* Init the command buffer	      */
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    /* This is a good place to start a re-execution: */
X
Xstart_over:
X
X    /* ask the user for the text of a pattern */
X    col = promptpattern("ISearch: ");		/* Prompt, remember the col   */
X
X    cpos = 0;					/* Start afresh		      */
X    status = 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 = ectoc(expc = 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);		/* Do the search	      */
X	c = ectoc(expc = 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 special characters first: */
X	/* Most cases here change the search */
X
X	if (expc == metac)			/* Want to quit searching?    */
X	    return (TRUE);			/* Quit searching now	      */
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		n = -1;				/* Set the reverse direction  */
X	    else				/* Otherwise, 		      */
X		n = 1;				/*  go forward		      */
X	    status = scanmore(pat, n);		/* Start the search again     */
X	    c = ectoc(expc = get_char());	/* Get the next char	      */
X	    continue;				/* Go continue with the search*/
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 = ectoc(expc = get_char());	/* Get the next char	      */
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 (cmd_offset <= 1)		/* Anything to delete?	      */
X		return (TRUE);			/* No, just exit	      */
X	    --cmd_offset;			/* Back up over the Rubout    */
X	    cmd_buff[--cmd_offset] = '\0';	/* Yes, delete last char   */
X	    curwp->w_dotp = curline;		/* Reset the line pointer     */
X	    curwp->w_doto = curoff;		/*  and the offset	      */
X	    n = init_direction;			/* Reset the search direction */
X	    strncpy (pat, pat_save, NPAT);	/* Restore the old search str */
X	    cmd_reexecute = 0;			/* Start the whole mess over  */
X	    goto start_over;			/* Let it take care of itself */
X
X	  /* Presumably a quasi-normal character comes here */
X
X	  default:				/* All other chars    	      */
X	    if (c < ' ')			/* Is it printable?	      */
X	    {					/* Nope.		      */
X		reeat (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	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	    TTputc(BELL);		/* Feep again		      */
X	    TTflush();			/* see that the feep feeps    */
X	} else					/* Otherwise, we must have won*/
X	    if (!(status = checknext(c, pat, n))) /* See if match	      */
X		status = scanmore(pat, n);	/*  or find the next match    */
X	c = ectoc(expc = get_char());		/* Get the next char	      */
X    } /* for {;;} */
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)	/* 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			 */
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
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)	/* search forward or back for a pattern	      */
Xchar	*patrn;			/* string to scan for			      */
Xint	dir;			/* direction to search			      */
X{
X	int	sts;			/* search status		      */
X
X    	if (dir < 0)				/* reverse search?	      */
X    	{
X		rvstrcpy(tap, patrn);		/* Put reversed string in tap */
X		sts = scanner(tap, REVERSE, PTBEG);
X	}
X	else
X		sts = scanner(patrn, FORWARD, PTEND);	/* Nope. Go forward   */
X
X	if (!sts)
X	{
X		TTputc(BELL);	/* Feep if search fails       */
X		TTflush();		/* see that the feep feeps    */
X	}
X
X	return(sts);				/* else, don't even try	      */
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    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, "]<META>: ");
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	    TTputc('<');
X	    TTputc('N');
X	    TTputc('L');
X	    TTputc('>');
X	    col += 3;
X	    break;
X
X	  case '\t':				/* Tab			      */
X	    TTputc('<');
X	    TTputc('T');
X	    TTputc('A');
X	    TTputc('B');
X	    TTputc('>');
X	    col += 4;
X	    break;
X
X	  case 0x7F:				/* Rubout:		      */
X	    TTputc('^');		/* Output a funny looking     */
X	    TTputc('?');		/*  indication of Rubout      */
X	    col++;				/* Count the extra char       */
X	    break;
X
X	  default:				/* Vanilla control char       */
X	    TTputc('^');		/* Yes, output prefix	      */
X    	    TTputc(c+0x40);		/* Make it "^X"		      */
X	    col++;				/* Count this char	      */
X	}
X    } else
X	TTputc(c);			/* Otherwise, output raw char */
X    TTflush();				/* 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    /* See if we're re-executing: */
X
X    if (cmd_reexecute >= 0)		/* Is there an offset?		      */
X	if ((c = cmd_buff[cmd_reexecute++]) != 0)
X	    return (c);			/* Yes, return any character	      */
X
X    /* We're not re-executing (or aren't any more).  Try for a real char      */
X
X    cmd_reexecute = -1;		/* Say we're in real mode again	      */
X    update(FALSE);			/* Pretty up the screen		      */
X    if (cmd_offset >= CMDBUFLEN-1)	/* If we're getting too big ...	      */
X    {
X	mlwrite ("? command too long");	/* Complain loudly and bitterly	      */
X	return (metac);			/* And force a quit		      */
X    }
X    c = get1key();		/* Get the next character	      */
X    cmd_buff[cmd_offset++] = c; /* Save the char for next time        */
X    cmd_buff[cmd_offset] = '\0';/* And terminate the buffer	      */
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 uneat()
X{
X    int c;
X
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 reeat(c)
Xint	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 = uneat;		/* Replace it with ours		      */
X}
X#else
Xisearch()
X{
X}
X#endif
END_OF_isearch.c
if test 18764 -ne `wc -c <isearch.c`; then
    echo shar: \"isearch.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 9 \(of 14\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 archives.
    echo "See the readme file"
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0