[mod.sources] v06i075: MicroEmacs, Version 3.7

sources-request@mirror.UUCP (07/30/86)

Submitted by: ihnp4!pur-ee!pur-phy!duncan!lawrence
Mod.sources: Volume 6, Issue 75
Archive-name: uEmacs3.7/Part05

[  This is the latest revision of one of two programs named "MicroEmacs";
   when discussing these on the net, or in contacting the authors, make
   sure to mention the version number -- in this case 3.7 -- as that is
   the easiest way to distinguish between them.  Daniel will be posting
   uuencoded executables in net.micro.pc and net.micro.amiga; the file
   'readme' contains information on how to also get these from him
   directly.   --r$ ]

echo extracting - epath.h
sed 's/^X//' > epath.h << 'FRIDAY_NIGHT'
X/*	PATH:	This file contains certain info needed to locate the
X		MicroEMACS files on a system dependant basis.
X
X									*/
X
X/*	possible names and paths of help files under different OSs	*/
X
Xchar *pathname[] =
X
X#if	AMIGA
X{
X	".emacsrc",
X	"emacs.hlp",
X	"",
X	":c/",
X	":t/"
X};
X#endif
X
X#if	MSDOS
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"\\sys\\public\\",
X	"\\usr\\bin\\",
X	"\\bin\\",
X	"\\",
X	""
X};
X#endif
X
X#if	V7 | BSD | USG
X{
X	".emacsrc",
X	"emacs.hlp",
X	"/usr/local/",
X	"/usr/lib/",
X	""
X};
X#endif
X
X#if	VMS
X{
X	"emacs.rc",
X	"emacs.hlp",
X	"",
X	"sys$sysdevice:[vmstools]"
X};
X#endif
X
X#define	NPNAMES	(sizeof(pathname)/sizeof(char *))
FRIDAY_NIGHT
echo extracting - estruct.h
sed 's/^X//' > estruct.h << 'FRIDAY_NIGHT'
X/*	ESTRUCT:	Structure and preprocesser defined for
X			MicroEMACS 3.7
X
X			written by Dave G. Conroy
X			modified by Steve Wilhite, George Jones
X			greatly modified by Daniel Lawrence
X*/
X
X#undef	LATTICE		/* don't use their definitions...use ours	*/
X#undef	MSDOS
X#undef	CPM
X#undef	AMIGA
X
X/*	Machine/OS definitions			*/
X
X#define AMIGA   0                       /* AmigaDOS			*/
X#define ST520   0                       /* ST520, TOS                   */
X#define MSDOS   0                       /* MS-DOS                       */
X#define V7      1                       /* V7 UN*X or Coherent or BSD4.2*/
X#define	BSD	0			/* UNIX BSD 4.2	and ULTRIX	*/
X#define	USG	0			/* UNIX system V		*/
X#define VMS     0                       /* VAX/VMS                      */
X#define CPM     0                       /* CP/M-86                      */
X
X/*	Compiler definitions			*/
X#define MWC86   0	/* marc williams compiler */
X#define	LATTICE	0	/* either lattice compiler */
X#define	LAT2	0	/* Lattice 2.15 */
X#define	LAT3	0	/* Lattice 3.0 */
X#define	AZTEC	0	/* Aztec C 3.20e */
X#define	MSC	0	/* MicroSoft C compile version 3 */
X
X/*	Profiling options	*/
X#define	APROF	0	/* turn Aztec C profiling on? */
X#define	NBUCK	100	/* number of buckets to profile */
X
X/*   Special keyboard definitions            */
X 
X#define WANGPC	0			/* WangPC - mostly escape sequences     */
X 
X/*	Terminal Output definitions		*/
X
X#define ANSI    0			/* ansi escape sequences	*/
X#define	HP150	0			/* HP150 screen driver		*/
X#define	VMSVT	0			/* various VMS terminal entries	*/
X#define VT52    0                       /* VT52 terminal (Zenith).      */
X#define VT100   0                       /* Handle VT100 style keypad.   */
X#define LK201   0                       /* Handle LK201 style keypad.   */
X#define RAINBOW 0                       /* Use Rainbow fast video.      */
X#define TERMCAP 1                       /* Use TERMCAP                  */
X#define	IBMPC	0			/* IBM-PC specific driver	*/
X#define	DG10	0			/* Data General system/10	*/
X
X/*	Configuration options	*/
X
X#define CVMVAS  1	/* arguments to page forward/back in pages	*/
X#define	NFWORD	1	/* forward word jumps to begining of word	*/
X#define	CLRMSG	0	/* space clears the message line with no insert	*/
X#define	TYPEAH	1	/* type ahead causes update to be skipped	*/
X#define	FILOCK	0	/* file locking under unix BSD 4.2		*/
X#define	REVSTA	1	/* Status line appears in reverse video		*/
X#define	COLOR	0	/* color commands and windows			*/
X#define	ACMODE	1	/* auto CMODE on .C and .H files		*/
X#define	CFENCE	1	/* fench matching in CMODE			*/
X#define	ISRCH	1	/* Incremental searches like ITS EMACS		*/
X#define	WORDPRO	1	/* Advanced word processing features		*/
X
X/*	System dependant library redefinitions, structures and includes	*/
X
X#if	MSDOS & AZTEC
X#undef	fputc
X#undef	fgetc
X#define	fputc	aputc
X#define	fgetc	agetc
X#define	int86	sysint
X#define	inp	inportb
X
Xstruct XREG {
X	int ax,bx,cx,dx,si,di;
X};
X
Xstruct HREG {
X	char al,ah,bl,bh,cl,ch,dl,dh;
X};
X
Xunion REGS {
X	struct XREG x;
X	struct HREG h;
X};
X#endif
X
X#if	MSDOS & LATTICE
X#undef	CPM
X#undef	LATTICE
X#include	<dos.h>
X#undef	CPM
X#endif
X
X/*	internal constants	*/
X
X#define	NBINDS	200			/* max # of bound keys		*/
X#define NFILEN  80                      /* # of bytes, file name        */
X#define NBUFN   16                      /* # of bytes, buffer name      */
X#define NLINE   256                     /* # of bytes, line             */
X#define	NSTRING	256			/* # of bytes, string buffers	*/
X#define NKBDM   256                     /* # of strokes, keyboard macro */
X#define NPAT    80                      /* # of bytes, pattern          */
X#define HUGE    1000                    /* Huge number                  */
X#define	NLOCKS	100			/* max # of file locks active	*/
X#define	NCOLORS	8			/* number of supported colors	*/
X#define	KBLOCK	250			/* sizeof kill buffer chunks	*/
X#define	NBLOCK	16			/* line block chunk size	*/
X
X#define AGRAVE  0x60                    /* M- prefix,   Grave (LK201)   */
X#define METACH  0x1B                    /* M- prefix,   Control-[, ESC  */
X#define CTMECH  0x1C                    /* C-M- prefix, Control-\       */
X#define EXITCH  0x1D                    /* Exit level,  Control-]       */
X#define CTRLCH  0x1E                    /* C- prefix,   Control-^       */
X#define HELPCH  0x1F                    /* Help key,    Control-_       */
X
X#define CTRL    0x0100                  /* Control flag, or'ed in       */
X#define META    0x0200                  /* Meta flag, or'ed in          */
X#define CTLX    0x0400                  /* ^X flag, or'ed in            */
X#define	SPEC	0x0800			/* special key (function keys)	*/
X
X#define FALSE   0                       /* False, no, bad, etc.         */
X#define TRUE    1                       /* True, yes, good, etc.        */
X#define ABORT   2                       /* Death, ^G, abort, etc.       */
X
X#define FIOSUC  0                       /* File I/O, success.           */
X#define FIOFNF  1                       /* File I/O, file not found.    */
X#define FIOEOF  2                       /* File I/O, end of file.       */
X#define FIOERR  3                       /* File I/O, error.             */
X#define	FIOLNG	4			/*line longer than allowed len	*/
X
X#define CFCPCN  0x0001                  /* Last command was C-P, C-N    */
X#define CFKILL  0x0002                  /* Last command was a kill      */
X
X#define	BELL	0x07			/* a bell character		*/
X#define	TAB	0x09			/* a tab character		*/
X
X/*
X * There is a window structure allocated for every active display window. The
X * windows are kept in a big list, in top to bottom screen order, with the
X * listhead at "wheadp". Each window contains its own values of dot and mark.
X * The flag field contains some bits that are set by commands to guide
X * redisplay; although this is a bit of a compromise in terms of decoupling,
X * the full blown redisplay is just too expensive to run for every input
X * character.
X */
Xtypedef struct  WINDOW {
X        struct  WINDOW *w_wndp;         /* Next window                  */
X        struct  BUFFER *w_bufp;         /* Buffer displayed in window   */
X        struct  LINE *w_linep;          /* Top line in the window       */
X        struct  LINE *w_dotp;           /* Line containing "."          */
X        short   w_doto;                 /* Byte offset for "."          */
X        struct  LINE *w_markp;          /* Line containing "mark"       */
X        short   w_marko;                /* Byte offset for "mark"       */
X        char    w_toprow;               /* Origin 0 top row of window   */
X        char    w_ntrows;               /* # of rows of text in window  */
X        char    w_force;                /* If NZ, forcing row.          */
X        char    w_flag;                 /* Flags.                       */
X#if	COLOR
X	char	w_fcolor;		/* current forground color	*/
X	char	w_bcolor;		/* current background color	*/
X#endif
X}       WINDOW;
X
X#define WFFORCE 0x01                    /* Window needs forced reframe  */
X#define WFMOVE  0x02                    /* Movement from line to line   */
X#define WFEDIT  0x04                    /* Editing within a line        */
X#define WFHARD  0x08                    /* Better to a full display     */
X#define WFMODE  0x10                    /* Update mode line.            */
X#define	WFCOLR	0x20			/* Needs a color change		*/
X
X/*
X * Text is kept in buffers. A buffer header, described below, exists for every
X * buffer in the system. The buffers are kept in a big list, so that commands
X * that search for a buffer by name can find the buffer header. There is a
X * safe store for the dot and mark in the header, but this is only valid if
X * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
X * the buffer is kept in a circularly linked list of lines, with a pointer to
X * the header line in "b_linep".
X * 	Buffers may be "Inactive" which means the files accosiated with them
X * have not been read in yet. These get read in at "use buffer" time.
X */
Xtypedef struct  BUFFER {
X        struct  BUFFER *b_bufp;         /* Link to next BUFFER          */
X        struct  LINE *b_dotp;           /* Link to "." LINE structure   */
X        short   b_doto;                 /* Offset of "." in above LINE  */
X        struct  LINE *b_markp;          /* The same as the above two,   */
X        short   b_marko;                /* but for the "mark"           */
X        struct  LINE *b_linep;          /* Link to the header LINE      */
X	char	b_active;		/* window activated flag	*/
X        char    b_nwnd;                 /* Count of windows on buffer   */
X        char    b_flag;                 /* Flags                        */
X	char	b_mode;			/* editor mode of this buffer	*/
X        char    b_fname[NFILEN];        /* File name                    */
X        char    b_bname[NBUFN];         /* Buffer name                  */
X}       BUFFER;
X
X#define BFINVS  0x01                    /* Internal invisable buffer    */
X#define BFCHG   0x02                    /* Changed since last write     */
X
X/*	mode flags	*/
X#define	NUMMODES	7		/* # of defined modes		*/
X
X#define	MDWRAP	0x0001			/* word wrap			*/
X#define	MDCMOD	0x0002			/* C indentation and fence match*/
X#define	MDSPELL	0x0004			/* spell error parcing		*/
X#define	MDEXACT	0x0008			/* Exact matching for searches	*/
X#define	MDVIEW	0x0010			/* read-only buffer		*/
X#define MDOVER	0x0020			/* overwrite mode		*/
X#define MDMAGIC	0x0040			/* regular expresions in search */
X
X/*
X * The starting position of a region, and the size of the region in
X * characters, is kept in a region structure.  Used by the region commands.
X */
Xtypedef struct  {
X        struct  LINE *r_linep;          /* Origin LINE address.         */
X        short   r_offset;               /* Origin LINE offset.          */
X        long	r_size;                 /* Length in characters.        */
X}       REGION;
X
X/*
X * All text is kept in circularly linked lists of "LINE" structures. These
X * begin at the header line (which is the blank line beyond the end of the
X * buffer). This line is pointed to by the "BUFFER". Each line contains a the
X * number of bytes in the line (the "used" size), the size of the text array,
X * and the text. The end of line is not stored as a byte; it's implied. Future
X * additions will include update hints, and a list of marks into the line.
X */
Xtypedef struct  LINE {
X        struct  LINE *l_fp;             /* Link to the next line        */
X        struct  LINE *l_bp;             /* Link to the previous line    */
X        short   l_size;                 /* Allocated size               */
X        short   l_used;                 /* Used size                    */
X        char    l_text[1];              /* A bunch of characters.       */
X}       LINE;
X
X#define lforw(lp)       ((lp)->l_fp)
X#define lback(lp)       ((lp)->l_bp)
X#define lgetc(lp, n)    ((lp)->l_text[(n)]&0xFF)
X#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
X#define llength(lp)     ((lp)->l_used)
X
X/*
X * The editor communicates with the display using a high level interface. A
X * "TERM" structure holds useful variables, and indirect pointers to routines
X * that do useful operations. The low level get and put routines are here too.
X * This lets a terminal, in addition to having non standard commands, have
X * funny get and put character code too. The calls might get changed to
X * "termp->t_field" style in the future, to make it possible to run more than
X * one terminal type.
X */
Xtypedef struct  {
X        short   t_nrow;                 /* Number of rows.              */
X        short   t_ncol;                 /* Number of columns.           */
X	short	t_margin;		/* min margin for extended lines*/
X	short	t_scrsiz;		/* size of scroll region "	*/
X	int	t_pause;		/* # times thru update to pause */
X        int     (*t_open)();            /* Open terminal at the start.  */
X        int     (*t_close)();           /* Close terminal at end.       */
X        int     (*t_getchar)();         /* Get character from keyboard. */
X        int     (*t_putchar)();         /* Put character to display.    */
X        int     (*t_flush)();           /* Flush output buffers.        */
X        int     (*t_move)();            /* Move the cursor, origin 0.   */
X        int     (*t_eeol)();            /* Erase to end of line.        */
X        int     (*t_eeop)();            /* Erase to end of page.        */
X        int     (*t_beep)();            /* Beep.                        */
X	int	(*t_rev)();		/* set reverse video state	*/
X#if	COLOR
X	int	(*t_setfor)();		/* set forground color		*/
X	int	(*t_setback)();		/* set background color		*/
X#endif
X}       TERM;
X
X/*	structure for the table of initial key bindings		*/
X
Xtypedef struct  {
X        short   k_code;                 /* Key code                     */
X        int     (*k_fp)();              /* Routine to handle it         */
X}       KEYTAB;
X
X/*	structure for the name binding table		*/
X
Xtypedef struct {
X	char *n_name;		/* name of function key */
X	int (*n_func)();	/* function name is bound to */
X}	NBIND;
X
X/*	The editor holds deleted text chunks in the KILL buffer. The
X	kill buffer is logically a stream of ascii characters, however
X	due to its unpredicatable size, it gets implemented as a linked
X	list of chunks. (The d_ prefix is for "deleted" text, as k_
X	was taken up by the keycode structure			*/
X
Xtypedef	struct KILL {
X	struct KILL *d_next;	/* link to next chunk, NULL if last */
X	char d_chunk[KBLOCK];	/* deleted text */
X} KILL;
X
FRIDAY_NIGHT
echo extracting - exec.c
sed 's/^X//' > exec.c << 'FRIDAY_NIGHT'
X/*	This file is for functions dealing with execution of
X	commands, command lines, buffers, files and startup files
X
X	written 1986 by Daniel Lawrence				*/
X
X#include	<stdio.h>
X#include	"estruct.h"
X#include	"edef.h"
X
X/* namedcmd:	execute a named command even if it is not bound
X*/
X
Xnamedcmd(f, n)
X
Xint f, n;	/* command arguments [passed through to command executed] */
X
X{
X	register (*kfunc)();	/* ptr to the requexted function to bind to */
X	int (*getname())();
X
X	/* prompt the user to type a named command */
X	mlwrite(": ");
X
X	/* and now get the function name to execute */
X	kfunc = getname();
X	if (kfunc == NULL) {
X		mlwrite("[No such function]");
X		return(FALSE);
X	}
X
X	/* and then execute the command */
X	return((*kfunc)(f, n));
X}
X
X/*	execcmd:	Execute a command line command to be typed in
X			by the user					*/
X
Xexeccmd(f, n)
X
Xint f, n;	/* default Flag and Numeric argument */
X
X{
X	register int status;		/* status return */
X	char cmdstr[NSTRING];		/* string holding command to execute */
X
X	/* get the line wanted */
X	if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
X		return(status);
X
X	return(docmd(cmdstr));
X}
X
X/*	docmd:	take a passed string as a command line and translate
X		it to be executed as a command. This function will be
X		used by execute-command-line and by all source and
X		startup files.
X
X	format of the command line is:
X
X		{# arg} <command-name> {<argument string(s)>}
X
X	Macro storing is turned off by a line:
X
X		[end]
X*/
X
Xdocmd(cline)
X
Xchar *cline;	/* command line to execute */
X
X{
X	register char *tp;	/* pointer to current position in token */
X	register int f;		/* default argument flag */
X	register int n;		/* numeric repeat value */
X	register int i;
X	int sign;		/* sign of numeric argument */
X	int (*fnc)();		/* function to execute */
X	int status;		/* return status of function */
X	int oldcle;		/* old contents of clexec flag */
X	int llen;		/* length of cline */
X	struct LINE *lp;	/* a line pointer */
X	char token[NSTRING];	/* next token off of command line */
X	int (*fncmatch())();
X
X	/* check to see if this line turns macro storage off */
X	if (strcmp(cline, "[end]") == 0) {
X		mstore = FALSE;
X		bstore = NULL;
X		return(TRUE);
X	}
X
X	/* if macro store is on, just salt this away */
X	if (mstore) {
X		/* trim leading indentation */
X		while (cline[0] == ' ' || cline[0] == '\t')
X			strcpy(cline, &cline[1]);
X
X		/* allocate the space for the line */
X		llen = strlen(cline);
X		if ((lp=lalloc(llen)) == NULL) {
X			mlwrite("Out of memory while storing macro");
X			return (FALSE);
X		}
X
X		/* copy the text into the new line */
X		for (i=0; i<llen; ++i)
X			lputc(lp, i, cline[i]);
X
X		/* attach the line to the end of the buffer */
X       		bstore->b_linep->l_bp->l_fp = lp;
X		lp->l_bp = bstore->b_linep->l_bp;
X		bstore->b_linep->l_bp = lp;
X		lp->l_fp = bstore->b_linep;
X		return (TRUE);
X	}
X	
X	/* first set up the default command values */
X	f = FALSE;
X	n = 1;
X
X	strcpy(sarg, cline);	/* move string to string argument buffer */
X	if ((status = nxtarg(token)) != TRUE)	/* and grab the first token */
X		return(status);
X
X	/* check for and process numeric leadin argument */
X	if ((token[0] >= '0' && token[0] <= '9') || token[0] == '-') {
X		f = TRUE;
X		n = 0;
X		tp = &token[0];
X
X		/* check for a sign! */
X		sign = 1;
X		if (*tp == '-') {
X			++tp;
X			sign = -1;
X		}
X
X		/* calc up the digits in the token string */
X		while(*tp) {
X			if (*tp >= '0' && *tp <= '9')
X				n = n * 10 + *tp - '0';
X			++tp;
X		}
X		n *= sign;	/* adjust for the sign */
X
X		/* and now get the command to execute */
X		if ((status = nxtarg(token)) != TRUE)
X			return(status);		
X	}
X
X	/* and match the token to see if it exists */
X	if ((fnc = fncmatch(token)) == NULL) {
X		mlwrite("[No such Function]");
X		return(FALSE);
X	}
X	
X	/* save the arguments and go execute the command */
X	oldcle = clexec;		/* save old clexec flag */
X	clexec = TRUE;			/* in cline execution */
X	status = (*fnc)(f, n);		/* call the function */
X	clexec = oldcle;		/* restore clexec flag */
X	return(status);
X}
X
X/* gettok:	chop a token off a string
X		return a pointer past the token
X*/
X
Xchar *gettok(src, tok)
X
Xchar *src, *tok;	/* source string, destination token string */
X
X{
X	register int quotef;	/* is the current string quoted? */
X
X	/* first scan past any whitespace in the source string */
X	while (*src == ' ' || *src == '\t')
X		++src;
X
X	/* if quoted, record it */
X	quotef = (*src == '"');
X	if (quotef)
X		++src;
X
X	/* scan through the source string */
X	while (*src) {
X		/* process special characters */
X		if (*src == '~') {
X			++src;
X			if (*src == 0)
X				break;
X			switch (*src++) {
X				case 'r':	*tok++ = 13; break;
X				case 'n':	*tok++ = 10; break;
X				case 't':	*tok++ = 9;  break;
X				case 'b':	*tok++ = 8;  break;
X				case 'f':	*tok++ = 12; break;
X				case '@':	*tok++ = 192;break;
X				default:	*tok++ = *(src-1);
X			}
X		} else {
X			/* check for the end of the token */
X			if (quotef) {
X				if (*src == '"')
X					break;
X			} else {
X				if (*src == ' ' || *src == '\t')
X					break;
X			}
X
X			/* record the character */
X			*tok++ = *src++;
X		}
X	}
X
X	/* terminate the token and exit */
X	if (*src)
X		++src;
X	*tok = 0;
X	return(src);
X}
X
X/* nxtarg:	grab the next token out of sarg, return it, and
X		chop it of sarg					*/
X
Xnxtarg(tok)
X
Xchar *tok;	/* buffer to put token into */
X
X{
X	register char *newsarg;	/* pointer to new begining of sarg */
X	register oldexec;	/* saved execution flag */
X	register BUFFER *bp;	/* ptr to buffer to get arg from */
X	register int status;
X	char *gettok();
X
X	newsarg = gettok(sarg, tok);	/* grab the token */
X	strcpy(sarg, newsarg);		/* and chop it of sarg */
X
X	/* check for an interactive argument */
X	if (*tok == '@') {		/* get interactive argument */
X		oldexec = clexec;	/* save execution flag */
X		clexec = FALSE;
X		status = mlreply(&tok[1], &tok[0], NSTRING);
X		clexec = oldexec;
X		if (status != TRUE)
X			return(status);
X	}
X
X	/* check for a quoted "@" in the first position */
X	if (*tok == 192)
X		*tok = '@';
X
X	/* check for an argument from a buffer */
X	if (*tok == '#') {
X
X		/* get the referenced buffer */
X		bp = bfind(&tok[1], FALSE, 0);
X		if (bp == NULL)
X			return(FALSE);
X
X		/* make sure we are not at the end */
X		if (bp->b_linep == bp->b_dotp)
X			return(FALSE);
X
X		/* grab the line as an argument */
X		strncpy(tok, bp->b_dotp->l_text, bp->b_dotp->l_used);
X		tok[bp->b_dotp->l_used] = 0;
X
X		/* and step the buffer's line ptr ahead a line */
X		bp->b_dotp = bp->b_dotp->l_fp;
X		bp->b_doto = 0;
X	}
X
X	return(TRUE);
X}
X
X/*	storemac:	Set up a macro buffer and flag to store all
X			executed command lines there			*/
X
Xstoremac(f, n)
X
Xint f;		/* default flag */
Xint n;		/* macro number to use */
X
X{
X	register struct BUFFER *bp;	/* pointer to macro buffer */
X	char bname[NBUFN];		/* name of buffer to use */
X
X	/* must have a numeric argument to this function */
X	if (f == FALSE) {
X		mlwrite("No macro specified");
X		return(FALSE);
X	}
X
X	/* range check the macro number */
X	if (n < 1 || n > 40) {
X		mlwrite("Macro number out of range");
X		return(FALSE);
X	}
X
X	/* construct the macro buffer name */
X	strcpy(bname, "[Macro xx]");
X	bname[7] = '0' + (n / 10);
X	bname[8] = '0' + (n % 10);
X
X	/* set up the new macro buffer */
X	if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
X		mlwrite("Can not create macro");
X		return(FALSE);
X	}
X
X	/* and make sure it is empty */
X	bclear(bp);
X
X	/* and set the macro store pointers to it */
X	mstore = TRUE;
X	bstore = bp;
X	return(TRUE);
X}
X
X/*	execbuf:	Execute the contents of a buffer of commands	*/
X
Xexecbuf(f, n)
X
Xint f, n;	/* default flag and numeric arg */
X
X{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X        char bufn[NBUFN];		/* name of buffer to execute */
X
X	/* find out what buffer the user wants to execute */
X        if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
X                return(status);
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
X		mlwrite("No such buffer");
X                return(FALSE);
X        }
X
X	/* and now execute it as asked */
X	while (n-- > 0)
X		if ((status = dobuf(bp)) != TRUE)
X			return(status);
X	return(TRUE);
X}
X
X/*	dobuf:	execute the contents of the buffer pointed to
X		by the passed BP				*/
X
Xdobuf(bp)
X
XBUFFER *bp;	/* buffer to execute */
X
X{
X        register int status;		/* status return */
X	register LINE *lp;		/* pointer to line to execute */
X	register LINE *hlp;		/* pointer to line header */
X	register int linlen;		/* length of line to execute */
X	register WINDOW *wp;		/* ptr to windows to scan */
X	char eline[NSTRING];		/* text of line to execute */
X
X	/* starting at the beginning of the buffer */
X	hlp = bp->b_linep;
X	lp = hlp->l_fp;
X	while (lp != hlp) {
X		/* calculate the line length and make a local copy */
X		linlen = lp->l_used;
X		if (linlen > NSTRING - 1)
X			linlen = NSTRING - 1;
X		strncpy(eline, lp->l_text, linlen);
X		eline[linlen] = 0;	/* make sure it ends */
X
X		/* if it is not a comment, execute it */
X		if (eline[0] != ';' && eline[0] != 0) {
X			status = docmd(eline);
X			if (status != TRUE) {	/* a command error */
X				/* look if buffer is showing */
X				wp = wheadp;
X				while (wp != NULL) {
X					if (wp->w_bufp == bp) {
X						/* and point it */
X						wp->w_dotp = lp;
X						wp->w_doto = 0;
X						wp->w_flag |= WFHARD;
X					}
X					wp = wp->w_wndp;
X				}
X				/* in any case set the buffer . */
X				bp->b_dotp = lp;
X				bp->b_doto = 0;
X				return(status);
X			}
X		}
X		lp = lp->l_fp;		/* on to the next line */
X	}
X        return(TRUE);
X}
X
Xexecfile(f, n)	/* execute a series of commands in a file
X*/
X
Xint f, n;	/* default flag and numeric arg to pass on to file */
X
X{
X	register int status;	/* return status of name query */
X	char *fname[NSTRING];	/* name of file to execute */
X
X	if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
X		return(status);
X
X	/* otherwise, execute it */
X	while (n-- > 0)
X		if ((status=dofile(fname)) != TRUE)
X			return(status);
X
X	return(TRUE);
X}
X
X/*	dofile:	yank a file into a buffer and execute it
X		if there are no errors, delete the buffer on exit */
X
Xdofile(fname)
X
Xchar *fname;	/* file name to execute */
X
X{
X	register BUFFER *bp;	/* buffer to place file to exeute */
X	register BUFFER *cb;	/* temp to hold current buf while we read */
X	register int status;	/* results of various calls */
X	char bname[NBUFN];	/* name of buffer */
X
X	makename(bname, fname);		/* derive the name of the buffer */
X	if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
X		return(FALSE);
X
X	bp->b_mode = MDVIEW;	/* mark the buffer as read only */
X	cb = curbp;		/* save the old buffer */
X	curbp = bp;		/* make this one current */
X	/* and try to read in the file to execute */
X	if ((status = readin(fname, FALSE)) != TRUE) {
X		curbp = cb;	/* restore the current buffer */
X		return(status);
X	}
X
X	/* go execute it! */
X	curbp = cb;		/* restore the current buffer */
X	if ((status = dobuf(bp)) != TRUE)
X		return(status);
X
X	/* if not displayed, remove the now unneeded buffer and exit */
X	if (bp->b_nwnd == 0)
X		zotbuf(bp);
X	return(TRUE);
X}
X
X/*	cbuf:	Execute the contents of a numbered buffer	*/
X
Xcbuf(f, n, bufnum)
X
Xint f, n;	/* default flag and numeric arg */
Xint bufnum;	/* number of buffer to execute */
X
X{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X	static char bufname[] = "[Macro xx]";
X
X	/* make the buffer name */
X	bufname[7] = '0' + (bufnum / 10);
X	bufname[8] = '0' + (bufnum % 10);
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
X        	mlwrite("Macro not defined");
X                return(FALSE);
X        }
X
X	/* and now execute it as asked */
X	while (n-- > 0)
X		if ((status = dobuf(bp)) != TRUE)
X			return(status);
X	return(TRUE);
X}
X
Xcbuf1(f, n)
X
X{
X	cbuf(f, n, 1);
X}
X
Xcbuf2(f, n)
X
X{
X	cbuf(f, n, 2);
X}
X
Xcbuf3(f, n)
X
X{
X	cbuf(f, n, 3);
X}
X
Xcbuf4(f, n)
X
X{
X	cbuf(f, n, 4);
X}
X
Xcbuf5(f, n)
X
X{
X	cbuf(f, n, 5);
X}
X
Xcbuf6(f, n)
X
X{
X	cbuf(f, n, 6);
X}
X
Xcbuf7(f, n)
X
X{
X	cbuf(f, n, 7);
X}
X
Xcbuf8(f, n)
X
X{
X	cbuf(f, n, 8);
X}
X
Xcbuf9(f, n)
X
X{
X	cbuf(f, n, 9);
X}
X
Xcbuf10(f, n)
X
X{
X	cbuf(f, n, 10);
X}
X
Xcbuf11(f, n)
X
X{
X	cbuf(f, n, 11);
X}
X
Xcbuf12(f, n)
X
X{
X	cbuf(f, n, 12);
X}
X
Xcbuf13(f, n)
X
X{
X	cbuf(f, n, 13);
X}
X
Xcbuf14(f, n)
X
X{
X	cbuf(f, n, 14);
X}
X
Xcbuf15(f, n)
X
X{
X	cbuf(f, n, 15);
X}
X
Xcbuf16(f, n)
X
X{
X	cbuf(f, n, 16);
X}
X
Xcbuf17(f, n)
X
X{
X	cbuf(f, n, 17);
X}
X
Xcbuf18(f, n)
X
X{
X	cbuf(f, n, 18);
X}
X
Xcbuf19(f, n)
X
X{
X	cbuf(f, n, 19);
X}
X
Xcbuf20(f, n)
X
X{
X	cbuf(f, n, 20);
X}
X
Xcbuf21(f, n)
X
X{
X	cbuf(f, n, 21);
X}
X
Xcbuf22(f, n)
X
X{
X	cbuf(f, n, 22);
X}
X
Xcbuf23(f, n)
X
X{
X	cbuf(f, n, 23);
X}
X
Xcbuf24(f, n)
X
X{
X	cbuf(f, n, 24);
X}
X
Xcbuf25(f, n)
X
X{
X	cbuf(f, n, 25);
X}
X
Xcbuf26(f, n)
X
X{
X	cbuf(f, n, 26);
X}
X
Xcbuf27(f, n)
X
X{
X	cbuf(f, n, 27);
X}
X
Xcbuf28(f, n)
X
X{
X	cbuf(f, n, 28);
X}
X
Xcbuf29(f, n)
X
X{
X	cbuf(f, n, 29);
X}
X
Xcbuf30(f, n)
X
X{
X	cbuf(f, n, 30);
X}
X
Xcbuf31(f, n)
X
X{
X	cbuf(f, n, 31);
X}
X
Xcbuf32(f, n)
X
X{
X	cbuf(f, n, 32);
X}
X
Xcbuf33(f, n)
X
X{
X	cbuf(f, n, 33);
X}
X
Xcbuf34(f, n)
X
X{
X	cbuf(f, n, 34);
X}
X
Xcbuf35(f, n)
X
X{
X	cbuf(f, n, 35);
X}
X
Xcbuf36(f, n)
X
X{
X	cbuf(f, n, 36);
X}
X
Xcbuf37(f, n)
X
X{
X	cbuf(f, n, 37);
X}
X
Xcbuf38(f, n)
X
X{
X	cbuf(f, n, 38);
X}
X
Xcbuf39(f, n)
X
X{
X	cbuf(f, n, 39);
X}
X
Xcbuf40(f, n)
X
X{
X	cbuf(f, n, 40);
X}
X
X
FRIDAY_NIGHT
echo extracting - file.c
sed 's/^X//' > file.c << 'FRIDAY_NIGHT'
X/*
X * The routines in this file
X * handle the reading and writing of
X * disk files. All of details about the
X * reading and writing of the disk are
X * in "fileio.c".
X */
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
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 ((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 (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 ((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 ((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
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        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        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		if (s == FIOLNG)
X			lflag = TRUE;
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        }
X        ffclose();                              /* Ignore errors.       */
X        if (s == FIOEOF) {                      /* Don't zap message!   */
X                if (nline == 1)
X                        mlwrite("[Read 1 line]");
X                else
X                        mlwrite("[Read %d lines]", nline);
X        }
X	if (lflag)
X		mlwrite("[Read %d line(s), Long lines wrapped]",nline);
Xout:
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     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 ((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 ((s=ffwopen(fn)) != FIOSUC)          /* Open writes message. */
X                return (FALSE);
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        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 ((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	/* 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		if (s == FIOLNG)
X			lflag = TRUE;
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        }
X        ffclose();                              /* Ignore errors.       */
X	curwp->w_markp = lforw(curwp->w_markp);
X        if (s == FIOEOF) {                      /* Don't zap message!   */
X                if (nline == 1)
X                        mlwrite("[Inserted 1 line]");
X                else
X                        mlwrite("[Inserted %d lines]", nline);
X        }
X	if (lflag)
X		mlwrite("[Inserted %d line(s), Long lines wrapped]",nline);
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}
FRIDAY_NIGHT
echo es.5 completed!
: That's all folks!