Vile 06/17 - vi feel-alike (multi-window)

Paul Fox pgf at cayman.COM
Sat Jun 8 08:09:32 AEST 1991


#!/bin/sh
# this is vileshar.06 (part 6 of Vile)
# do not concatenate these parts, unpack them in order with /bin/sh
# file evar.h continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 6; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
echo 'x - continuing file evar.h'
sed 's/^X//' << 'SHAR_EOF' >> 'evar.h' &&
X
/*	list of recognized environment variables	*/
X
char *envars[] = {
X	"fillcol",		/* current fill column */
X	"pagelen",		/* number of lines used by editor */
X	"curcol",		/* current column pos of cursor */
X	"curline",		/* current line in file */
X	"ram",			/* ram in use by malloc */
X	"flicker",		/* flicker supression */
X	"curwidth",		/* current screen width */
X	"cbufname",		/* current buffer name */
X	"cfname",		/* current file name */
X	"sres",			/* current screen resolution */
X	"debug",		/* macro debugging */
X	"status",		/* returns the status of the last command */
X	"palette",		/* current palette string */
X	"asave",		/* # of chars between auto-saves */
X	"acount",		/* # of chars until next auto-save */
X	"lastkey",		/* last keyboard char struck */
X	"curchar",		/* current character under the cursor */
X	"discmd",		/* display commands on command line */
X	"version",		/* current version number */
X	"progname",		/* returns current prog name - "vile" */
X	"seed",			/* current random number seed */
X	"disinp",		/* display command line input characters */
X	"wline",		/* # of lines in current window */
X	"cwline",		/* current screen line in window */
X	"target",		/* target for line moves */
X	"search",		/* search pattern */
X	"replace",		/* replacement pattern */
X	"match",		/* last matched magic pattern */
X	"kill",			/* kill buffer (read only) */
X	"cmode",		/* mode of current buffer */
X	"gmode",		/* global modes */
X	"tpause",		/* length to pause for paren matching */
X	"pending",		/* type ahead pending flag */
X	"lwidth",		/* width of current line */
X	"line",			/* text of current line */
};
X
#define	NEVARS	sizeof(envars) / sizeof(char *)
X
/* 	and its preprocesor definitions		*/
X
#define	EVFILLCOL	0
#define	EVPAGELEN	1
#define	EVCURCOL	2
#define	EVCURLINE	3
#define	EVRAM		4
#define	EVFLICKER	5
#define	EVCURWIDTH	6
#define	EVCBUFNAME	7
#define	EVCFNAME	8
#define	EVSRES		9
#define	EVDEBUG		10
#define	EVSTATUS	11
#define	EVPALETTE	12
#define	EVASAVE		13
#define	EVACOUNT	14
#define	EVLASTKEY	15
#define	EVCURCHAR	16
#define	EVDISCMD	17
#define	EVVERSION	18
#define	EVPROGNAME	19
#define	EVSEED		20
#define	EVDISINP	21
#define	EVWLINE		22
#define EVCWLINE	23
#define	EVTARGET	24
#define	EVSEARCH	25
#define	EVREPLACE	26
#define	EVMATCH		27
#define	EVKILL		28
#define	EVCMODE		29
#define	EVGMODE		30
#define	EVTPAUSE	31
#define	EVPENDING	32
#define	EVLWIDTH	33
#define	EVLINE		34
X
/*	list of recognized user functions	*/
X
typedef struct UFUNC {
X	char *f_name;	/* name of function */
X	int f_type;	/* 1 = monamic, 2 = dynamic */
} UFUNC;
X
#define	NILNAMIC	0
#define	MONAMIC		1
#define	DYNAMIC		2
#define	TRINAMIC	3
X
UFUNC funcs[] = {
X	"add", DYNAMIC,		/* add two numbers together */
X	"sub", DYNAMIC,		/* subtraction */
X	"tim", DYNAMIC,		/* multiplication */
X	"div", DYNAMIC,		/* division */
X	"mod", DYNAMIC,		/* mod */
X	"neg", MONAMIC,		/* negate */
X	"cat", DYNAMIC,		/* concatinate string */
X	"lef", DYNAMIC,		/* left string(string, len) */
X	"rig", DYNAMIC,		/* right string(string, pos) */
X	"mid", TRINAMIC,	/* mid string(string, pos, len) */
X	"not", MONAMIC,		/* logical not */
X	"equ", DYNAMIC,		/* logical equality check */
X	"les", DYNAMIC,		/* logical less than */
X	"gre", DYNAMIC,		/* logical greater than */
X	"seq", DYNAMIC,		/* string logical equality check */
X	"sle", DYNAMIC,		/* string logical less than */
X	"sgr", DYNAMIC,		/* string logical greater than */
X	"ind", MONAMIC,		/* evaluate indirect value */
X	"and", DYNAMIC,		/* logical and */
X	"or",  DYNAMIC,		/* logical or */
X	"len", MONAMIC,		/* string length */
X	"upp", MONAMIC,		/* uppercase string */
X	"low", MONAMIC,		/* lower case string */
X	"tru", MONAMIC,		/* Truth of the universe logical test */
X	"asc", MONAMIC,		/* char to integer conversion */
X	"chr", MONAMIC,		/* integer to char conversion */
X	"gtk", NILNAMIC,	/* get 1 charater */
X	"rnd", MONAMIC,		/* get a random number */
X	"abs", MONAMIC,		/* absolute value of a number */
X	"sin", DYNAMIC,		/* find the index of one string in another */
X	"env", MONAMIC,		/* retrieve a system environment var */
X	"bin", MONAMIC,		/* loopup what function name is bound to a key */
};
X
#define	NFUNCS	sizeof(funcs) / sizeof(UFUNC)
X
/* 	and its preprocesor definitions		*/
X
#define	UFADD		0
#define	UFSUB		1
#define	UFTIMES		2
#define	UFDIV		3
#define	UFMOD		4
#define	UFNEG		5
#define	UFCAT		6
#define	UFLEFT		7
#define	UFRIGHT		8
#define	UFMID		9
#define	UFNOT		10
#define	UFEQUAL		11
#define	UFLESS		12
#define	UFGREATER	13
#define	UFSEQUAL	14
#define	UFSLESS		15
#define	UFSGREAT	16
#define	UFIND		17
#define	UFAND		18
#define	UFOR		19
#define	UFLENGTH	20
#define	UFUPPER		21
#define	UFLOWER		22
#define	UFTRUTH		23
#define	UFASCII		24
#define	UFCHR		25
#define	UFGTKEY		26
#define	UFRND		27
#define	UFABS		28
#define	UFSINDEX	29
#define	UFENV		30
#define	UFBIND		31
X
#endif
SHAR_EOF
echo 'File evar.h is complete' &&
chmod 0444 evar.h ||
echo 'restore of evar.h failed'
Wc_c="`wc -c < 'evar.h'`"
test 5247 -eq "$Wc_c" ||
	echo 'evar.h: original size 5247, current size' "$Wc_c"
# ============= exec.c ==============
echo 'x - extracting exec.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'exec.c' &&
/*	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
#include	<stdio.h>
#include	"estruct.h"
#include	"edef.h"
X
/* namedcmd:	execute a named command even if it is not bound */
X
namedcmd(f, n)
int f, n;
{
X	char *fnp;	/* ptr to the name of the cmd to exec */
X	LINE *fromline;	/* first linespec */
X	LINE *toline;	/* second linespec */
X	char lspec[NLINE];
X	int cpos = 0;
X	int s,c,isdfl,zero,flags;
X	char *kbd_engl();
X	CMDFUNC *cfp;		/* function to execute */
X	extern CMDFUNC f_gomark;
X
X	/* prompt the user to type a named command */
X	mlwrite(": ");
X
X	/* and now get the function name to execute */
#if	NeWS
X	newsimmediateon() ;
#endif
X
X	while(1) {
X		c = tgetc();
X		if (c == '\r') {
X			lspec[cpos] = 0;
X			fnp = NULL;
X			break;
X		} else if (c == kcod2key(abortc)) {	/* Bell, abort */
X		isabortc:
X			lspec[0] = '\0';
X			return FALSE;
X		} else if (isbackspace(c)) {
X			if (cpos != 0) {
X				TTputc('\b');
X				TTputc(' ');
X				TTputc('\b');
X				--ttcol;
X				--cpos;
X			} else {
X				lspec[0] = '\0';
X				lineinput = FALSE;
X				return FALSE;
X			}
X
X		} else if (c == kcod2key(killc)) {	/* ^U, kill */
X		iskillc:
X			while (cpos != 0) {
X				TTputc('\b');
X				TTputc(' ');
X				TTputc('\b');
X				--cpos;
X				--ttcol;
X			}
X		} else if (islinespecchar(c) ||
X			/* special test for 'a style mark references */
X				(cpos > 0 &&
X				 lspec[cpos-1] == '\'' &&
X				 (islower(c) || (c == '\'') )
X				)
X			 ) {
X			lspec[cpos++] = c;
X			TTputc(c);
X			++ttcol;
X		} else {
X			int status;
X			tungetc(c);
X			lspec[cpos] = 0;
X			status = kbd_engl_stat(&fnp);
X			if (status == TRUE) {
X				break;
X			} else if (status == SORTOFTRUE) {
X				fnp = NULL;
X				continue;
X			} else {
X				return status;
X			}
X		}
X		TTflush();
X	}
X
X	/* parse the accumulated lspec */
X	if (rangespec(lspec,&fromline,&toline,&isdfl,&zero) != TRUE) {
X		mlwrite("[Improper line range]");
X		return FALSE;
X	}
X
X	/* if range given, and it wasn't "0" and the buffer's empty */
X	if (!isdfl && !zero && (lforw(curbp->b_linep) == curbp->b_linep)) {
X		mlwrite("[No range possible in empty buffer]", fnp);
X		return FALSE;
X	}
X
#if	NeWS
X	newsimmediateoff() ;
#endif
X
X	/* did we get a name? */
X	if (fnp == NULL) {
X		if (isdfl) { /* no range, no function */
X			mlwrite("[No such function]");
X			return FALSE;
X		} else { /* range, no function */
X			cfp = &f_gomark;
X			fnp = "";
X		}
X	} else if ((cfp = engl2fnc(fnp)) == NULL) { /* bad function */
X		mlwrite("[No such function %s]",fnp);
X		return FALSE;
X	}
X	flags = cfp->c_flags;
X	
X	/* bad arguments? */
#ifdef EXRC_FILES
seems like we need one more check here -- is it from a .exrc file?
X	    cmd not ok in .exrc 		empty file
X	if (!(flags & EXRCOK) && (lforw(curbp->b_linep) == curbp->b_linep)) {
X		mlwrite("[Can't use the \"%s\" command in a %s file.]", 
X					cmdnames[cmdidx].name, EXRC);
X		return FALSE;
X	}
#endif
X
X	/* was: if (!(flags & (ZERO | EXRCOK)) && fromline == NULL ) { */
X	if (zero) {
X		extern CMDFUNC f_lineputafter, f_opendown, f_insfile;
X		extern CMDFUNC f_lineputbefore, f_openup;
X		if (!(flags & ZERO)) {
X			mlwrite("[Can't use address 0 with \"%s\" command]", fnp);
X			return FALSE;
X		}
X		/*  we're positioned at fromline == curbp->b_linep, so commands
X			must be willing to go _down_ from there.  Seems easiest
X			to special case the commands that prefer going up */
X		if (cfp == &f_insfile) {
X			/* works okay -- acts down normally */
X		} else if (cfp == &f_lineputafter) {
X			cfp = &f_lineputbefore;
X			fromline = lforw(fromline);
X		} else if (cfp == &f_opendown) {
X			cfp = &f_openup;
X			fromline = lforw(fromline);
X		} else {
X			mlwrite("[Configuration error: ZERO]");
X			return FALSE;
X		}
X		flags = cfp->c_flags;
X		toline = fromline;
X	}
X
X	/* if we're not supposed to have a line no., and the line no. isn't
X		the current line, and there's more than one line */
X	if (!(flags & FROM) && fromline != curwp->w_dotp && 
X			(lforw(curbp->b_linep)  != curbp->b_linep) &&
X		  (lforw(lforw(curbp->b_linep)) != curbp->b_linep) ) {
X		mlwrite("[Can't use address with \"%s\" command.]", fnp);
X		return FALSE;
X	}
X	/* if we're not supposed to have a second line no., and the line no. 
X		isn't the same as the first line no., and there's more than
X		one line */
X	if (!(flags & TO) && toline != fromline &&
X			(lforw(curbp->b_linep) != curbp->b_linep) &&
X		  (lforw(lforw(curbp->b_linep)) != curbp->b_linep) ) {
X		mlwrite("[Can't use a range with \"%s\" command.]", fnp);
X		return FALSE;
X	}
#ifdef NEEDED
X	if (!(flags & EXTRA) && *scan) {
X		mlwrite("[Extra characters after \"%s\" command.]", 
X						cmdnames[cmdidx].name);
X		return FALSE;
X	}
#endif
#ifdef NEEDED
X	if ((flags & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!'))) {
X		build = scan;
#ifndef CRUNCH  /* what is this for? -pgf */
X		if ((flags & PLUS) && *build == '+') {
X			while (*build && !(isspace(*build))) {
X				build++;
X			}
X			while (*build && isspace(*build)) {
X				build++;
X			}
X		}
#endif /* not CRUNCH */
X		for (; *build; build++) {
X			if (isspace(*build)) {
X				mlwrite("[Too many %s to \"%s\" command.]",
X					(flags & XFILE) ? "filenames" : "arguments",
X					cmdnames[cmdidx].name);
X				return FALSE;
X			}
X		}
X	}
#endif /* NEEDED */
X
X	/* some commands have special default ranges */
X	if (isdfl) {
X		if (flags & DFLALL) {
X			extern CMDFUNC f_operwrite, f_filewrite, f_operglobals,
X					f_globals, f_opervglobals, f_vglobals;
X			if (cfp == &f_operwrite) {
X				cfp = &f_filewrite;
#if GLOBALS
X			} else if (cfp == &f_operglobals) {
X				cfp = &f_globals;
X			} else if (cfp == &f_opervglobals) {
X				cfp = &f_vglobals;
#endif
X			} else {
X				mlwrite("[Configuration error: DFLALL]");
X				return FALSE;
X			}
X		} else if (flags & DFLNONE) {
X			extern CMDFUNC f_operfilter, f_spawn;
X			if (cfp == &f_operfilter) {
X				cfp = &f_spawn;
X				setmark();  /* not that it matters */
X			} else {
X				mlwrite("[Configuration error: DFLNONE]");
X				return FALSE;
X			}
X			fromline = toline = NULL;
X		}
X	}
X
#ifdef NEEDED
X	/* write a newline if called from visual mode */
X	if ((flags & NL) && !exmode /* && !exwrote */) {
X		TTputc('\n');
X		/* exrefresh(); */
X	}
#endif
X
X	if (toline || fromline) {  /* assume it's an absolute motion */
X				   /* we could probably do better */
X		curwp->w_ldmkp = curwp->w_dotp;
X		curwp->w_ldmko = curwp->w_doto;
X	}
X	if (toline) {
X		curwp->w_dotp = toline;
X		firstnonwhite();
X		setmark();
X	}
X	if (fromline) {
X		curwp->w_dotp = fromline;
X		firstnonwhite();
X		if (!toline)
X			setmark();
X	}
X
X	/* and then execute the command */
X	isnamedcmd = TRUE;
X	havemotion = &f_gomark;
X	fulllineregions = TRUE;
X
X	s = execute(cfp,f,n);
X
X	havemotion = NULL;
X	isnamedcmd = FALSE;
X	fulllineregions = FALSE;
X
X	return s;
}
X
/* parse an ex-style line spec -- code culled from elvis, file ex.c, by
X	Steve Kirkendall
*/
char *
linespec(s, markptr)
register char	*s;		/* start of the line specifier */
LINE		**markptr;	/* where to store the mark's value */
{
X	long		num;
X	LINE		*lp;	/* where the linespec takes us */
X	register char	*t;
X	int		status;
X
X	setmark();
X	lp = NULL;
X
X	/* parse each ;-delimited clause of this linespec */
X	do
X	{
X		/* skip an initial ';', if any */
X		if (*s == ';')
X			s++;
X
X		/* skip leading spaces */
X		while (isspace(*s))
X			s++;
X	
X		/* dot means current position */
X		if (*s == '.') {
X			s++;
X			lp = curwp->w_dotp;
X		} else if (*s == '$') { /* '$' means the last line */
X			s++;
X			status = gotoeob(TRUE,1);
X			if (status) lp = curwp->w_dotp;
X		} else if (isdigit(*s)) {
X			/* digit means an absolute line number */
X			for (num = 0; isdigit(*s); s++) {
X				num = num * 10 + *s - '0';
X			}
X			status = gotoline(TRUE,num);
X			if (status) lp = curwp->w_dotp;
X		} else if (*s == '\'') {
X			/* appostrophe means go to a set mark */
X			s++;
X			status = gonmmark(*s);
X			if (status) lp = curwp->w_dotp;
X			s++;
X		} 
#if PATTERNS
X		else if (*s == '/' || *s == '?') { /* slash means do a search */
X			/* put a '\0' at the end of the search pattern */
X			t = parseptrn(s);
X	
X			/* search for the pattern */
X			lp &= ~(BLKSIZE - 1);
X			if (*s == '/') {
X				pfetch(markline(lp));
X				if (plen > 0)
X					lp += plen - 1;
X				lp = m_fsrch(lp, s);
X			} else {
X				lp = m_bsrch(lp, s);
X			}
X	
X			/* adjust command string pointer */
X			s = t;
X		}
#endif
X	
X		/* if linespec was faulty, quit now */
X		if (!lp) {
X			*markptr = lp;
X			swapmark();
X			return s;
X		}
X	
X		/* maybe add an offset */
X		t = s;
X		if (*t == '-' || *t == '+') {
X			s++;
X			for (num = 0; *s >= '0' && *s <= '9'; s++) {
X				num = num * 10 + *s - '0';
X			}
X			if (num == 0)
X				num = 1;
X			forwline(TRUE, (*t == '+') ? num : -num);
X			lp = curwp->w_dotp;
X		}
X	} while (*s == ';' || *s == '+' || *s == '-');
X
X	*markptr = lp;
X	swapmark();
X	return s;
}
X
/* parse an ex-style line range -- code culled from elvis, file ex.c, by
X	Steve Kirkendall
*/
rangespec(specp,fromlinep,tolinep,isdefaultp,zerop)
char		*specp;	/* string containing a line range */
LINE		**fromlinep;	/* first linespec */
LINE		**tolinep;	/* second linespec */
int		*isdefaultp;
int		*zerop;
{
X	register char	*scan;		/* used to scan thru specp */
X	LINE		*fromline;	/* first linespec */
X	LINE		*toline;	/* second linespec */
X	int		noaddrallowed;
X
X	*zerop = FALSE;
X
X	/* ignore command lines that start with a double-quote */
X	if (*specp == '"') {
X		*fromlinep = *tolinep = curwp->w_dotp;
X		return TRUE;
X	}
X
X	/* permit extra colons at the start of the line */
X	while (isspace(*specp) || *specp == ':') {
X		specp++;
X	}
X
X	/* parse the line specifier */
X	scan = specp;
X	if (lforw(curbp->b_linep) == curbp->b_linep) {
X		fromline = toline = NULL;
X	} else if (*scan == '%') {
X		/* '%' means all lines */
X		fromline = lforw(curbp->b_linep);
X		toline = lback(curbp->b_linep);
X		scan++;
X	} else if (*scan == '0') {
X		fromline = toline = curbp->b_linep; /* _very_ top of buffer */
X		*zerop = TRUE;
X		scan++;
X	} else {
X		scan = linespec(scan, &fromline);
X		if (!fromline)
X			fromline = curwp->w_dotp;
X		toline = fromline;
X		if (*scan == ',') {
X			scan++;
X			scan = linespec(scan, &toline);
X		}
X		if (!toline) {
X			/* faulty line spec -- fault already described */
X			dbgwrite("null toline");
X			return FALSE;
X		}
X	}
X
X	*isdefaultp = (scan == specp);
X
X	/* skip whitespace */
X	while (isspace(*scan))
X		scan++;
X
X	if (*scan) {
X		dbgwrite("crud at end %s",specp);
X		return FALSE;
X	}
X
X	*fromlinep = fromline;
X	*tolinep = toline;
X	
X	return TRUE;
}
X
/* old namedcmd:	execute a named command even if it is not bound */
onamedcmd(f, n)
int f, n;	/* command arguments [passed through to command executed] */
{
X	register char *fnp;	/* ptr to the name of the cmd to exec */
X	char *kbd_engl();
X	int s;
X
X	/* prompt the user to type a named command */
X	mlwrite(": ");
X
X	/* and now get the function name to execute */
#if	NeWS
X	newsimmediateon() ;
#endif
X
X	fnp = kbd_engl();
X
#if	NeWS
X	newsimmediateoff() ;
#endif
X
X	if (fnp == NULL) {
X		mlwrite("[No such function]");
X		return FALSE;
X	}
X
X	/* and then execute the command */
X	isnamedcmd = TRUE;
X	s = docmd(fnp,FALSE,f,n);
X	isnamedcmd = FALSE;
X
X	return s;
}
X
#if NEVER
/*	execcmd:	Execute a command line command by name alone */
execcmd(f, n)
int f, n;	/* default Flag and Numeric argument */
{
X	register int status;		/* status return */
X	char cmdbuf[NSTRING];		/* string holding command to execute */
X
X	/* get the line wanted */
X	cmdbuf[0] = 0;
X	if ((status = mlreply("cmd: ", cmdbuf, NSTRING)) != TRUE)
X		return status;
X
X	execlevel = 0;
X	return docmd(cmdbuf,TRUE,f,n);
}
#endif
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
docmd(cline,newcle,f,n)
char *cline;	/* command line to execute */
{
X	int status;		/* return status of function */
X	int flags;		/* function flags */
X	int oldcle;		/* old contents of clexec flag */
X	char *oldestr;		/* original exec string */
X	char tkn[NSTRING];	/* next token off of command line */
X	CMDFUNC *cfp;
X	extern CMDFUNC f_godotplus;
X		
X	/* if we are scanning and not executing..go back here */
X	if (execlevel)
X		return TRUE;
X
X	oldestr = execstr;	/* save last ptr to string to execute */
X	execstr = cline;	/* and set this one as current */
X
X	/* first set up the default command values */
X	if (newcle == TRUE) {
X		f = FALSE;
X		n = 1;
X	}
X
X	if ((status = macarg(tkn)) != TRUE) {	/* and grab the first token */
X		execstr = oldestr;
X		return status;
X	}
X
X	/* process leadin argument */
X	if (toktyp(tkn) != TKCMD) {
X		f = TRUE;
X		strcpy(tkn, tokval(tkn));
X		n = atoi(tkn);
X
X		/* and now get the command to execute */
X		if ((status = macarg(tkn)) != TRUE) {
X			execstr = oldestr;
X			return status;	
X		}	
X	}
X
X	/* and match the token to see if it exists */
X	if ((cfp = engl2fnc(tkn)) == NULL) {
X		mlwrite("[No such function %s]",tkn);
X		execstr = oldestr;
X		return FALSE;
X	}
X	
X	/* save the arguments and go execute the command */
X	oldcle = clexec;		/* save old clexec flag */
X	clexec = newcle;		/* in cline execution */
X	status = execute(cfp,f,n);
X	cmdstatus = status;		/* save the status */
X	clexec = oldcle;		/* restore clexec flag */
X	execstr = oldestr;
X	return status;
}
X
/* token:	chop a token off a string
X		return a pointer past the token
*/
X
char *
token(src, tok)
char *src, *tok;	/* source string, destination token string */
{
X	register int quotef;	/* is the current string quoted? */
X
X	/* first scan past any whitespace in the source string */
X	while (isspace(*src))
X		++src;
X
X	/* scan through the source string */
X	quotef = FALSE;
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++ = '\r'; break;
X				case 'n':	*tok++ = '\n'; break;
X				case 't':	*tok++ = '\t';  break;
X				case 'b':	*tok++ = '\b';  break;
X				case 'f':	*tok++ = '\f'; 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			/* set quote mode if qoute found */
X			if (*src == '"')
X				quotef = TRUE;
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
macarg(tok)	/* get a macro line argument */
char *tok;	/* buffer to place argument */
{
X	int savcle;	/* buffer to store original clexec */
X
X	savcle = clexec;	/* save execution mode */
X	clexec = TRUE;		/* get the argument */
X	/* grab token and advance past */
X	execstr = token(execstr, tok);
X	/* evaluate it */
X	strcpy(tok, tokval(tok));
X	clexec = savcle;	/* restore execution mode */
X	return TRUE;
}
X
/*	nextarg:	get the next argument	*/
X
nextarg(buffer)
char *buffer;		/* buffer to put token into */
{
X	/* grab token and advance past */
X	execstr = token(execstr, buffer);
X	/* evaluate it */
X	strcpy(buffer, tokval(buffer));
X	return TRUE;
}
X
/*	storemac:	Set up a macro buffer and flag to store all
X			executed command lines there			*/
X
storemac(f, n)
int f;		/* default flag */
int n;		/* macro number to use */
{
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, OK_CREAT, BFINVS)) == NULL) {
X		mlwrite("[Cannot 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
#if	PROC
/*	storeproc:	Set up a procedure buffer and flag to store all
X			executed command lines there			*/
X
storeproc(f, n)
int f;		/* default flag */
int n;		/* macro number to use */
{
X	register struct BUFFER *bp;	/* pointer to macro buffer */
X	register int status;		/* return status */
X	char bname[NBUFN];		/* name of buffer to use */
X
X	/* a numeric argument means its a numbered macro */
X	if (f == TRUE)
X		return storemac(f, n);
X
X	/* get the name of the procedure */
X	bname[1] = 0;
X        if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
X                return status;
X
X	/* construct the macro buffer name */
X	bname[0] = '[';
X	strcat(bname, "]");
X
X	/* set up the new macro buffer */
X	if ((bp = bfind(bname, OK_CREAT, 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
/*	execproc:	Execute a procedure				*/
X
execproc(f, n)
int f, n;	/* default flag and numeric arg */
{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X        static char obufn[NBUFN+2];		/* name of buffer to execute */
X        char bufn[NBUFN+2];		/* name of buffer to execute */
X
X	/* find out what buffer the user wants to execute */
X        if ((status = mlreply("Execute procedure: ", obufn, NBUFN)) != TRUE)
X                return status;
X
X	/* construct the buffer name */
X	bufn[0] = '[';
X	strcat(bufn, obufn);
X	strcat(bufn, "]");
X
X	/* find the pointer to that buffer */
X        if ((bp=bfind(bufn, NO_CREAT, 0)) == NULL) {
X		mlwrite("[No such procedure]");
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	}
X	return TRUE;
}
#endif
X
#if ! SMALLER
/*	execbuf:	Execute the contents of a buffer of commands	*/
X
execbuf(f, n)
int f, n;	/* default flag and numeric arg */
{
X        register BUFFER *bp;		/* ptr to buffer to execute */
X        register int status;		/* status return */
X        static char bufn[NSTRING];		/* 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, NO_CREAT, 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	}
X	return TRUE;
}
#endif
X
/*	dobuf:	execute the contents of the buffer pointed to
X		by the passed BP
X
X	Directives start with a "!" and include:
X
#if SMALLER
X	!endm		End a macro
#else
X	!endm		End a macro
X	!if (cond)	conditional execution
X	!else
X	!endif
X	!return		Return (terminating current macro)
X	!goto <label>	Jump to a label in the current macro
X	!force		Force macro to continue...even if command fails
X	!while (cond)	Execute a loop if the condition is true
X	!endwhile
X	
X	Line Labels begin with a "*" as the first nonblank char, like:
X
X	*LBL01
#endif
X
*/
X
dobuf(bp)
BUFFER *bp;	/* buffer to execute */
{
X        register int status;	/* status return */
X	register LINE *lp;	/* pointer to line to execute */
X	register LINE *hlp;	/* pointer to line header */
X	LINE *mp;		/* Macro line storage temp */
X	int dirnum;		/* directive index */
X	int linlen;		/* length of line to execute */
X	int i;			/* index */
X	int force;		/* force TRUE result? */
X	WINDOW *wp;		/* ptr to windows to scan */
X	WHBLOCK *whlist;	/* ptr to !WHILE list */
X	char *einit;		/* initial value of eline */
X	char *eline;		/* text of line to execute */
#if ! SMALLER
X	WHBLOCK *scanner;	/* ptr during scan */
X	register LINE *glp;	/* line to goto */
X	WHBLOCK *whtemp;	/* temporary ptr to a WHBLOCK */
X	char tkn[NSTRING];	/* buffer to evaluate an expresion in */
#endif
X
#if	DEBUGM
X	char *sp;			/* temp for building debug string */
X	register char *ep;	/* ptr to end of outline */
#endif
X
X	/* clear IF level flags/while ptr */
X	execlevel = 0;
X	whlist = NULL;
X	fulllineregions = FALSE;
X	havemotion = FALSE;
X
#if ! SMALLER
X	scanner = NULL;
X	/* scan the buffer to execute, building WHILE header blocks */
X	hlp = bp->b_linep;
X	lp = hlp->l_fp;
X	while (lp != hlp) {
X		/* scan the current line */
X		eline = lp->l_text;
X		i = lp->l_used;
X
X		/* trim leading whitespace */
X		while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
X			++eline;
X
X		/* if theres nothing here, don't bother */
X		if (i <= 0)
X			goto nxtscan;
X
X		/* if is a while directive, make a block... */
X		if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
X			whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
X			if (whtemp == NULL) {
noram:				mlwrite("%%Out of memory during while scan");
failexit:			freewhile(scanner);
X				freewhile(whlist);
X				mstore = FALSE;
X				return FALSE;
X			}
X			whtemp->w_begin = lp;
X			whtemp->w_type = BTWHILE;
X			whtemp->w_next = scanner;
X			scanner = whtemp;
X		}
X
X		/* if is a BREAK directive, make a block... */
X		if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
X			if (scanner == NULL) {
X				mlwrite("%%!BREAK outside of any !WHILE loop");
X				goto failexit;
X			}
X			whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
X			if (whtemp == NULL)
X				goto noram;
X			whtemp->w_begin = lp;
X			whtemp->w_type = BTBREAK;
X			whtemp->w_next = scanner;
X			scanner = whtemp;
X		}
X
X		/* if it is an endwhile directive, record the spot... */
X		if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
X			if (scanner == NULL) {
X				mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
X					bp->b_bname);
X				goto failexit;
X			}
X			/* move top records from the scanner list to the
X			   whlist until we have moved all BREAK records
X			   and one WHILE record */
X			do {
X				scanner->w_end = lp;
X				whtemp = whlist;
X				whlist = scanner;
X				scanner = scanner->w_next;
X				whlist->w_next = whtemp;
X			} while (whlist->w_type == BTBREAK);
X		}
X
nxtscan:	/* on to the next line */
X		lp = lp->l_fp;
X	}
X
X	/* while and endwhile should match! */
X	if (scanner != NULL) {
X		mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
X			bp->b_bname);
X		goto failexit;
X	}
#endif
X
X	/* starting at the beginning of the buffer */
X	hlp = bp->b_linep;
X	lp = hlp->l_fp;
X	while (lp != hlp) {
X		/* allocate eline and copy macro line to it */
X		linlen = lp->l_used;
X		if ((einit = eline = malloc(linlen+1)) == NULL) {
X			mlwrite("%%Out of Memory during macro execution");
X			freewhile(whlist);
X			mstore = FALSE;
X			return FALSE;
X		}
X		strncpy(eline, lp->l_text, linlen);
X		eline[linlen] = 0;	/* make sure it ends */
X
X		/* trim leading whitespace */
X		while (*eline == ' ' || *eline == '\t')
X			++eline;
X
X		/* dump comments and blank lines */
X		if (*eline == ';' || *eline == 0)
X			goto onward;
X
#if	DEBUGM
X		/* if $debug == TRUE, every line to execute
X		   gets echoed and a key needs to be pressed to continue
X		   ^G will abort the command */
X	
X		if (macbug) {
X			strcpy(outline, "<<<");
X	
X			/* debug macro name */
X			strcat(outline, bp->b_bname);
X			strcat(outline, ":");
X	
X			/* debug if levels */
X			strcat(outline, itoa(execlevel));
X			strcat(outline, ":");
X
X			/* and lastly the line */
X			strcat(outline, eline);
X			strcat(outline, ">>>");
X	
X			/* change all '%' to ':' so mlwrite won't expect arguments */
X			sp = outline;
X			while (*sp)
X			if (*sp++ == '%') {
X				/* advance to the end */
X				ep = --sp;
X				while (*ep++)
X					;
X				/* null terminate the string one out */
X				*(ep + 1) = 0;
X				/* copy backwards */
X				while(ep-- > sp)
X					*(ep + 1) = *ep;
X
X				/* and advance sp past the new % */
X				sp += 2;					
X			}
X	
X			/* write out the debug line */
X			mlforce(outline);
X			update(TRUE);
X	
X			/* and get the keystroke */
X			if (kbd_key() == abortc) {
X				mlforce("[Macro aborted]");
X				freewhile(whlist);
X				mstore = FALSE;
X				return FALSE;
X			}
X		}
#endif
X
X		/* Parse directives here.... */
X		dirnum = -1;
X		if (*eline == '~') {
X			/* Find out which directive this is */
X			++eline;
X			for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
X				if (strncmp(eline, dname[dirnum],
X				            strlen(dname[dirnum])) == 0)
X					break;
X
X			/* and bitch if it's illegal */
X			if (dirnum == NUMDIRS) {
X				mlwrite("%%Unknown Directive");
X				freewhile(whlist);
X				mstore = FALSE;
X				return FALSE;
X			}
X
X			/* service only the !ENDM macro here */
X			if (dirnum == DENDM) {
X				mstore = FALSE;
X				bstore = NULL;
X				goto onward;
X			}
X
X			/* restore the original eline....*/
X			--eline;
X		}
X
X		/* if macro store is on, just salt this away */
X		if (mstore) {
X			/* allocate the space for the line */
X			linlen = strlen(eline);
X			if ((mp=lalloc(linlen)) == NULL) {
X				mlwrite("%%Out of memory while storing macro");
X				mstore = FALSE;
X				return FALSE;
X			}
X	
X			/* copy the text into the new line */
X			for (i=0; i<linlen; ++i)
X				lputc(mp, i, eline[i]);
X	
X			/* attach the line to the end of the buffer */
X	       		bstore->b_linep->l_bp->l_fp = mp;
X			mp->l_bp = bstore->b_linep->l_bp;
X			bstore->b_linep->l_bp = mp;
X			mp->l_fp = bstore->b_linep;
X			goto onward;
X		}
X	
X
X		force = FALSE;
X
X		/* dump comments */
X		if (*eline == '*')
X			goto onward;
X
#if ! SMALLER
X		/* now, execute directives */
X		if (dirnum != -1) {
X			/* skip past the directive */
X			while (*eline && *eline != ' ' && *eline != '\t')
X				++eline;
X			execstr = eline;
X
X			switch (dirnum) {
X			case DIF:	/* IF directive */
X				/* grab the value of the logical exp */
X				if (execlevel == 0) {
X					if (macarg(tkn) != TRUE)
X						goto eexec;
X					if (stol(tkn) == FALSE)
X						++execlevel;
X				} else
X					++execlevel;
X				goto onward;
X
X			case DWHILE:	/* WHILE directive */
X				/* grab the value of the logical exp */
X				if (execlevel == 0) {
X					if (macarg(tkn) != TRUE)
X						goto eexec;
X					if (stol(tkn) == TRUE)
X						goto onward;
X				}
X				/* drop down and act just like !BREAK */
X
X			case DBREAK:	/* BREAK directive */
X				if (dirnum == DBREAK && execlevel)
X					goto onward;
X
X				/* jump down to the endwhile */
X				/* find the right while loop */
X				whtemp = whlist;
X				while (whtemp) {
X					if (whtemp->w_begin == lp)
X						break;
X					whtemp = whtemp->w_next;
X				}
X			
X				if (whtemp == NULL) {
X					mlwrite("%%Internal While loop error");
X					freewhile(whlist);
X					mstore = FALSE;
X					return FALSE;
X				}
X			
X				/* reset the line pointer back.. */
X				lp = whtemp->w_end;
X				goto onward;
X
X			case DELSE:	/* ELSE directive */
X				if (execlevel == 1)
X					--execlevel;
X				else if (execlevel == 0 )
X					++execlevel;
X				goto onward;
X
X			case DENDIF:	/* ENDIF directive */
X				if (execlevel)
X					--execlevel;
X				goto onward;
X
X			case DGOTO:	/* GOTO directive */
X				/* .....only if we are currently executing */
X				if (execlevel == 0) {
X
X					/* grab label to jump to */
X					eline = token(eline, golabel);
X					linlen = strlen(golabel);
X					glp = hlp->l_fp;
X					while (glp != hlp) {
X						if (*glp->l_text == '*' &&
X						    (strncmp(&glp->l_text[1], golabel,
X						            linlen) == 0)) {
X							lp = glp;
X							goto onward;
X						}
X						glp = glp->l_fp;
X					}
X					mlwrite("%%No such label");
X					freewhile(whlist);
X					mstore = FALSE;
X					return FALSE;
X				}
X				goto onward;
X	
X			case DRETURN:	/* RETURN directive */
X				if (execlevel == 0)
X					goto eexec;
X				goto onward;
X
X			case DENDWHILE:	/* ENDWHILE directive */
X				if (execlevel) {
X					--execlevel;
X					goto onward;
X				} else {
X					/* find the right while loop */
X					whtemp = whlist;
X					while (whtemp) {
X						if (whtemp->w_type == BTWHILE &&
X						    whtemp->w_end == lp)
X							break;
X						whtemp = whtemp->w_next;
X					}
X		
X					if (whtemp == NULL) {
X						mlwrite("%%Internal While loop error");
X						freewhile(whlist);
X						mstore = FALSE;
X						return FALSE;
X					}
X		
X					/* reset the line pointer back.. */
X					lp = whtemp->w_begin->l_bp;
X					goto onward;
X				}
X
X			case DFORCE:	/* FORCE directive */
X				force = TRUE;
X
X			}
X		}
#endif
X
X		/* execute the statement */
X		status = docmd(eline,TRUE,FALSE,1);
X		if (force)		/* force the status */
X			status = TRUE;
X
X		/* check for a command error */
X		if (status != TRUE) {
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			free(einit);
X			execlevel = 0;
X			mstore = FALSE;
X			freewhile(whlist);
X			return status;
X		}
X
onward:		/* on to the next line */
X		free(einit);
X		lp = lp->l_fp;
X	}
X
#if ! SMALLER
eexec:	/* exit the current function */
#endif
X	mstore = FALSE;
X	execlevel = 0;
X	freewhile(whlist);
X        return TRUE;
}
X
freewhile(wp)	/* free a list of while block pointers */
WHBLOCK *wp;	/* head of structure to free */
{
X	if (wp == NULL)
X		return;
X	if (wp->w_next)
X		freewhile(wp->w_next);
X	free((char *)wp);
}
X
#if ! SMALLER
execfile(f, n)	/* execute a series of commands in a file */
int f, n;	/* default flag and numeric arg to pass on to file */
{
X	register int status;	/* return status of name query */
X	static char ofname[NSTRING];	/* name of file to execute */
X	char fname[NSTRING];	/* name of file to execute */
X	char *fspec;		/* full file spec */
X
X	if ((status = mlreply("File to execute: ", ofname, NSTRING -1)) != TRUE)
X		return status;
X	strcpy(fname,ofname);
X
#if	1
X	/* look up the path for the file */
X	fspec = flook(fname, FL_ANYWHERE);
X
X	/* if it isn't around */
X	if (fspec == NULL)
X		return FALSE;
X
#endif
X	/* otherwise, execute it */
X	while (n-- > 0)
X		if ((status=dofile(fspec)) != TRUE)
X			return status;
X
X	return TRUE;
}
#endif
X
/*	dofile:	yank a file into a buffer and execute it
X		if there are no errors, delete the buffer on exit */
X
dofile(fname)
char *fname;	/* file name to execute */
{
X	register BUFFER *bp;	/* buffer to place file to exeute */
X	register int status;	/* results of various calls */
X	register int odiscmd;
X	char bname[NBUFN];	/* name of buffer */
X
X	makename(bname, fname);		/* derive the name of the buffer */
X	if ((bp = bfind(bname, OK_CREAT, 0)) == NULL) /* get the needed buffer */
X		return FALSE;
X
X	bp->b_mode = MDVIEW;	/* mark the buffer as read only */
X	/* and try to read in the file to execute */
X	if ((status = readin(fname, FALSE, bp, TRUE)) != TRUE) {
X		return status;
X	}
X
X	/* go execute it! */
X	odiscmd = discmd;
X	discmd = FALSE;
X	status = dobuf(bp);
X	discmd = odiscmd;
X	if (status != 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
/*	cbuf:	Execute the contents of a numbered buffer	*/
X
cbuf(f, n, bufnum)
int f, n;	/* default flag and numeric arg */
int bufnum;	/* number of buffer to execute */
{
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, NO_CREAT, 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
cbuf1(f, n)
{
X	cbuf(f, n, 1);
}
X
cbuf2(f, n)
{
X	cbuf(f, n, 2);
}
X
cbuf3(f, n)
{
X	cbuf(f, n, 3);
}
X
cbuf4(f, n)
{
X	cbuf(f, n, 4);
}
X
cbuf5(f, n)
{
X	cbuf(f, n, 5);
}
X
cbuf6(f, n)
{
X	cbuf(f, n, 6);
}
X
cbuf7(f, n)
{
X	cbuf(f, n, 7);
}
X
cbuf8(f, n)
{
X	cbuf(f, n, 8);
}
X
cbuf9(f, n)
{
X	cbuf(f, n, 9);
}
X
cbuf10(f, n)
{
X	cbuf(f, n, 10);
}
X
cbuf11(f, n)
{
X	cbuf(f, n, 11);
}
X
cbuf12(f, n)
{
X	cbuf(f, n, 12);
}
X
cbuf13(f, n)
{
X	cbuf(f, n, 13);
}
X
cbuf14(f, n)
{
X	cbuf(f, n, 14);
}
X
cbuf15(f, n)
{
X	cbuf(f, n, 15);
}
X
cbuf16(f, n)
{
X	cbuf(f, n, 16);
}
X
cbuf17(f, n)
{
X	cbuf(f, n, 17);
}
X
cbuf18(f, n)
{
X	cbuf(f, n, 18);
}
X
cbuf19(f, n)
{
X	cbuf(f, n, 19);
}
X
cbuf20(f, n)
{
X	cbuf(f, n, 20);
}
X
cbuf21(f, n)
{
X	cbuf(f, n, 21);
}
X
cbuf22(f, n)
{
X	cbuf(f, n, 22);
}
X
cbuf23(f, n)
{
X	cbuf(f, n, 23);
}
X
cbuf24(f, n)
{
X	cbuf(f, n, 24);
}
X
cbuf25(f, n)
{
X	cbuf(f, n, 25);
}
X
cbuf26(f, n)
{
X	cbuf(f, n, 26);
}
X
cbuf27(f, n)
{
X	cbuf(f, n, 27);
}
X
cbuf28(f, n)
{
X	cbuf(f, n, 28);
}
X
cbuf29(f, n)
{
X	cbuf(f, n, 29);
}
X
cbuf30(f, n)
{
X	cbuf(f, n, 30);
}
X
cbuf31(f, n)
{
X	cbuf(f, n, 31);
}
X
cbuf32(f, n)
{
X	cbuf(f, n, 32);
}
X
cbuf33(f, n)
{
X	cbuf(f, n, 33);
}
X
cbuf34(f, n)
{
X	cbuf(f, n, 34);
}
X
cbuf35(f, n)
{
X	cbuf(f, n, 35);
}
X
cbuf36(f, n)
{
X	cbuf(f, n, 36);
}
X
cbuf37(f, n)
{
X	cbuf(f, n, 37);
}
X
cbuf38(f, n)
{
X	cbuf(f, n, 38);
}
X
cbuf39(f, n)
{
X	cbuf(f, n, 39);
}
X
cbuf40(f, n)
{
X	cbuf(f, n, 40);
}
X
X
SHAR_EOF
chmod 0444 exec.c ||
echo 'restore of exec.c failed'
Wc_c="`wc -c < 'exec.c'`"
test 32572 -eq "$Wc_c" ||
	echo 'exec.c: original size 32572, current size' "$Wc_c"
# ============= file.c ==============
echo 'x - extracting file.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'file.c' &&
/*	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
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"
X
char *strchr();
char *strrchr();
X
extern int fileispipe;
#if DOSFILES
extern int dosfile;
#endif
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 */
fileread(f, n)
{
X        register int    s;
X        static char fname[NFILEN];
X
X        if ((s=mlreply("Replace with file: ", fname, NFILEN)) != TRUE)
X                return s;
X	if ((s = glob(fname)) != TRUE)
X		return FALSE;
X	/* we want no errors or complaints, so mark it unchanged */
X	curbp->b_flag &= ~BFCHG;
X        return readin(fname, TRUE, curbp, TRUE);
}
X
/*
X * Select a file for editing.
X * Look around to see if you can find the
X * file 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 * This is ": e"
X */
filefind(f, n)
{
X        static char fname[NFILEN];	/* file user wishes to find */
X	char nfname[NFILEN];
X	char rnfname[NFILEN];
X        register int s;		/* status return */
X	LINE *lp;
X
X	if (clexec || isnamedcmd) {
X	        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
X	                return s;
X        } else {
X		screen_string(fname,NFILEN,_path);
X        }
X	if ((s = glob(fname)) != TRUE)
X		return FALSE;
X	strcpy (nfname, fname);
#if TAGS
X	if (othmode & OTH_LAZY) {
X		extern BUFFER *filesbp;
X		lp = NULL;
X		while (flook(nfname, FL_HERE) == NULL) {
X			rvstrcpy(rnfname, fname);
X			if (makeflist() == FALSE || !sortsearch(rnfname, 
X					strlen(rnfname), filesbp, FALSE, &lp)) {
X				/* give up, and try what they asked for */
X				strcpy (nfname, fname);
X				break;
X			}
X			rvstrncpy(nfname, lp->l_text, llength(lp));
X		}
X	}
#endif
X	return getfile(nfname, TRUE);
}
X
viewfile(f, n)	/* visit a file in VIEW mode */
{
X        char fname[NFILEN];	/* file user wishes to find */
X        register int s;		/* status return */
X
X	fname[0] = 0;
X        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
X                return s;
X	if ((s = glob(fname)) != TRUE)
X		return FALSE;
X	s = getfile(fname, FALSE);
X	if (s == TRUE) {	/* if we succeed, put it in view mode */
X		curwp->w_bufp->b_mode |= MDVIEW;
X		markWFMODE(curwp->w_bufp);
X	}
X	return s;
}
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 */
static char insfname[NFILEN];
X
insfile(f, n)
{
X        register int    s;
X
X	if (!calledbefore) {
X	        if ((s=mlreply("Insert file: ", insfname, NFILEN)) != TRUE)
X	                return s;
X		if ((s = glob(insfname)) != TRUE)
X			return FALSE;
X	}
X	if (ukb == 0)
X	        return ifile(insfname,TRUE,NULL);
X	else
X	        return kifile(insfname);
}
X
#if BEFORE
insfiletop(f, n)
{
X        register int    s;
X        if ((s=mlreply("Insert file: ", insfname, NFILEN)) != TRUE)
X                return s;
X	if ((s = glob(insfname)) != TRUE)
X		return FALSE;
X	curwp->w_dotp = curbp->b_linep;
X        return ifile(insfname,TRUE,NULL);
}
#endif
X
getfile(fname, lockfl)
char fname[];		/* file name to find */
int lockfl;		/* check the file for locks? */
{
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
#if	MSDOS
X	mklower(fname);		/* msdos isn't case sensitive */
#endif
X        if ((bp=bfind(fname, NO_CREAT, 0)) == NULL) {
X		/* it's not already here by that buffer name */
X	        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
X			/* is it here by that filename? */
X	                if (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				if (fname[0] != '!') {
X		                        mlwrite("[Old buffer]");
X				} else {
X		                        if (mlyesno(
X		                         "Old command output -- rerun")) {
X					        return readin(fname, lockfl, 
X								curbp, TRUE);
X					}
X				}
X					
X	                        return TRUE;
X	                }
X	        }
X		/* it's not here */
X	        makename(bname, fname);            /* New buffer name.     */
X		/* make sure the buffer name doesn't exist */
X	        while ((bp=bfind(bname, NO_CREAT, 0)) != NULL) {
X			if ( !(bp->b_flag & BFCHG) && 
X					lforw(bp->b_linep) == bp->b_linep ) {
X				/* empty and unmodiefied -- then its okay 
X					to re-use this buffer */
X				bp->b_active = 0;
X				return readin(fname, lockfl, bp, TRUE) &&
X						swbuffer(bp);;
X			}
X			/* old buffer name conflict code */
X			unqname(bname,TRUE);
X	                s = mlreply("Will use buffer name: ", bname, NBUFN);
X	                if (s == ABORT)
X	                        return s;
X			if (s == FALSE || bname[0] == 0)
X		                makename(bname, fname);
X	        }
X		/* okay, we've got a unique name -- create it */
X	        if (bp==NULL && (bp=bfind(bname, OK_CREAT, 0))==NULL) {
X	                mlwrite("Cannot create buffer");
X	                return FALSE;
X	        }
X		/* switch and read it in. */
X	        strcpy(bp->b_fname, fname);
X	}
X	return swbuffer(bp);
}
X
/*
X	Read file "fname" into a buffer, blowing away any text
X	found there.  Returns the final status of the read.
*/
X
readin(fname, lockfl, bp, mflg)
char    *fname;		/* name of file to read */
int	lockfl;		/* check for file locks? */
register BUFFER *bp;	/* read into this buffer */
int	mflg;		/* print messages? */
{
X        register WINDOW *wp;
X        register int    s;
X        register int    nline;
X        int    len;
X	char *errst;
X	int flag = 0;
#if UNIX
X        int    done_update = FALSE;
#endif
#if VMALLOC
X	extern int doverifys;
X	int odv;
#endif
X
#if	FILOCK
X	if (lockfl && lockchk(fname) == ABORT)
X		return ABORT;
#endif
#if	CRYPT
X	s = resetkey(bp);
X	if (s != TRUE)
X		return s;
#endif
X        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
X                return s;
X        bp->b_flag &= ~(BFINVS|BFCHG);
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
X        if (s == FIOFNF) {                      /* File not found.      */
X                if (mflg) mlwrite("[New file]");
X                goto out;
X        }
X
X        if (mflg) {
X		 mlwrite("[Reading %s ]", fname);
X	}
X
#if UNIX & before
X	if (fileispipe)
X		ttclean(TRUE);
#endif
X	/* read the file in */
X        nline = 0;
#if VMALLOC
X	/* we really think this stuff is clean... */
X	odv = doverifys;
X	doverifys = 0;
#endif
X        while ((s = ffgetline(&len)) == FIOSUC) {
X		if (addline(bp,fline,len) != TRUE) {
X                        s = FIOMEM;             /* Keep message on the  */
X                        break;                  /* display.             */
X                } else {
#if UNIX
X                	/* reading from a pipe, and internal? */
X			if (fileispipe && !ffhasdata()) {
X				flag |= WFEDIT;
X				if (!done_update || bp->b_nwnd > 1)
X					flag |= WFHARD;
X			        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
X			                if (wp->w_bufp == bp) {
X			                        wp->w_linep=lforw(bp->b_linep);
X			                        wp->w_dotp =lback(bp->b_linep);
X			                        wp->w_doto = 0;
X						wp->w_flag |= flag;
X			                }
X			        }
X				update(FALSE);
X				done_update = TRUE;
X				flag = 0;
X			} else {
X				flag |= WFHARD;
X			}
X			
X		}
#endif
X                ++nline;
X        }
#if VMALLOC
X	doverifys = odv;
#endif
X	bp->b_flag &= ~BFCHG;
#if UNIX & before
X	if (fileispipe == TRUE) {
X		ttunclean();
X	        TTflush();
X	        sgarbf = TRUE;
X	}
#endif
#if FINDERR
X	if (fileispipe == TRUE) {
X		strncpy(febuff,bp->b_bname,NBUFN);
X		newfebuff = TRUE;
X	}
#endif
X        ffclose();                              /* Ignore errors.       */
#if DOSFILES
X	if (dosfile && (gmode & MDDOS))
X		bp->b_mode |= MDDOS;
#endif
X	if (mflg)
X		readlinesmsg(nline,s,fname,ffronly(fname));
X
X	/* set read-only mode for read-only files */
X	if (fname[0] == '!' 
#if RONLYVIEW
X		|| ffronly(fname) 
#endif
X	) {
X		bp->b_mode |= MDVIEW;
X	}
X	
X	bp->b_active = TRUE;
X
X	/* set C mode for C files */
X	if (gmode & MDCMOD) {
X		char *cp;
X		cp = &fname[strlen(fname)-2];
X		if (cp >= fname && cp[0] == '.' && strchr("chCH",cp[1]) ) {
X			bp->b_mode |= MDCMOD;
X		}
X	}
X
out:
X	TTkopen();	/* open the keyboard again */
X        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
X                if (wp->w_bufp == bp) {
X                        wp->w_linep = lforw(bp->b_linep);
X                        wp->w_dotp  = lforw(bp->b_linep);
X                        wp->w_doto  = 0;
X                        wp->w_mkp = NULL;
X                        wp->w_mko = 0;
X                        wp->w_ldmkp = NULL;
X                        wp->w_ldmko = 0;
X                        wp->w_flag |= WFMODE|WFHARD;
X                }
X        }
X        if (s == FIOERR || s == FIOFNF) {	/* False if error.      */
#if UNIX
X		extern int sys_nerr, errno;
X		extern char *sys_errlist[];
X		if (errno > 0 && errno < sys_nerr)
X			mlwrite("%s: %s",fname,sys_errlist[errno]);
#endif
X                return FALSE;
X	}
#if     NeWS
X        newsreportmodes() ;
#endif
X        return TRUE;
}
X
/* utility routine for no. of lines read */
readlinesmsg(n,s,f,rdonly)
{
X	mlwrite("[%sRead %d line%s from \"%s\"%s]",
X     (s==FIOERR ? "I/O ERROR, " : (s == FIOMEM ? "OUT OF MEMORY, ":"")),
X	n, n != 1 ? "s":"", f, rdonly ? "  (read-only)":"" );
}
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 */
X
makename(bname, fname)
char    bname[];
char    fname[];
{
X        register char *cp2;
X        register char *lastsl;
X
X        register char *fcp;
X        register char *bcp;
X
X	fcp = &fname[strlen(fname)];
X	/* trim trailing whitespace */
X	while (fcp != fname && (fcp[-1] == ' ' || fcp[-1] == '\t'
#if UNIX  /* trim trailing slashes as well */
X					 || fcp[-1] == '/'
#endif
X							) )
X                *(--fcp) = '\0';
X	fcp = fname;
X	/* trim leading whitespace */
X	while (*fcp == ' ' || *fcp == '\t')
X		fcp++;
X
#if     AMIGA
X        while (cp1!=fcp && cp1[-1]!=':' && cp1[-1]!='/')
X                --cp1;
#endif
#if     VMS
X        while (cp1!=fcp && cp1[-1]!=':' && cp1[-1]!=']')
X                --cp1;
#endif
#if     CPM
X        while (cp1!=fcp && cp1[-1]!=':')
X                --cp1;
#endif
#if     MSDOS
X        while (cp1!=fcp && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
X                --cp1;
#endif
#if     ST520
X        while (cp1!=fcp && cp1[-1]!=':' && cp1[-1]!='\\')
X                --cp1;
#endif
#if     UNIX
X	bcp = bname;
X	if (*fcp == '!') { /* then it's a shell command.  bname is first word */
X		*bcp++ = '!';
X		while (isspace(*++fcp))
X			;
X		while (!isspace(*fcp) && bcp < &bname[NBUFN-1])
X			*bcp++ = *fcp++;
X		*bcp = '\0';
X		return;
X	}
X	if (lastsl = strrchr(fcp,'/')) {
X		strncpy(bcp,lastsl+1,NBUFN);
X		bcp[NBUFN-1] = '\0';
X	} else {  /* no slashes, use the filename as is */
X		strncpy(bcp,fcp,NBUFN);
X		bcp[NBUFN-1] = '\0';
X	}
X	return;
X
#else
X        cp2 = &bname[0];
X        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
X                *cp2++ = *cp1++;
X        *cp2 = 0;
#endif
}
X
unqname(name,ok_to_ask)	/* make sure a buffer name is unique */
char *name;	/* name to check on */
{
X	register char *sp;
X
X	/* check to see if it is in the buffer list */
X	while (bfind(name, 0, NO_CREAT) != NULL) {
X
X		sp = &name[strlen(name)-1];  /* last char */
X		if (sp - name >= 2 && sp[-1] == '-') {
X			if (sp[0] == '9')
X				sp[0] = 'A';
X			else if (sp[0] == 'Z')
X				goto choosename;
X			else if (isdigit(sp[0]) || isupper(sp[0]))
X				sp[0] += 1;
X		} else if (sp + 2 < &name[NBUFN-1])  {
X			strcat(sp, "-1");
X		} else {
X		choosename:
X			if (ok_to_ask) {
X				do {
X					mlreply("Choose a unique buffer name: ",
X						 name, NBUFN);
X				} while (name[0] == '\0');
X			} else { /* can't ask, just overwrite end of name */
X				sp[-1] = '-';
X				sp[0] = '1';
X			}
X		}
X	}
}
X
/*
X * Ask for a file name, and write the
X * contents of the current buffer to that file.
X */
filewrite(f, n)
{
X        register int    s;
X        static char            fname[NFILEN];
X
X	strncpy(fname, curbp->b_fname, NFILEN);
X	
X	/* HACK -- this implies knowledge of how kbd_engl works! */
X	if (isnamedcmd && lastkey != '\r') {
X	        if ((s=mlreply("Write to file: ", fname, NFILEN)) != TRUE)
X	                return s;
X		if ((s = glob(fname)) != TRUE)
X			return FALSE;
X		if (strcmp(fname,curbp->b_fname) &&
X			fname[0] != '!' && flook(fname,FL_HERE)) {
X			if (mlyesno("File exists, okay to overwrite") != TRUE) {
X				mlwrite("File not written");
X				return FALSE;
X			}
X		}
X        }
X        if ((s=writeout(fname,curbp,TRUE)) == TRUE) {
X                curbp->b_flag &= ~BFCHG;
X		markWFMODE(curbp);
X        }
X        return s;
}
X
/*
X * Save the contents of the current
X * buffer in its associatd file. Do 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.
X */
filesave(f, n)
{
X        register int    s;
X
#if its_a_bug
X        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
X                return TRUE;
#endif
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,curbp,TRUE)) == TRUE) {
X                curbp->b_flag &= ~BFCHG;
X		markWFMODE(curbp);
X        }
X        return s;
}
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 */
writeout(fn,bp,msgf)
char    *fn;
BUFFER *bp;
{
X        register LINE   *lp;		/* current line */
X        register long   numchars;	/* # of chars in file */
X        REGION region;
X
X	/* starting at the beginning of the buffer */
X        lp = lforw(bp->b_linep);
X        region.r_linep = lp;
X        region.r_offset = 0;
X
X	/* start counting chars */
X        numchars = 0;
X        while (lp != bp->b_linep) {
X		numchars += llength(lp) + 1;
X		lp = lforw(lp);
X        }
X        region.r_size = numchars;
X        
#if DOSFILES
X	dosfile = bp->b_mode & MDDOS;
#endif
X
X	return writereg(&region,fn,msgf);
}
X
writeregion(f,n)
{
X        REGION region;
X	int s;
X        static char fname[NFILEN];
SHAR_EOF
true || echo 'restore of file.c failed'
echo 'End of Vile part 6'
echo 'File file.c is continued in part 7'
echo 7 > _shar_seq_.tmp
exit 0
-- 
		paul fox, pgf at cayman.com, (617)494-1999
		Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139



More information about the Alt.sources mailing list