4.3BSD/usr/contrib/apl/src/xed.c

Compare this file to the similar file:
Show the results in this format:

static char Sccsid[] = "xed.c @(#)xed.c	1.1	10/1/82 Berkeley ";
#

/*
 *	V7.15 81/09/16 14:22	Fixed bug causing bus errors occasionally
 *	V7.14 81/09/10 21:50	-B dynamically allocated line buffer
 *	V7.13 81/07/25 22:51	added -O and "long" pointers
 *
 * Editor
 *
 *	Major additions beginning	77/04
 *	Conversion to version 7		79/12
 *	Conversion to VAX		80/11
 *
 *	Purdue University, Engineering Computer Network
 *
 *	Tgi -- Room 337A
 *	Electrical Engineering Dept
 *	Purdue University
 *	West Lafayette, Indiana
 *	47907
 *	317/49-41592
 */

#define XED		/* enable powerful stuff */
#define V7		/* enable environment stuff for protocol */

/*
 *	At the entry to a function (PDP-11) the following sequence
 *	of instructions is executed:
 *		func:	jsr	r5,csv
 *		csv:	mov	r5,r0
 *		csv+2:	mov	sp,r5
 *	If a signal occurs between the first and second, or between the
 *	second and third instructions, r5 will NOT contain a valid
 *	stack address.  Hence, when longjmp() attempts to validate
 *	the environment pointer (r5) links, an instruction will be
 *	fetched instead of a valid pointer, and will generally cause
 *	one of "memory fault", "bus error", or "illegal instruction"
 *	resulting in the loss of the editing session.
 *
 *	Due to this wonderful feature of version 7 ingenuity, I have
 *	reverted to using setexit/reset, since they are simpler and
 *	do not assume that I do not know what I am doing.
 *
 *	80/11/10 V7.01 Tgi
 */

#ifndef pdp11
#include <setjmp.h>
jmp_buf	_env_rst;
#define setexit() setjmp(_env_rst)
#define reset()	longjmp(_env_rst,1)
#endif

#include <sys/types.h>
#include <sys/stat.h>

/*
 * Machine-dependent definitions
 */

#ifdef pdp11
# define BPB	8	/* bits per byte */
# define BPW	(BPB*sizeof(int))/* bits per word */
# define BPWC	4	/* log2(BPW) */
# define BPWM	017	/* mask of BPWC bits */
  typedef short	block;
  typedef short	charac;
  typedef short	filedes;
  typedef short	flag;
  typedef int	(*func)();
  typedef short	linep;
#endif

#ifdef vax
# define BPB	8	/* bits per byte */
# define BPW	(BPB*sizeof(int))/* bits per word */
# define BPWC	5	/* log2(BPW) */
# define BPWM	037	/* mask of BPWC bits */
  typedef long	block;
  typedef int	charac;
  typedef short	filedes;
  typedef char	flag;
  typedef int	(*func)();
  typedef long	linep;	/* NEW */
#endif

/*
 * conditional compilation
 */

#ifdef XED
# define AGAIN		/* enable "o" "again" command */
# define ALLOC	1024	/* line buffer size */
# define APLMAP		/* enable Apl character mapping */
# define DEBUG		/* enable "du" command */
# define DUMB	0	/* enable command to disable spcl chars */
# define EOL		/* enable special eol stuff */
# define EXTMARK	/* extended "k" capability */
# define G_VFY		/* enable verifying on "g" command */
# define HELP	"/etc/xed.doc"
# ifdef pdp11		/* only needed on 16-bit machines */
#  define HUGE		/* enable "huge" file stuff */
# endif
# define PAGE		/* enable proper line counting on ":" */
# define PARENS		/* enable "b" suffix to count parentheses */
# define PIPE		/* enable | command to pipe to process */
# define PROMPT	">"
# define STRLEN		/* enable string-length counting code */
# define TABS	((LBSIZE+sizeof(int)-1)/sizeof(int)) /* words for tab stops */
# define TTL	"XED\tV7.15"
/* #define TTL_NL	9	/* location of newline in TTL */
# define UNDO		/* enable "u"ndo command */
# define USE		/* enable "@" command */
# define XDEL		/* enable undelete stuff */
# define YINT		/* enable special interrupt processing */
#endif

/*
 * stuff for EED, instead of XED
 */

#ifndef XED
# define HELP	"/etc/eed.doc"
# define PROMPT	"*"
# define TTL	"EED"
#else
# define EEDHELP	"/etc/eed.doc"
# define EEDPROMPT "*"
# define EEDTTL	"EED"
#endif

/*
 * stuff normally enabled
 */

#define CLEAR	"\33:\33H\33J\32\14"	/* HP-2640A, Lear ADM-3A */
#define CMDS	"edsav"	/* all commands written if exists */
#ifndef DUMB
# define DUMB	1	/* enable command to disable spcl chars */
#endif

/*
 * special stuff, occasionally enabled
 */

#define LOG	"/a/tgi/etc/xed.log"	/* feature use logging */

/*
 * data #defines
 */

#define BAK	4	/* file.bak - backup() */
#define BLKSIZE	512	/* disk block size (bytes) */
#define BS1	0100000	/* stty() */
#define CBACK	14	/* back-reference: \(blah\)more\1 */
#define CBRA	1	/* \( */
#define CCHR	2	/* literal character */
#define CCL	6	/* character class [x...y] */
#define CCOUNT	(80-1)	/* terminal width */
#define CDOL	10	/* ...$ */
#define CDOT	4	/*  .  */
#define CEOF	11	/* end of pattern */
#define CKET	12	/* \) */
#define EOF	-1	/* end of file */
#define ESIZE	128	/* regular expression size */
#define FILE	0	/* no extension - backup() */
#define FNSIZE	64	/* max size of pathname to file */
#define GBSIZE	256	/* max global command length */
#define HUP	3	/* file.hup - backup() */
#define INT	2	/* file.int - backup() */
#define LBSIZE	512	/* max line length */
#define LMASK	077	/* mask for "locked" file */
#define LMODE	(MODE&~LMASK)	/* mode for "locked" file */
#define MODCNT	35	/* default mod count before auto-write */
#define MODE	0666	/* mode for normal files */
#define NBRA	9	/* number of \( \) pairs */
#define NCCL	8	/* not in character class: [^x...y] */
#define PAGSIZ	22	/* page size for ":" command */
#define READ	0	/* getblock: read function */
#define SIGBUS	10	/* Bus error */
#define SIGEMT	7	/* EMT trap */
#define SIGFPE	8	/* Floating Point Exception */
#define SIGHUP	1	/* Hangup signal */
#define SIGILL	4	/* Illegal instruction */
#define SIGINT	2	/* Interrupt signal */
#define SIGIOT	6	/* IOT trap */
#define SIGPIP	13	/* Broken pipe for ! stuff */
#define SIGQIT	3	/* Quit signal */
#define SIGSEGV	11	/* Memory fault */
#define SIGSYS	12	/* Bad system call */
#define SIGTRC	5	/* Trace/BPT for mail stuff */
#define SIGTRM	15	/* Termination */
#define STAR	1	/*  *  */
#define TABFILL	'\t'	/* fill character for tab expansion */
#define TMP	1	/* file.edt - backup() */
#define TRM	5	/* file.trm - backup() */
#define TTSIZE	(512+4)	/* terminal output buffer size */
#define WRITE	1	/* getblock: write function */
#define ever	(;;)

#define error	errfunc
#define ctrl(x)	((x)&037)

#ifdef AGAIN
char	agbuf[GBSIZE],	/* save area for "again" command */
	*agp	= 0;	/* "again" command pointer */
flag	agf	= 0;	/* "again" flag  (executing the command) */
#endif

#ifdef ALLOC
int	lbsize	= LBSIZE;/* line buffer size */
#endif

#ifdef APLMAP
flag	aplmap	= 0;	/* Apl character mapping */
#include "aplmap.h"	/* apl ADM-3A char set mapping tables */
#endif

#ifdef CKPT
char	*cfname	= "/tmp/ce00000";/* filename for checkpoint */
int	recovry	= 0,	/* non-zero to recover checkpointed session */
	tfnum;		/* index into tfname for "00000" string */
#endif

#ifdef CLEAR
char	*clears = CLEAR;/* screen-clear sequence */
flag	zflg	= 0;	/* if "stty bs1" not set */
			/* bs1 displays ctrl-z as ^Z on tty */
#endif

#ifdef CMDS
filedes	cmd	= 0;	/* file des for command-save file */
char	cmdfil[] = CMDS;/* command-save file */
#endif

#ifdef DEBUG
flag	tflg	= 0;	/* tracing flag */
#endif

#ifdef DUMB
flag	dumbf	= DUMB;	/* 1 = disable special chars in patterns */
#endif

#ifdef EOL
charac	eol	= 0;	/* "end-of-line" char for multiple commands */
			/*   per line */
flag	prompt3	= 1;	/* disable prompts for "eol" stuff */
#endif

#ifdef G_VFY
flag	gaskf	= 0;	/* verify mode on global command */
#endif

#ifdef HELP
filedes	doc	= 0;	/* "help" file descriptor */
char	*help	= HELP;	/* "help" file name */
#endif

#ifdef LOG
char	logfile[]= LOG;	/* logging use of features */
filedes	lfile	= 0;	/* logging file descriptor */
short	logamp;		/* since s/x/&/ may be done many times */
struct logstat {
	short	l_uid;	/* user id of caller */
	char	l_xed,		/* 1 if xed, 0 if eed, 2 if apled */
		l_inter;	/* 1 if interactive */
/* command features */
	short	lc_shell,	/*  !  */
		lc_pipe,	/*  |  */
		lc_piplus,	/*  |+  */
		lc_piminus,	/*  |-  */
		lc_dpipe,	/*  ||  */
		lc_pfrom,	/*  |<  */
		lc_pto,		/*  |>  */
		lc_at,		/*  @  */
		lc_colon,	/*  :  */
		lc_star,	/*  *  */
		lc_clnminus,	/*  :-  */
		lc_comment,	/*  : stuff  or  * stuff  */
		lc_append,	/*  a  */
		lc_abort,	/*  abort  */
		lc_aspace,	/*  a line  */
		lc_aslash,	/*  a/string/  */
		lc_browse,	/*  bN  */
		lc_change,	/*  c  */
		lc_cslash,	/*  c/s1/s2/  */
		lc_copy,	/*  coNN  */
		lc_delete,	/*  d  */
		lc_depth,	/*  d=NN  */
		lc_directory,	/*  d path  */
		lc_edit,	/*  e file  */
		lc_eol,		/*  e=C  */
		lc_errmsg,	/*  eNN  */
		lc_exp,		/*  exp  */
		lc_eplus,	/*  e+  */
		lc_eminus,	/*  e-  */
		lc_fshow,	/*  f  */
		lc_fset,	/*  f file  */
		lc_fillset,	/*  f=C  */
		lc_global,	/*  g/str/cmd  */
		lc_gvfy,	/*  g/str/vcmd  */
		lc_header,	/*  h  */
		lc_help,	/*  help  */
		lc_insert,	/*  i  */
		lc_islash,	/*  i/string/  */
		lc_join,	/*  j  */
		lc_jglue,	/*  j/glue/  */
		lc_klist,	/*  k  */
		lc_kset,	/*  kC  */
		lc_list,	/*  l  */
		lc_move,	/*  mNN  */
		lc_moove,	/*  moNN  */
		lc_magic,	/*  m  */
		lc_numbers,	/*  n  */
		lc_numinus,	/*  n-  */
		lc_numplus,	/*  n+  */
		lc_o,		/*  o ^Q  */
		lc_print,	/*  p  */
		lc_pprint,	/*  pp  */
		lc_quit,	/*  q  */
		lc_qimm,	/*  qi  */
		lc_quote,	/*  q=C  */
		lc_read,	/*  r  */
		lc_substitute,	/*  s/s1/s2/  */
		lc_stop,	/*  s  */
		lc_savecount,	/*  saNN  */
		lc_tablist,	/*  t  */
		lc_tabset,	/*  t,NN  */
		lc_tabchar,	/*  t=C  */
		lc_transfer,	/*  tNN  */
		lc_undo,	/*  u  */
		lc_vglobal,	/*  v/str/cmd  */
		lc_write,	/*  w  */
		lc_wonto,	/*  w>  */
		lc_wimm,	/*  wi  */
		lc_width,	/*  w=NN  */
		lc_xundelete,	/*  x  */
		lc_yintr,	/*  y  */
		lc_yminus,	/*  y-  */
		lc_yplus,	/*  y+  */
/* address features */
		la_dot,		/*  .  */
		la_dotdot,	/*  ..  */
		la_dol,		/*  $  */
		la_num,		/*  NN  */
		la_plus,	/*  +  */
		la_minus,	/*  -  */
		la_caret,	/*  ^  */
		la_quote,	/*  'a  */
		la_letter,	/*  A  */
		la_slash,	/*  /str/  */
		la_query,	/*  ?str?  */
		la_equal,	/*  =  */
/* pattern features */
		lp_caret,	/*  ^  */
		lp_dol,		/*  $  */
		lp_dot,		/*  .  */
		lp_star,	/*  *  */
		lp_ccl,		/*  [ ]  */
		lp_nccl,	/*  [^ ]  */
		lp_paren,	/*  \( \)  */
		lp_digit,	/*  \1 \2 \3 ...  */
/* substitution features */
		lp_amp,		/*  &  */
/* miscellaneous features */
		lm_quote,	/*  ...q  */
		lm_bracket,	/*  ...b  */
		lm_overwrite;	/*  -O,wi  */
/* resources */
	long	lt_start,	/* starting time */
		lt_end,		/* elapsed time */
		lt_usercpu,	/* user cpu time */
		lt_syscpu,	/* system cpu time */
		lt_kidscpu,	/* total ! kids time */
		lt_rlines,	/* total lines read */
		lt_wlines;	/* total lines written */
} logstats;
#endif

#ifdef PAGE
int	ccount	= CCOUNT;/* terminal width */
#endif

#ifdef PARENS
int	parenc[3] = {0, 0, 0};/* parentheses counts */
flag	parenf	= 0;	/* count parentheses and brackets */
#endif

#ifdef PIPE
filedes	pfile	= 0;	/* "pipe" file descriptor */
char	*pfname	= "/tmp/ep00000";/* for "double-piping" */
flag	piperr	= 0,	/* pipe error flag - shell() */
	pno	= -1,	/* piping line numbering flag (default n-) */
	strict	= 1;	/* strict exit status checking for | */
#endif

#ifdef STRLEN
charac	quotec	= '\0',	/* quote character other than " or ' */
	quotec2	= '\0';	/* closing quote */
int	quotef	= 0;	/* length of strings within " or ' chars */
#endif

#ifdef TABS
charac	tabfill	= TABFILL,/* fill character */
	tabc	= 0;	/* tab character - if 0 no tab processing */
int	maxtab	= -1,	/* last column number with tab stop */
	tabs[TABS];	/* each bit on = tab stop */
#endif

#ifdef UNDO
linep	undo_oldp,	/* original line pointer */
	undo_newp;	/* replacement line */
#endif

#ifdef USE
filedes	alt	= 0;	/* alternate command input file */
char	altfile[FNSIZE];
flag	eflg2	= 0;	/* another kludge */
#endif

#ifdef XDEL
linep	deleted = 0;	/* pointer to deleted line pointers */
int	ndeleted = 0;	/* number of lines */
#endif

#ifdef YINT
flag	yflg	= 0;	/* page upon interrupt */
linep	*yplus	= 0;	/* page from this line - if zero, from dot */
#endif

/*
 * globals
 */

block	iblock	= -1,	/* block number of input buffer */
	oblock	= -1;	/* output buffer block number */

char	*braelist[NBRA],	/* bracket \( \) end list */
	*braslist[NBRA],	/* bracket \( \) start list */
	dotbak[] = ".bak",
	dotedt[] = ".edt",	/* "file saved" file */
	dothup[] = ".hup",
	dotint[] = ".int",
	dottrm[] = ".trm",
	*dots[] = { dothup, dottrm, dotedt, dotint, 0 },
	expbuf[ESIZE + 4],	/* expression buffer */
	file[FNSIZE],		/* filename buffer */
#ifndef ALLOC
	genbuf[LBSIZE],		/* generated line buffer */
#else
	*genbuf,		/* generated line buffer pointer */
#endif
	ibuff[BLKSIZE],		/* input tmpfile buffer */
	line[TTSIZE + 4],	/* terminal output buffer */
#ifndef ALLOC
	linebuf[LBSIZE],	/* line buffer for getline()/putline() */
#else
	*linebuf,		/* line buffer for getline()/putline() */
#endif
	no[]	= "no ",
	null[]	= "",		/* "" */
	obuff[BLKSIZE],		/* output tmpfile buffer */
	off[]	= "off",
	on[]	= "on",
	prcntu[] = "%u\n",	/* %u */
	quote_s[] = "s",	/* "s" */
	rhsbuf[LBSIZE / 2],	/* right-hand-side expression buffer */
	savedfile[FNSIZE],	/* saved filename */
	tempfile[FNSIZE],	/* scratch area for filename */

	*editor,	/* argv[0] */
	*e_prompt = PROMPT,/* editor command prompt */
	*fmtlno	= "%7u=",/* format for line-number output */
	*globp,		/* global command pointer */
	*linp	= line,	/* line pointer */
	*linebp,
	*loc1,		/* start pointer of & string */
	*loc2,		/* end pointer of & string */
	*locs,
	*nextip,
	*overfile,	/* filename mode was changed on */
	*tfname	= "/tmp/e00000",/* "buffer" name */
	*ver	= TTL;	/* ID message */

charac	lastc	= 0,	/* peekc set to lastc on interrupt */
	peekc	= 0;	/* one character pushback */

int	brcount	= 1,	/* number of lines to output on "newline" */
	col	= 0,	/* column counter for calculating line wraps */
	line_num,	/* integer for line number on output */
	modcount = MODCNT,/* number of mods before auto-write */
	overmode,	/* mode of overridden file */
	mods	= 0,	/* number of mods */
	nbra	= 0,	/* count of currently defined \( \) pairs */
	ninbuf,		/* bytes in tmpfile input buffer */
	nleft,		/* bytes remaining in tmpfile output buffer */
	num_reads = 0,	/* indicator to aid text_modified-- */
			/* first read isn't really a modify */
	pcount	= PAGSIZ-1,/* number of lines to display on ":" command */
	s_cnt	= 0,	/* counter for "s/str1/str2/nn" */
	s_tmp	= 0,	/* scratch var for same */
	savf,		/* counter for auto-write stuff */
	text_modified = 0;/* flag--on if text was modified */

filedes	fout	= 1,	/* putchar() writes on this fildes */
	io	= 0,	/* file descriptor for "r", "w", "e" */
	tfile	= -1;	/* file des for "buffer" */

flag	aflg	= 0,	/* "apl mode" flag */
	appflg	= 0,	/* append flag (if "w>file") */
	badf	= 0,	/* bad read on temp file */
	bflg	= 0,	/* "back-up" flag -- Generate back-up file */
	bflg2	= 0,	/* Secondary "back-up" flag */
	circfl,		/* reg expr started with ^ */
	curt	= 0,	/* short error messages -- ie: '?' */
	deltflg	= 0,	/* don't delete .edt file upon exit */
	eflg	= 0,	/* echo input flag */
	eof	= 0,	/* eof was last char typed */
	fflg	= 0,	/* "create" flag */
	globf2	= 0,	/* kludge for -f */
#ifdef HUGE
	hugef	= 0,	/* -h is process huge file */
	hugef2	= 0,	/* getblock() conversion to huge */
#endif
	hupflag	= 0,	/* hangup signal has been caught */
	ichanged,	/* ibuf has been changed */
	iflg	= 0,	/* file.int and exit on interrupt */
	immflg	= 0,	/* immediate flag -- q and e */
	io_w	= 0,	/* writing in progress */
	listf	= 0,	/* list control chars explicitly */
	noshell	= 0,	/* true if no ! command allowed */
	over	= 0,	/* override permissions on write if possible */
	pflag,		/* print line after doing command */
	pipef	= 0,	/* for talking to pipes */
	prompt1	= 1,	/* flag--enable or disable line-num prompts */
	prompt2	= 1,	/* flag--enable or disable ALL prompting */
	reading	= 0,	/* waiting on tty read */
	seekf	= 0,	/* no seek to EOF on error on fd 0 */
	termflg	= 0;	/* if termination signal (15) occurred */

linep	*addr1,		/* lower line bound */
	*addr2,		/* upper line bound */
	*dol,		/* last line in file */
	*dot,		/* "current" line */
	*dotdot,	/* last different "dot" */
	*endcore,	/* current end of memory */
	*fendcore,	/* start of dynamic area */
	*lastdot,	/* last "dot" */
	names['z' - 'a' + 1],	/* "k" command markers */
#ifdef EXTMARK
	names2['z' - 'a' + 1],	/* "k" command markers */
#endif
	*old_a1,	/* previous address bounds */
	*old_a2,
	tline,		/* pointer to next available pos in tmpfile */
	*zero;		/* anchor line for all other lines */

/*
 * magic constants used in many places
 */

#ifdef pdp11
# define _1a	 ~0377
# define _2a	  0400
# define _3a	  0377
# define _4a	  0774
# define _5a	   255
# define _6a	077776
# define _1b	 ~0177
# define _2b	  0200
# define _3b	  0777
# define _4b	  0774
# define _5b	   511
# define _6b	077777
#endif

#ifdef vax
# define _1a	    ~0377
# define _2a	     0400
# define _3a	077777777
# define _4a	     0774
# define _5a	    65535
# define _6a	077777776
#endif

#ifdef HUGE
int	_1[]	= { _1a, _1b },	/* tl &= _1; getline() */
	_2[]	= { _2a, _2b },	/* tl += _2; getline()... */
	_3[]	= { _3a, _3b },	/* bno = ... & _3; getblock() */
	_4[]	= { _4a, _4b },	/* off = ... & _4; getblock() */
	_5[]	= { _5a, _5b },	/* if (bno >= _5)... getblock() */
	_6[]	= { _6a, _6b };	/* tline += ... & _6; */
#else
# define _1	_1a
# define _2	_2a
# define _3	_3a
# define _4	_4a
# define _5	_5a
# define _6	_6a
#endif

/*
 * error messages
 *
 *	(there are more than these)
 */

char	*errtext[] = {
	/*  0 */	"syntax is k[a-z]",
	/*  1 */	"illegal command format",
	/*  2 */	"no command",
	/*  3 */	"no tab character",
	/*  4 */	"can't change filename",
	/*  5 */	"file name syntax",
	/*  6 */	"recursive \"@\" command",
	/*  7 */	"null file name illegal",
	/*  8 */	"unrecognized command",
	/*  9 */	"no tabs set",
	/* 10 */	"global command not allowed with huge file",
	/* 11 */	"file name too long",
	/* 12 */	"expanded line too long",
	/* 13 */	"no such line",
	/* 14 */	"can't fork",
	/* 15 */	"can't write to process",
	/* 16 */	"no lines",
	/* 17 */	"backup(FILE) error (?)",
	/* 18 */	"string not found",
	/* 19 */	"  '  must be followed by [a-z]",
	/* 20 */	"address syntax error",
	/* 21 */	"lower address bound > upper one",
	/* 22 */	"address illegal here",
	/* 23 */	"non-existent line number",
	/* 24 */	"bottom of file reached",
	/* 25 */	"command syntax error",
	/* 26 */	"\"advance\" error (?)",
	/* 27 */	"null string illegal",
	/* 28 */	"destination not found",
	/* 29 */	"INTERRUPT!",
	/* 30 */	"line too long",
	/* 31 */	"missing destination address",
	/* 32 */	"I/O error--file not saved!",
	/* 33 */	"file overflows available memory",
	/* 34 */	"file too large (TMPERR)",
	/* 35 */	"I/O error on temp file (TMPERR)",
	/* 36 */	"open error on temp file (TMPERR)",
	/* 37 */	"recursive global command",
	/* 38 */	"global command list too long",
	/* 39 */	"substitute pattern not found",
	/* 40 */	"missing substring",
	/* 41 */	"string2 too long",
	/* 42 */	"substring too long",
	/* 43 */	"substituted string too long",
	/* 44 */	"too many  \\(",
	/* 45 */	"unbalanced  \\(  \\)",
	/* 46 */	"\\n  illegal",
	/* 47 */	"unimplemented feature",
	/* 48 */	"[nothing written]",
	/* 49 */	"pattern too complicated",
	/* 50 */	"can't create temp file (TMPERR)",
	/* 51 */	"bad directory",
	/* 52 */	"no ! allowed",
	/* 53 */	"can't read ",
	/* 54 */	"can't create ",
	/* 55 */	"%u line%s\n",
	/* 56 */	"[file saved]",
	/* 57 */	"\nHangup!\n",
	/* 58 */	"\nTerminated...\n",
	/* 59 */	"EOF illegal here",
	/* 60 */	"can't join to line 0",
	/* 61 */	"! not allowed with global command",
	/* 62 */	"no filename specified",
	/* 63 */	"not enough  \\( \\)  pairs",
	/* 64 */	"can't create pipe file (PIPERR)",
	/* 65 */	"open error on pipe file (PIPERR)",
	/* 66 */	"can't checkpoint",
	/* 67 */	"can't recover",
};
#define NERR	(sizeof errtext / sizeof errtext[0])

/*
 * ! error strings
 */

char *status[] = {
	/*  0 */	0,
	/*  1 */	"hangup",
	/*  2 */	"interrupt",
	/*  3 */	"quit",
	/*  4 */	"illegal instruction",
	/*  5 */	"bpt",
	/*  6 */	"iot",
	/*  7 */	"emt",
	/*  8 */	"fpp",
	/*  9 */	"killed",
	/* 10 */	"bus error",
	/* 11 */	"memory fault",
	/* 12 */	"bad sys call",
	/* 13 */	"broken pipe",
	/* 14 */	"alarm",
	/* 15 */	"terminated",
#ifdef pdp11
	/* 16 */	"time limit",
#else
	/* 16 */	0,
	/* 17 */	"stopped",
	/* 18 */	"terminal stop",
	/* 19 */	"continue",
	/* 20 */	"child status changed",
	/* 21 */	"terminal input",
	/* 22 */	"terminal output",
	/* 23 */	"terminal input ready",
	/* 24 */	"cpu timelimit exceeded",
	/* 25 */	"filesize limit exceeded",
#endif
};
#define NSTR	(sizeof status / sizeof status[0])

#define putsn(x) (puts2((x)),putchar('\n'))
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))

/*
 * function declarations
 */

linep	*findmark();
char	*getblock();
long	lseek();
func	signal();
#ifndef CKPT
int	badsig(),
#else
int	checkpoint(),
#endif
	hangup(),
	mail(),
	onintr(),
	term();

/*
 * signals
 */

struct sigtab {
	int	s_sig,
		s_func;
} sigtab1[] = {
#ifdef CKPT
	SIGILL,		checkpoint,
	SIGIOT,		checkpoint,
	SIGEMT,		checkpoint,
	SIGFPE,		checkpoint,
	SIGBUS,		checkpoint,
	SIGSEGV,	checkpoint,
	SIGSYS,		checkpoint,
#else
	SIGILL,		badsig,
	SIGIOT,		badsig,
	SIGEMT,		badsig,
	SIGFPE,		badsig,
	SIGBUS,		badsig,
	SIGSEGV,	badsig,
	SIGSYS,		badsig,
#endif
	0,		0,
}, sigtab2[] = {
	SIGTRC,		mail,
	SIGHUP,		hangup,
	SIGTRM,		term,
	SIGINT,		onintr,
	0,		0,
};

main(argc, argv)
char **argv;
{
#ifdef CKPT
	extern checkpoint();
#else
	extern badsig();
#endif
	extern onintr(), hangup(), mail(), term();
#ifdef DEBUG
#ifdef EXPDMP
	extern expdmp();
#endif
#endif
	register n;
	register char *p1, *p2, *ep;
	func savint;

	signal(SIGQIT, 1);
	savint = signal(SIGINT, 1);
	ep = *argv;
#ifdef XED
	p1 = ep;
	p2 = p1;
	while (*p1)
		if (*p1++ == '/' && *p1 && *p1 != '/')
			p2 = p1;
	p1 = p2;
	*argv = p2;
	n = 0;
	while (*p1)
		if (*p1++ == 'x') {	/* xed .vs. eed */
			++n;
			break;
		}
	if (n == 0) {
		e_prompt = EEDPROMPT;
		ver = EEDTTL;
		help = EEDHELP;
		dumbf = 1;
	}
#ifdef LOG
	logstats.l_xed = n;
#endif
#endif
	prompt2 = istty(0);
#ifdef V7
	if (getenv("_OVERWRITE_"))
		++over;
#endif
	while (--argc)
		if (**++argv == '-') {
			while (*++*argv) {
				switch (**argv) {
				case '!':  /* no ! allowed */
					noshell = 1;
					break;
#ifdef APLMAP
				case 'A':  /* apl char mapping */
					aplmap = 1;
					errtext[29] = "G interrupt G";
					p1 = ver;
					while (*p1) {
						if ('A' <= *p1 && *p1 <= 'Z')
							*p1 |= 040;
						++p1;
					}
#endif
				case 'a':  /* apl mode */
					aflg = 1;
					fmtlno = "[ %u ]\t";
#ifdef DUMB
					dumbf = 1;
#endif
#ifdef XED
#ifdef TTL_NL
					ver[TTL_NL] = 0;
#endif
#endif
					break;
				case 'b':  /* file.bak on entry */
					bflg = 1;
					bflg2 = 1;
					break;
#ifdef PAGE
				case 'c':  /* crt depth in lines */
					++*argv;
					n = argnum(argv);
					if (n >= 0)
						pcount = n;
					break;
#endif
				case 'd':  /* don't delete .edt file */
					deltflg = 1;
					break;
				case 'e':  /* echo input commands */
					eflg = 1;
					break;
				case 'f':  /* create mode */
					fflg = 1;
					break;
#ifdef HUGE
				case 'h':  /* edit "huge" file */
					hugef = 1;
					break;
#endif
				case 'i':  /* file.int on interrupt */
					iflg = 1;
					break;
				case 'k':  /* kill verbose messages */
					curt = 1;
					break;
#ifdef EOL
				case 'l':  /* set eol char to "x" */
					if (*++*argv)
						eol = **argv;
					else
						--*argv;
					break;
#endif
				case 'm':  /* mod cnt for autosave */
					++*argv;
					n = argnum(argv);
					if (n >= 0)
						modcount = n;
					break;
				case 'n':  /* no line num */
					prompt1 = 0;
					break;
				case 'o':  /* no seek to EOF on error */
					seekf = 1;
					break;
				case 'p':  /* force prompts for pipe */
					pipef = 1;
					prompt2 = 1;
					break;
				case 'q':  /* don't inhibit quits */
					signal(SIGQIT, 0);
					break;
#ifdef DUMB
				case 'r':  /* spcl char meaning */
					dumbf ^= 01;
					break;
#endif
				case 's':  /* silent mode */
					prompt2 = 0;
					break;
#ifdef TABS
				case 't':  /* tab char */
					if (*++*argv)
						tabc = **argv;
					else
						--*argv;
					break;
#endif
#ifdef TABS
				case 'v':  /* tab fill char */
					if (*++*argv)
						tabfill = **argv;
					else
						--*argv;
					break;
#endif
#ifdef PAGE
				case 'w':  /* crt width */
					++*argv;
					n = argnum(argv);
					if (--n >= 2)
						ccount = n;
					break;
#endif
#ifdef YINT
				case 'y':  /* page on interrupt */
					yflg = 1;
					break;
#endif
#ifdef USE
				case '@':  /* set "@" filename */
					p2 = altfile;
					p1 = ++*argv;
					while (*p1 && p2 < &altfile[FNSIZE - 2])
						*p2++ = *p1++;
					if (*p1) {
						p2 = altfile;
						putsn(errtext[11]);
					}
					*p2 = '\0';
					*argv = &p1[-1];
					break;
#endif
#ifdef ALLOC
				case 'B':  /* line buffer size */
					++*argv;
					n = argnum(argv);
					if (n >= LBSIZE)
						lbsize = n;
					break;
#endif
#ifdef DEBUG
				case 'D':  /* trace mode -- debug */
					tflg = 1;
					break;
#ifdef EXPDMP
				case 'Q':  /* show pattern on quit */
					signal(SIGQIT, expdmp);
					break;
#endif
#endif
#ifdef XED
				case 'I':  /* suppress ID message */
					ver = 0;
					break;
				case 'P':  /* prompt */
					p1 = *argv;
					e_prompt = ++p1;
					while (*p1++);
					*argv = &p1[-2];
					break;
				case 'L':  /* line number prompt */
					p1 = *argv;
					fmtlno = ++p1;
					while (*p1++);
					*argv = &p1[-2];
					break;
				case 'C':  /* screen-clear */
					p1 = *argv;
					clears = ++p1;
					while (*p1++);
					*argv = &p1[-2];
					break;
#ifdef CKPT
				case 'R':  /* recover */
					++*argv;
					if ((recovry = argnum(argv)) == 0)
						recovry = 1;
					break;
#endif
				case 'O':  /* over-ride write perm */
					over ^= 01;
					break;
				case 'T':  /* temp filename */
					p1 = *argv;
					tfname = ++p1;
#ifdef PIPE
					while (*p1)
						if (*p1++ == ':') {
							p1[-1] = '\0';
							pfname = p1;
#ifdef CKPT
							break;
#endif
						}
#endif
#ifdef CKPT
					while (*p1)
						if (*p1++ == ':') {
							p1[-1] = '\0';
							cfname = p1;
						}
#endif
					*argv = &p1[-1];
					break;
#endif
				default:  /* tabs stops/illegals */
					if (!**argv || **argv == '-'
#ifdef TABS
						    || **argv == ','
#endif
								    )
						break;
#ifdef TABS
					if (**argv < '0' ||
					    **argv > '9') {
#endif
						printf("bad flag: -%c\n",
						    **argv);
						exit(1);
#ifdef TABS
					}
					n = argnum(argv);
					settab(n);
#endif
				}
			}
		} else {
			p1 = *argv;
			p2 = savedfile;
			while (*p2++ = *p1++)
				if (p2 >= &savedfile[FNSIZE - 2]) {
					putsn(errtext[11]);
					exit(1);
				}
			globf2 = 1;
			if (fflg)
				globp = "a\n";
			else
				globp = "r\n";
		}


#ifdef YINT
	if (iflg)
		yflg = 0;
#endif
#ifdef ALLOC
	linebuf = sbrk(lbsize);
	genbuf = sbrk(lbsize);
#endif
	fendcore = sbrk(0);
#ifdef CKPT
	if ((n = recovry) == 0)
#endif
		n = getpid();
#ifdef PIPE
	tmpname(pfname, n);
#endif
#ifdef CKPT
	tmpname(cfname, n);
#endif
	tmpname(tfname, n);	/* MUST be last call to tmpname */
#ifdef LOG
	logstats.l_uid = getuid();
	time(&logstats.lt_start);
	if (prompt2)
		++logstats.l_inter;
	if (aflg)
		logstats.l_xed = 2;	/* magic num for apled */
#endif
#ifdef CKPT
	if (recovry)
		recover();
#endif
	editor = ep;
	if (prompt2) {
#ifdef CMDS
		if ((cmd = open(cmdfil, 1)) > 0)
			lseek(cmd, 0L, 2);
		else
			cmd = 0;
#endif
		if (ver)
			putsn(ver);	/* XED V0.00 ... */
		flush_buf();
	} else
		modcount = 0;
#ifdef CMDS
	if (cmd && *savedfile) {
		write(cmd, "e,", 2);
		p1 = savedfile;
		while (*p1++);
		write(cmd, savedfile, --p1 - savedfile);
		write(cmd, "\n", 1);
	}
#endif
	signals(sigtab1);
	setexit();
	if (((int)savint & 01) == 0)
		signals(sigtab2);
#ifdef YINT
	else
		yflg = 0;
#endif
#ifdef CKPT
	if (!recovry)
#endif
		init();
	setexit();
cant:	do {
		commands(0);
	} while (are_you_sure());
	if (immflg == 0) {
		if (fflg)
			if (backup(FILE))
				text_modified = 0;
			else
				goto cant;
		if (text_modified == 0)
			backup(-TMP);
		else if (modcount && eof)
			if (backup(TMP) && prompt2)
				if (!curt)
					putsn(errtext[56]);
	}
	delexit(0);
}

abort() {
	register char *p;
	register charac c;

	setnoaddr();
	peekc = 0;
	p = "ort\n";
	while (*p)
		if ((c = getchar()) != *p++) {
			peekc = c;
			errmsg(25);
		}
#ifdef LOG
	++logstats.lc_abort;
#endif
	delexit(1);
}

linep *
address() {
	register minus;
	register charac c;
	register linep *a1, *start;
	register n, relerr;

	minus = 0;
	a1 = 0;
	for ever {
		c = getchar();
		if ('0' <= c && c <= '9') {
			peekc = c;
			n = getnum();
			if (a1 == 0) {
				a1 = zero;
				n += aflg;
#ifdef LOG
				if (!globp)
					++logstats.la_num;
#endif
			}
			if (minus < 0)
				n = -n;
			a1 += n;
			minus = 0;
			continue;
		}
		relerr = 0;
		if (a1 || minus)
			relerr++;
		switch (c) {
		case ' ':
		case '\t':
			continue;

		case '+':
			minus += brcount;
			if (a1 == 0)
				a1 = dot;
#ifdef LOG
			if (!globp)
				++logstats.la_plus;
#endif
			continue;

		case '-':
		case '^':	/* for upwards compatibility */
			minus -= brcount;
			if (a1 == 0)
				a1 = dot;
#ifdef LOG
			if (!globp)
				if (c == '^')
					++logstats.la_caret;
				else
					++logstats.la_minus;
#endif
			continue;

	     /* search:	*/
		case '?':
			minus++;
		case '/':
			compile(c);
			if (a1 == 0)
				a1 = dot;
			if (a1 < zero)
				a1 = zero;
			if (a1 > dol)
				a1 = dol;
			start = a1;
#ifdef LOG
			if (!globp)
				if (minus)
					++logstats.la_query;
				else
					++logstats.la_slash;
#endif
			for ever {
				if (minus == 0) {
					if (++a1 > dol)
						a1 = zero;
				} else {
					if (--a1 < zero)
						a1 = dol;
				}
				if (execute(0, a1)) {
					minus = 0;
					relerr = 0;
					break;
				}
				if (a1 == start)
					errmsg(18);
			}
			break;

		case '$':
			a1 = dol;
#ifdef LOG
			if (!globp)
				++logstats.la_dol;
#endif
			break;

		case '.':
			if ((peekc = getchar()) == '.') {
				peekc = 0;
				a1 = dotdot;
#ifdef LOG
				if (!globp)
					++logstats.la_dotdot;
#endif
			} else {
				a1 = dot;
#ifdef LOG
				if (!globp)
					++logstats.la_dot;
#endif
			}
			break;

		case '\'':
			if (((c = getchar()) | 040) < 'a' ||
			    (c | 040) > 'z') {
				peekc = c;
				errmsg(19);
			}
			c |= 040;
#ifdef LOG
			if (!globp)
				++logstats.la_quote;
#endif
		casemark:
#ifdef EXTMARK
			n = 3;
			if ((peekc = getchar()) == '^') {
				n = 1;
				peekc = 0;
			} else if (peekc == '$') {
				n = 2;
				if (names2[c - 'a'] == 0)
					n = 1;
				peekc = 0;
			}
			if (n & 01)
				if ((a1=findmark(names[c-'a'],0))==0) {
					a1 = dol;
					n = 0;
				}
			if (n > 1 && names2[c - 'a']) {
				if (n == 3) {
					if (addr1 || addr2)
						errmsg(20);
					addr1 = a1;
				}
				a1 = findmark(names2[c - 'a'], dol);
				if (n == 2)
					break;
				addr2 = a1;
				return(0);
			}
#else
			a1 = findmark(names[c - 'a'], dol);
#endif
			break;

		case '=':
#ifdef LOG
			if (!globp)
				++logstats.la_equal;
#endif
			if ((peekc = getchar()) == '^')
				a1 = old_a1;
			else if (peekc == '$')
				a1 = old_a2;
			else {
				if (addr1 || addr2 || a1)
					errmsg(20);
				addr1 = old_a1;
				addr2 = old_a2;
				return(0);
			}
			peekc = 0;
			break;

		default:
			if ('A' <= c && c <= 'Z') {
				c |= 040;
#ifdef LOG
				if (!globp)
					++logstats.la_letter;
#endif
				goto casemark;
			}
			peekc = c;
			if (a1 == 0)
				if (c == ',' || c == ';')
					if (dot + 1 > dol)
						return(dol);
					else
						return(dot + 1);
				else
					return(0);
			a1 += minus;
			if (a1 < zero)
				a1 = zero + (zero != dol);
			else if (a1 > dol)
				a1 = dol;
			return(a1);
		}
		if (relerr)
			errmsg(20);
	}
}

advance(alp, aep) {
	register char *lp, *ep, *curlp;
	register s_sav, i;

	lp = alp;
	ep = aep;
	for ever switch (*ep++) {

	case CCHR:
		if (*ep++ == *lp++)
			continue;
		return(0);

	case CDOT:
		if (*lp++)
			continue;
		return(0);

	case CDOL:
		if (*lp == 0)
			continue;
		return(0);

	case CEOF:
		loc2 = lp;
		if (--s_tmp > 0)
			return(0);
		return(1);

	case CCL:
	case NCCL:
		if (cclass(ep, *lp++, ep[-1] == CCL)) {
			ep += *ep;
			continue;
		}
		return(0);

	case CBRA:
		braslist[*ep++] = lp;
		continue;

	case CKET:
		braelist[*ep++] = lp;
		continue;

	case CBACK:
		if (braelist[i = *ep++] == 0)
			errmsg(63);
		if (backref(i, lp)) {
			lp += braelist[i] - braslist[i];
			continue;
		}
		return(0);

	case CBACK | STAR:
		if (braelist[i = *ep++] == 0)
			errmsg(63);
		curlp = lp;
		while (backref(i, lp))
			lp += braelist[i] - braslist[i];
		while (lp >= curlp) {
			if (advance(lp, ep))
				return(1);
			lp -= braelist[i] - braslist[i];
		}
		continue;

	case CDOT | STAR:
		curlp = lp;
		while (*lp++);
		goto star;

	case CCHR | STAR:
		curlp = lp;
		while (*lp++ == *ep);
		ep++;
		goto star;

	case CCL | STAR:
	case NCCL | STAR:
		curlp = lp;
		while (cclass(ep, *lp++, ep[-1] == (CCL | STAR)));
		ep += *ep;
		/* goto star; */

	star:
		s_sav = s_tmp;
		do {
			if (--lp == locs)
				break;
			if (advance(lp, ep))
				return(1);
			s_tmp = s_sav;
		} while (lp > curlp);
		--s_tmp;
		return(0);

	default:
		errmsg(-26);
	}
}

linep *
append(f, a, single, bkpf)
func f;
linep *a;
{
	register linep *a1, *a2, *rdot;
	register nline, tl;

	nline = 0;
	dot = a;
	while ((*f)(single) == 0) {
		if (dol >= endcore) {
			if (sbrk(1024) == -1)
				errmsg(33);
			endcore = (int)endcore + 1024;
		}
		tl = putline();
		nline++;
		a1 = ++dol;
		a2 = a1 + 1;
		rdot = ++dot;
		while (a1 > rdot)
			*--a2 = *--a1;
		*rdot = tl;
		if (bkpf) {
			mods++;
			backchk();
		}
		if (single)
			break;
	}
	return(nline);
}

are_you_sure() {
#ifdef USE
	if (alt)
		return(1);
#endif
	if (!text_modified || fflg || immflg || zero == dol)
		return(0);
	return(yes_no(curt? "?forget" :
	    "did you forget to save your text", 1, 1, 0));
}

argnum(ap)
char **ap;
{
	register n;
	register char *p;

	p = *ap;
	n = 0;
	while ('0' <= *p && *p <= '9')
		n = n * 10 + *p++ - '0';
	*ap = --p;
	return(n);
}

backchk() {
	if (modcount == 0)
		return;
	if (mods >= modcount) {
		mods = 0;
#ifdef EOL
		if (backup(TMP) && prompt2 && prompt3)
#endif
#ifndef EOL
		if (backup(TMP) && prompt2)
#endif
			if (!curt)
				putsn(errtext[56]);
	}
}

backref(an, alp)
char *alp;
{
	register n;
	register char *bp, *lp;

	n = an;
	bp = braslist[n];
	lp = alp;
	while (*bp++ == *lp++)
		if (bp >= braelist[n])
			return(1);
	return(0);
}

backup(af) {
	register char *p1, *p2, *t2;
	register linep *a1, *a2;
	register func savint, savhup;

	if (io) {
		putsn("******** backup: I/O in progress");
		return(0);
	}
	flush_buf();
	p1 = savedfile;
	t2 = p2 = file;
	while (*p2 = *p1++)
		if (*p2++ == '/')
			t2 = p2;
	if (p2 > t2 + 10)
		p2 = t2 + 10;
	if (af != FILE && p2 >= &file[FNSIZE - 6])
		errmsg(11);
	switch (af < 0? -af : af) {
		case FILE:	p1 = 0;		break;
		case TMP:	p1 = dotedt;	break;
		case INT:	p1 = dotint;	break;
		case HUP:	p1 = dothup;	break;
		case BAK:	p1 = dotbak;	break;
		case TRM:	p1 = dottrm;	break;
		default:	errmsg(-17);
	}
	if (p1)
		while (*p2++ = *p1++);
	if (af < 0) {
		if (deltflg)
			return(1);
		return(!unlink(file));
	}
	if (dol == zero && !fflg) {
		if (af == FILE)
			if (curt)
				putsn("?48");
			else
				putsn(errtext[48]);
		return(1);
	}
	if (dol == zero)
		return(1);
	if (!iflg) {
		savhup = signal(SIGHUP, 1);
		savint = signal(SIGINT, 1);
	}
	if (over && af == FILE)
		override();
	io = create(file, (af == FILE? MODE : LMODE));
	if (overfile) {
		chmod(overfile, overmode);
		overfile = 0;
	}
	if (io < 0) {
		io = 0;
		if (af != TMP) {
			if (curt)
				putsn("?54");
			else {
				puts2(errtext[54]);
				putsn(file);
			}
		}
		if (!iflg) {
			signal(SIGHUP, savhup);
			signal(SIGINT, savint);
		}
		return(0);
	}
	io_w++;
	a1 = addr1;
	a2 = addr2;
	addr1 = zero + 1;
	addr2 = dol;
	putfile();
	close(io);
	io = 0;
	io_w = 0;
	addr1 = a1;
	addr2 = a2;
	if (!iflg) {
		signal(SIGHUP, savhup);
		signal(SIGINT, savint);
	}
	return(1);
}

#ifndef CKPT
badsig(an) {
	register n;

	if (n = backup(TMP))
		putsn(errtext[56]);
	puts("  Fatal Signal: ");
	if (0 < an && an < NSTR && status[an])
		putsn(status[an]);
	else
		printf("%d\n", an);
	flush_buf();
	if (n)
		exit(1);
	error();
}
#endif

blkio(b, buf, iofcn)
func iofcn;
{
	lseek(tfile, 512L * b, 0);
	if ((*iofcn)(tfile, buf, BLKSIZE) != BLKSIZE) {
		badf++;
		errmsg(-35);
	}
}

cclass(aset, ac, af)
char *aset;
charac ac;
{
	register char *set;
	register n;
	register charac c, m;

	set = aset;
	if ((c = ac) == 0)
		return(0);
	n = *set++;
	while (--n)
		if (set[1] == '-' && n > 2) {
			c = min(set[0], set[2]);
			m = max(set[0], set[2]);
			do {
				if (c == ac)
					return(af);
			} while (++c != m);
			set += 2;
			c = ac;
		} else
			if (*set++ == c)
				return(af);
	return(!af);
}

#ifdef CKPT
checkpoint(asig) {
	extern etext;
	register filedes f;
	register char *p;
	register func savint, savqit;
	int n;

	savint = signal(SIGINT, 1);
	savqit = signal(SIGQIT, 1);
	p = &etext;	/* won't work for -n, -i, or -z */
	n = (char *)dol - p;
	n += sizeof (int);
	if ((f = create(cfname, LMODE)) < 0 ||
	    write(f, &n, sizeof n) != sizeof n) {
		n = 66;
		goto cerror;
	}
#ifdef pdp11	/* 16 bit byte count only */
	if (n < 0) {
		if (write(f, etext, 32256) != 32256) {
			n = 66;
			goto cerror;
		}
		n -= 32256;	/* 63 blocks, since 64 is < 0 */
		p += 32256;
	}
#endif
	if (write(f, p, n) != n)
		n = 66;
	else
		n = 0;
    cerror:
	close(f);
	if (n) {
		signal(SIGINT, savint);
		signal(SIGQIT, savqit);
		recovry = 0;
		errmsg(n);
	}
	if (asig) {
		puts2(status[asig]);
		if (!curt)
			puts(": Fatal error");
	}
	if (curt)
		puts2("?CKPT ");
	else {
		puts2("Editing session checkpointed to \"");
		puts2(cfname);
		puts("\".\nTo recover your work, type:");
		if (editor && *editor)
			puts2(editor);
		else
			puts2("edit");
		puts2(" -R");
	}
	puts(&tfname[tfnum]);
	exit(1);
}
#endif

chk() {
	register charac c;
	register char *p2, *p1, *t2, **p;
	register charac oldc;
	long t;
	struct stat s;

	if (*savedfile == '\0')
		return(0);
	t2 = p2 = file;
	p1 = savedfile;
	if (stat(p1, &s) >= 0)
		t = s.st_mtime;
	else
		t = 0L;
	while (*p2 = *p1++)
		if (*p2++ == '/')
			t2 = p2;
	if (p2 > t2 + 10)
		p2 = t2 + 10;
	if (p2 >= &file[FNSIZE - 6])
		return(0);
	t2 = p2;
	p = dots;
	while (p1 = *p++) {
		p2 = t2;
		while (*p2++ = *p1++);
		if (stat(file, &s) >= 0 && s.st_mtime >= t) {
			if (curt) {
				puts2("?\"");
				puts2(file);
				puts2("\"  ");
			} else {
				putsn("When you were last editing this file");
				putsn("you did not exit the editor normally,");
				puts2("leaving the file:  \"");
				puts2(file);
				if (p1 == dotedt) {
					putsn("\".\nIt contains your file up to the last \"[file saved]\"");
					putsn("message.  This file will be deleted if you do");
					putsn("not read it into the editor now.  If you read");
					putsn("it, then decide not to use it, exit the editor");
					putsn("with \"qi\".");
				} else
					putsn("\".");
			}
			return(yes_no(curt? "read" : "Do you wish to read it",
			    1, -1, 0));
		}
	}
	return(0);
}

_cleanup() {
	flush_buf();
}

#ifdef CLEAR
clear() {
	register l, i;

	l = listf;
	listf = 0;
	puts2(clears);	/* clear sequence */
	flush_buf();
	i = 5;
	while (--i >= 0)
		putchar(0);	/* ADM-3A's need padding at 19.2 */
	putchar('\n');
	listf = l;
}
#endif

commands(baseflg) {
	extern getfile(), gettty();
	register linep *a1;
	register charac c;
	register char *p;
	register r, num;

    for ever {
#ifdef AGAIN
	if (agp) {
		*agp++ = '\n';
		*agp = '\0';
	}
	agf = 0;
	agp = 0;
#endif
	immflg = 0;
#ifdef LOG
	if (logamp) {
		++logstats.lp_amp;
		logamp = 0;
	}
#endif
	if (!globp && (hupflag || termflg)) {
		if (hupflag) {
			backup(HUP);
			puts2(errtext[57]);
		} else {
			backup(TRM);
			puts2(errtext[58]);
		}
		delexit(1);
	}
	if (pflag) {
		pflag = 0;
		addr1 = addr2 = dot;
		goto print;
	}
	if (!globp) {
#ifdef USE
	    if (!alt) {
#endif
		if (modcount) {
			if (text_modified > savf)
				mods++;
			savf = text_modified;
			backchk();
		}
#ifdef EOL
#ifdef USE
		if (prompt2 && prompt3 && !eflg2)
#endif
#ifndef USE
		if (prompt2 && prompt3)
#endif
#endif
#ifndef EOL
#ifdef USE
		if (prompt2 && !eflg2)
#endif
#ifndef USE
		if (prompt2)
#endif
#endif
		{
			puts2(e_prompt);
			flush_buf();
		}
#ifdef USE
	    }
#endif
	}
	if (!globp) {
		if (dotdot > dol)
			dotdot = dol;
		if (dotdot < zero)
			dotdot = zero;
		if (dot != lastdot) {
			dotdot = lastdot;
			lastdot = dot;
		}
	}
	addr1 = 0;
	addr2 = 0;
	s_tmp = 0;
	s_cnt = 0;
	r = 1;
	do {
		addr1 = addr2;
		if ((a1 = address()) == 0) {
			c = getchar();
			break;
		}
		addr2 = a1;
		if ((c = getchar()) == ';') {
			c = ',';
			dot = a1;
		}
	} while (c == ',' && --r >= 0);
	if (addr1 == 0)
		addr1 = addr2;
	if (!globp && !baseflg) {
		if (addr1) {
			old_a1 = addr1;
			old_a2 = addr2;
		}
	}
	line_num = (addr1? addr1 : dot) - zero;
#ifdef AGAIN
	if (c == 'o' || c == ctrl('Q')) { /* again command "o" */
		if (c != ctrl('Q') && (peekc = getchar()) != '\n')
			errmsg(1);
		if (c == ctrl('Q'))
			putchar(lastc = '\n');
		if (*agbuf == 0)
			errmsg(2);
		agf++;
		agp = agbuf;
		c = *agp++;
		peekc = 0;
#ifdef LOG
		++logstats.lc_o;
#endif
	} else if (baseflg == 0 && globp == 0)
		if (c != '\n') {
			agp = agbuf;
			*agp++ = c;  /* first char not yet saved */
		}
#endif

	switch (c) {
	case 'a':
		if ((peekc = getchar()) == 'b')
			abort();
		setdot();
#ifdef XED
		if (peekc != ' ' && peekc != '\n') {
			c = peekc;
			peekc = 0;
			if (tack(c, 1))
				text_modified++;
#ifdef LOG
			++logstats.lc_aslash;
#endif
			continue;
		}
#endif
		line_num++;
		num = addr2;
#ifdef LOG
		++logstats.lc_append;
#endif
	caseadd:
		if ((c = getchar()) == ' ') {
			r = 1;
#ifdef LOG
			++logstats.lc_aspace;
#endif
		} else {
#ifndef XED
			if (c != '\n') {
				peekc = c;
				newline();
			}
#endif
			r = 0;
		}
		if (append(gettty, num, r, 1))
			text_modified++;
		continue;

	case 'b':
		setnoaddr();
		white_space();
		if ((brcount = setnum(1)) <= 0)
			brcount = 1;
#ifdef LOG
		++logstats.lc_browse;
#endif
		continue;

	case 'c':
		if ((peekc = getchar()) == 'o') {  /* co == t */
			peekc = 0;
#ifdef LOG
			++logstats.lc_copy;
#endif
			goto casecopy;
		}
		if (peekc != '\n')
			goto casesub;
		newline();
		setdot();
		nonzero();
		delete();
		text_modified++;
#ifdef LOG
		++logstats.lc_change;
#endif
		append(gettty, addr1 - 1, 0, 0);
		continue;

	case 'd':
#ifdef DEBUG
/*		*du	Dump command (testing only)	*/
		if ((peekc = getchar()) == 'u') {
			peekc = 0;
			dump();
			continue;
		}
#endif
		if ((peekc = getchar()) == ' ' || peekc == ',') {
			peekc = 0;
			white_space();
			p = linebuf;
			if ((c = getchar()) == '\n')
				errmsg(51);
			do {
				*p++ = c;
#ifndef ALLOC
				if (p >= &linebuf[LBSIZE - 2])
#else
				if (p >= &linebuf[lbsize - 2])
#endif
					errmsg(11);
			} while ((c = getchar()) >= 0 && c != '\n');
			*p = 0;
#ifdef LOG
			++logstats.lc_directory;
#endif
			if (chdir(linebuf) < 0)
				errmsg(51);
			continue;
		}
#ifdef PAGE
		if (peekc == '=') {	/* d=<depth> */
			peekc = 0;
			setnoaddr();
			pcount = setnum(PAGSIZ);
#ifdef LOG
			++logstats.lc_depth;
#endif
			continue;
		}
#endif
		newline();
		setdot();
		nonzero();
		delete();
		text_modified++;
#ifdef LOG
		++logstats.lc_delete;
#endif
		continue;

	case 'e':
	    eagain:
		if ((peekc = getchar()) != '\n') {
#ifdef EOL
			if (peekc == '=') {  /* e=c - set eol to 'c' */
				peekc = 0;
				if (immflg)
					errmsg(8);
				setnoaddr();
				eol = setchar(0);
#ifdef LOG
				++logstats.lc_eol;
#endif
				continue;
			}
#endif
#ifdef TABS
			if (peekc == 'x') {
				peekc = 0;
				if (immflg)
					errmsg(8);
				if ((c = getchar()) != 'p')
					errmsg(8);
				newline();
				if (!tabc)
					errmsg(3);
				if (maxtab < 0)
					errmsg(9);
				if (exp())
					text_modified++;
#ifdef LOG
				++logstats.lc_exp;
#endif
				continue;
			}
#endif
			if ('0' <= peekc && peekc <= '9') {
				c = getnum();
				newline();
				if (0 <= c && c < NERR)
					printf("%3d: %s\n",
					    c, errtext[c]);
#ifdef LOG
				++logstats.lc_errmsg;
#endif
				continue;
			}
			if (peekc == '+' || peekc == '-') {
				c = peekc;
				peekc = 0;
				newline();
				curt = c == '-';
#ifdef LOG
				if (curt)
					++logstats.lc_eminus;
				else
					++logstats.lc_eplus;
#endif
				continue;
			}
			if (peekc == 'i') {
				peekc = 0;
				if (immflg)
					errmsg(8);
				immflg++;
				goto eagain;
			}
			setnoaddr();
			if (fflg)
				errmsg(4);
			if (peekc != ' ' && peekc != ',')
		illfnm:		errmsg(5);
			scopy(savedfile, tempfile);
			if (zero == dol || text_modified == 0)
				backup(-TMP);
			savedfile[0] = 0;
			filename();
			if (text_modified && are_you_sure()) {
				scopy(tempfile, savedfile);
				error();
			}
			peekc = '\n';
		} else {
			setnoaddr();
			if (text_modified) {
				r = peekc;
				peekc = 0;
				if (are_you_sure()) {
					peekc = r;
					error();
				}
				peekc = r;
			}
			if (zero == dol || text_modified == 0)
				backup(-TMP);
		}
		if (init())
			continue;
#ifdef LOG
		++logstats.lc_edit;
#endif
		goto caseread;

	case 'f':
		setnoaddr();
#ifdef TABS
		if ((peekc = getchar()) == '=') {  /* f=c fill char */
			peekc = 0;
			tabfill = setchar(TABFILL);
#ifdef LOG
			++logstats.lc_fillset;
#endif
			continue;
		}
#endif
		if ((c = getchar()) != '\n') {
			if (fflg)
				errmsg(4);
			peekc = c;
			filename();
			scopy(file, savedfile);
#ifdef LOG
			++logstats.lc_fset;
#endif
			if (prompt2 == 0)
				continue;
		}
#ifdef LOG
		  else
			++logstats.lc_fshow;
#endif
		putsn(savedfile);
		continue;

	case 'g':
		global(1);
		continue;

	case 'h':
#ifdef HELP
		if ((peekc = getchar()) == 'e') {  /* he[lp] */
			peekc = 0;
			setnoaddr();
			skip_rest();
#ifdef LOG
			++logstats.lc_help;
#endif
			if ((doc = open(help, 0)) > 0) {
				while ((c = read(doc, linebuf,
#ifndef ALLOC
				    LBSIZE)) > 0)
#else
				    lbsize)) > 0)
#endif
					write(1, linebuf, c);
				close(doc);
			}
			doc = 0;
			continue;
		}
#endif
		if (zero != dol) {
			setdot();
			nonzero();
		}
#ifdef LOG
		++logstats.lc_header;
#endif
		header();
		continue;

	case 'i':
		setdot();
#ifdef XED
		if ((peekc = getchar()) != ' ' && peekc != '\n') {
			c = peekc;
			peekc = 0;
			if (tack(c, 0))
				text_modified++;
#ifdef LOG
			++logstats.lc_islash;
#endif
			continue;
		}
#endif
		nonzero();
		num = addr2 - 1;
#ifdef LOG
		++logstats.lc_insert;
#endif
		goto caseadd;

#ifdef XED
	case 'j':
		setdot();
		nonzero();
		join();
		text_modified++;
		continue;
#endif

	case 'k':
		if ((c = getchar()) == '\n') {
			setnoaddr();
#ifdef LOG
			++logstats.lc_klist;
#endif
			printmarks();
			continue;
		}
		if ('A' <= c && c <= 'Z')
			c |= 040;
		if (c < 'a' || c > 'z')
			errmsg(0);
		newline();
		setdot();
		nonzero();
#ifdef HUGE
		r = hugef ^ 01;
#else
#define r	1
#endif
#ifdef EXTMARK
		if (addr1 != addr2) {
			names[c - 'a'] = *addr1 | r;
			names2[c - 'a'] = *addr2 | r;
		} else {
			names[c - 'a'] = *addr2 | r;
			names2[c - 'a'] = 0;
		}
#else
		names[c - 'a'] = *addr2 | r;
#endif
#ifdef LOG
		++logstats.lc_kset;
#endif
		continue;
#ifndef HUGE
#undef  r
#endif

	case 'm':
#ifdef DUMB
		if ((peekc = getchar()) == '\n') {
			setnoaddr();
			peekc = 0;
			dumbf ^= 01;
#ifdef LOG
			++logstats.lc_magic;
#endif
			if (curt)
				putsn(dumbf? off : on);
			else {
				puts2("\"$&[^.*\\(\\)\" have ");
				if (dumbf)
					puts2(no);
				putsn("special meaning");
			}
			continue;
		}
#endif
		if ((peekc = getchar()) == 'o') {  /* mo == m */
			peekc = 0;
#ifdef LOG
			++logstats.lc_moove;
#endif
		}
#ifdef LOG
		  else
			++logstats.lc_move;
#endif
		move(0);
		text_modified++;
		continue;

	case 'n':
		setnoaddr();
#ifdef PIPE
		if ((peekc = getchar()) == '+') {
			peekc = 0;
			newline();
			pno = 1;
#ifdef LOG
			++logstats.lc_numplus;
#endif
			continue;
		}
		if (peekc == '-') {
			peekc = 0;
			newline();
			pno = -1;
#ifdef LOG
			++logstats.lc_numinus;
#endif
			continue;
		}
#endif
		newline();
		prompt1 ^= 01;
#ifdef LOG
		++logstats.lc_numbers;
#endif
		if (curt)
			putsn(prompt1? on : off);
		else {
			if (prompt1 == 0)
				puts2(no);
			putsn("line numbers");
		}
		continue;

	case '\n':
		if (globp || addr2 > dol)
			continue;
		if (addr2 == 0) {
			addr1 = addr2 = dot + 1;
			if (addr2 <= dol)
				line_num++;
			if (brcount != 1) {
				addr2 = dot + brcount;
				if (addr1 > dol)
					continue;
				if (addr2 > dol)
					addr2 = dol;
				if (addr2 < zero)
					addr2 = zero;
#ifdef CLEAR
				if (zflg && addr2 - addr1 > pcount / 2)
					clear();
#endif
			}
		}
		if (addr2 <= dol) {
			pflag = 0;
			goto print;
		}
		continue;

	case 'l':
		listf++;
#ifdef LOG
		++logstats.lc_list;
#endif
	case 'p':
		if ((peekc = getchar()) == 'a') {
			peekc = 0;
	case ':':
	case '*':
			num = 0;
			if (c == ':' || c == '*') {
				if ((peekc = getchar()) == ' ' ||
				    peekc == '\t') {
					skip_rest();	/* comments */
#ifdef LOG
					++logstats.lc_comment;
#endif
					continue;
				}
				r = peekc;
				peekc = 0;
#ifdef LOG
				if (r == '-' || r == '+')
					++logstats.lc_clnminus;
				else if (c == '*')
					++logstats.lc_star;
				else
					++logstats.lc_colon;
#endif
				while (r == '-' || r == '^' || r == '+') {
					if (r == '+')
						++num;
					else
						--num;
					r = getchar();
				}
				peekc = r;
			}
#ifdef LOG
			  else
				if (c != 'p')
					++logstats.lc_print;
#endif
			newline();
			pflag = 0;
			if (addr1 == addr2) {
				if (num == -1 && c == ':') {
					if (addr2 == 0)
						addr2 = dot;
					addr1 = addr2 - pcount;
					if (addr1 <= zero)
						addr1 = zero + 1;
#ifdef CLEAR
					if (zflg)
						clear();
#endif
					goto print;
				}
				num *= pcount;
				if (c == '*')
					num -= (pcount + 1) / 2;
				if (addr1 == 0)
					a1 = dot + (num? num : 1);
				else
					a1 = addr1 + num;
				if (a1 <= zero)
					a1 = zero + 1;
				addr1 = addr2 = a1;
			}
			nonzero();
			if (addr1 == addr2 || addr2 > dol ||
			    addr2 <= zero)
				addr2 = dol;
			setdot();
#ifdef CLEAR
			if (zflg && addr2 - addr1 > pcount / 2)
				clear();
#endif
#ifndef PAGE
			if (addr2 > addr1 + pcount)
				addr2 = addr1 + pcount;
			goto print;
#else
			page();
			listf = 0;
#ifdef PARENS
			parenf = 0;
#endif
#ifdef STRLEN
			quotef = 0;
#endif
			continue;
#endif
		} else if (peekc == 'p' || peekc == 'l') {
			peekc = 0;
			addr1 = zero + 1;
			addr2 = dol;
#ifdef LOG
			++logstats.lc_pprint;
#endif
		}
		newline();
		pflag = 0;
    print:
		setdot();
		nonzero();
		a1 = addr1;
#ifdef PARENS
		parenc[0] = 0;
		parenc[1] = 0;
		parenc[2] = 0;
#endif
		do {
			col = 0;
			printlno(line_num = a1 - zero);
			puts(getline(*a1++));
		} while (a1 <= addr2);
		dot = addr2;
		listf = 0;
#ifdef PARENS
		parenf = 0;
#endif
#ifdef STRLEN
		quotef = 0;
#endif
		continue;

	case 'q':
		if ((peekc = getchar()) == 'i') {  /* qi - immediate */
			peekc = 0;
			newline();
			immflg++;
#ifdef LOG
			++logstats.lc_qimm;
#endif
			return;
		}
#ifdef STRLEN
		if (peekc == '=') {	/* q=cc  set quote chars */
			peekc = 0;
			if ((c = getchar()) == '\\')
				c = getchar();
			quotec = quotec2 = c;
#ifdef LOG
			++logstats.lc_quote;
#endif
			if (c != '\n') {
				if ((c = getchar()) == '\\')
					c = getchar();
				if (c == '\n')
					continue;
				quotec2 = c;
			} else {
				quotec = 0;
				quotec2 = 0;
				continue;
			}
			if (c != '\n')
				newline();
			continue;
		}
#endif
		setnoaddr();
		if ((peekc = getchar()) != '\n')
			errmsg(25);
		peekc = 0;
#ifdef LOG
		++logstats.lc_quit;
#endif
		return;

	case 'r':
#ifdef LOG
		++logstats.lc_read;
#endif
	caseread:
		filename();
		if ((io = open(file, 0)) < 0) {
			io = 0;
			lastc = '\n';
			if (curt)
				errmsg(53);
			puts2(errtext[53]);
			putsn(file);
			error();
		}
		setall();
		ninbuf = 0;
		r = append(getfile, addr2, 0, 0);
		if (prompt2)
			printf((curt? prcntu : errtext[55]),
			    r, (r == 1? null : quote_s));
		close(io);
		io = 0;
#ifdef LOG
		logstats.lt_rlines += r;
#endif
		if (num_reads++ || fflg) {
			if (r)
				text_modified++;
		} /* else
			text_modified = 0; */
		if ((c == 'e' && bflg == 1) || bflg2 == 1) {
			bflg2 = 0;
			backup(BAK);
		}
		continue;

	case 's':
		if (!globp && (peekc = getchar()) == '\n') {  /* w;q */
			setnoaddr();
#ifdef LOG
			++logstats.lc_stop;
#endif
			if (text_modified && !fflg)
				if (backup(FILE) == 0)
					error();  /* errmsg(10) */
			peekc = text_modified = 0;
#ifdef LOG
			logstats.lt_wlines += dol - zero;
#endif
			return;
		}
		if (peekc == 'a') {  /* sa - count before auto-save */
			setnoaddr();
			peekc = 0;
			modcount = setnum(MODCNT);
			mods = 0;
#ifdef LOG
			++logstats.lc_savecount;
#endif
			continue;
		}
	casesub:
		setdot();
		nonzero();
		substitute(globp);
		text_modified++;
#ifdef LOG
		if (c == 's')
			++logstats.lc_substitute;
		else
			++logstats.lc_cslash;
#endif
		continue;

	case 't':
#ifdef TABS
		if ((peekc = getchar()) == '=') {  /* t=c tab char */
			setnoaddr();
			peekc = 0;
			tabc = setchar(0);
#ifdef LOG
			++logstats.lc_tabchar;
#endif
			continue;
		} else if (peekc == ',') {	/* t,nn  set tabs */
			setnoaddr();
#ifdef LOG
			++logstats.lc_tabset;
#endif
			while ((c = getchar()) == ',') {
				while ((c = getchar()) == ',');
				if ((c < '0' || c > '9') && c != '-')
					break;
				peekc = c;
				settab(getsnum());
			}
			peekc = c;
			newline();
			continue;
		} else if (peekc == '\n') {	/* list tabs */
			setnoaddr();
			peekc = 0;
#ifdef LOG
			++logstats.lc_tablist;
#endif
			listabs();
			continue;
		}
#endif
#ifdef LOG
		++logstats.lc_transfer;
#endif
	casecopy:
		move(1);
		text_modified++;
		continue;

#ifdef UNDO
	case 'u':
		setnoaddr();
		newline();
		undo();
#ifdef LOG
		++logstats.lc_undo;
#endif
		continue;
#endif

	case 'v':
		global(0);
		continue;

	case 'w':
#ifdef PAGE
		if ((peekc = getchar()) == '=') {  /* w=<width> */
			peekc = 0;
			ccount = setnum(CCOUNT);
#ifdef LOG
			++logstats.lc_width;
#endif
			continue;
		}
#endif
		if ((peekc = getchar()) == 'i') {	/* wi over-ride */
			++immflg;
			peekc = 0;
#ifdef LOG
			++logstats.lc_wimm;
#endif
		}
#ifdef LOG
		  else
			++logstats.lc_write;
#endif
		filename();
#ifdef LOG
		if (appflg) {
			--logstats.lc_write;
			++logstats.lc_wonto;
		}
#endif
		if (globp) {
			setdot();
			appflg++;
		} else
			setall();
		if (dol == zero) {
			if (curt)
				putsn("?48");
			else
				putsn(errtext[48]);
			if (!fflg || appflg)
				continue;
		}
		if (over || immflg)
			override();
		if (appflg)
			io = open(file, 1);
		if (!appflg || io < 0)
			io = creat(file, MODE);
		if (overfile) {
			chmod(overfile, overmode);
			overfile = 0;
		}
		if (io < 0) {
			io = 0;
			if (curt)
				errmsg(54);
			puts2(errtext[54]);
			putsn(file);
			error();
		}
		io_w++;
		if (appflg)
			lseek(io, 0L, 2);	/* append onto file */
		putfile();
		close(io);
		io = 0;
		io_w = 0;
		if (addr1 == zero + 1 && addr2 == dol)
			text_modified = 0;
#ifdef LOG
		logstats.lt_wlines += dol - zero;
#endif
		continue;

#ifdef USE
	case '@':
		setnoaddr();
		if (alt)
			errmsg(6);
		if ((peekc = getchar()) == 'p')
			peekc = 0;
		else
			eflg2++;
		if ((peekc = getchar()) == '\n' && altfile[0]) {
			peekc = 0;
			goto altname;
		}
		if ((c = getchar()) != ' ' && c != '\t' && c != ',')
			errmsg(5);
		white_space();
		if ((c = getchar()) == '\n')
			errmsg(7);
		p = altfile;
		*p++ = c;
		while ((c = getchar()) != '\n') {
			if (c < 0)
				errmsg(59);
			*p++ = c;
		}
		*p = '\0';
	altname:
#ifdef LOG
		++logstats.lc_at;
#endif
		if ((alt = open(altfile, 0)) < 0) {
			alt = 0;	/* this MUST be 0 */
			lastc = '\n';
			if (curt)
				errmsg(53);
			puts2(errtext[53]);
			putsn(altfile);
			error();
		}
		continue;
#endif

#ifdef DEBUG
	case '#':	/* toggle debug flag */
		if (addr1 != addr2 || addr1 != zero)
			goto illcmd;
		newline();
		tflg ^= 01;
		continue;

#ifdef XDEL
	case '`':
		setnoaddr();
		newline();
		if (ndeleted == 0)
			errmsg(16);
		printf("deleted = %o  ndeleted = %d\n", deleted, ndeleted);
		{ register n, *bp, nl;
		    int tl;

		    tl = deleted;
		    bp = getblock(tl, READ);
#ifdef HUGE
		    tl &= _1[hugef];
#else
		    tl &= _1;
#endif
		    nl = nleft / sizeof(linep);
		    for (n = 0; n < ndeleted; n++) {
		    	printf("%7d: %6o\n", n + 1, *bp++);
		    	if (--nl <= 0) {
#ifdef HUGE
			    bp = getblock(tl += _2[hugef], READ);
#else
			    bp = getblock(tl += _2, READ);
#endif
			    nl = nleft / sizeof(linep);
		    	}
		    }
		}
		continue;
#endif
#endif

#ifdef XDEL
	case 'x':
		newline();
		r = undelete();
#ifdef LOG
		++logstats.lc_xundelete;
#endif
		if (prompt2)
			printf((curt? prcntu : errtext[55]),
			    r, (r == 1? null : quote_s));
		text_modified++;
		continue;
#endif

#ifdef YINT
	case 'y':
		if ((c = getchar()) == '+') {
			setdot();
			nonzero();
			newline();
			if (zero == dol)
				yplus = 0;
			else
				yplus = *addr2 | 01;
			yflg = 1;
#ifdef LOG
			++logstats.lc_yplus;
#endif
		} else if (c == '-') {
			setnoaddr();
			newline();
			yflg = 0;
#ifdef LOG
			++logstats.lc_yminus;
#endif
		} else {
			setnoaddr();
			peekc = c;
			newline();
			yflg = 1;
			yplus = 0;
#ifdef LOG
			++logstats.lc_yintr;
#endif
		}
		continue;
#endif

#ifdef PIPE
	case '|':
#ifndef XED
		if (globp)		/* turkeys will be turkeys */
			errmsg(61);
#endif
		if (noshell)
			errmsg(52);
		if ((peekc = getchar()) == '+') {
			peekc = 0;
			newline();
			setnoaddr();
			strict++;
#ifdef LOG
			++logstats.lc_piplus;
#endif
			continue;
		} else if (peekc == '-') {
			peekc = 0;
			newline();
			setnoaddr();
			strict = 0;
#ifdef LOG
			++logstats.lc_piminus;
#endif
			continue;
		}
		setdot();
		shell();
		continue;
#endif

	case '!':
#ifndef XED
		if (globp)
			errmsg(61);
#endif
		if (noshell)
			errmsg(52);
		setnoaddr();
		shell();
		continue;

#ifdef CKPT
	case 'z':
		newline();
		setnoaddr();
		checkpoint(0);	/* doesn't return */
#endif

	case EOF:
#ifdef USE
		if (!baseflg && alt) {
			close(alt);
			alt = 0;
			eflg2 = 0;
			continue;
		}
#endif
		return;

	}
    illcmd:
		errmsg(8);
    }	/* nothing lasts "for ever" */
}

compile(aeof)
charac aeof;
{
	register charac eof, c;
	register char *ep, *lastep, *bracketp;
	register cclcnt;
	char bracket[NBRA];

	ep = expbuf;
	lastep = 0;
	eof = aeof;
	bracketp = bracket;
	if ((c = getchar()) == eof || c == '\n') {
		if (*ep == 0)
			errmsg(27);
		if (c == '\n')
			peekc = c;
		return;
	}
	circfl = 0;
	nbra = 0;
	if (
#ifdef DUMB
	    !dumbf &&
#endif
			c == '^') {
		c = getchar();
		circfl++;
#ifdef LOG
		++logstats.lp_caret;
#endif
	}
/*	if (c == '*') {		/* if first = *, then quote it */
/*		*ep++ = CCHR;	*/
/*		*ep++ = c;	*/
/*		c = 0;	*/
/*	}	*/
	peekc = c;
	for ever {
		if (ep >= &expbuf[ESIZE - 2 - (bracketp - bracket) * 2])
			break;
		c = getchar();
		if (c == eof || c == '\n') {
			while (bracketp > bracket) {
				*ep++ = CKET;
				*ep++ = *--bracketp;
			}
			*ep++ = CEOF;
			if (c == '\n') {
				if (prompt2)
					pflag++;
				peekc = c;
			}
			return;
		}
		if (c != '*')
			lastep = ep;
#ifdef DUMB
		if (dumbf && c >= 0)
			goto defchar;
#endif
		switch (c) {
		case '\\':
			if ((c = getchar()) == '(') {
				if (nbra >= NBRA) {
					c = 44;
					goto cerror;
				}
				*bracketp++ = nbra;
				*ep++ = CBRA;
				*ep++ = nbra++;
#ifdef LOG
				++logstats.lp_paren;
#endif
				continue;
			}
			if (c == ')') {
				if (bracketp <= bracket) {
					c = 45;
					goto cerror;
				}
				*ep++ = CKET;
				*ep++ = *--bracketp;
				continue;
			}
			if ('1' <= c && c < '1' + nbra) {
				*ep++ = CBACK;
				*ep++ = c - '1';
#ifdef LOG
				++logstats.lp_digit;
#endif
				continue;
			}
			if (c == '\n') {
				c = 46;
				goto cerror;
			}
		defchar:
		default:
			*ep++ = CCHR;
			*ep++ = c;
			continue;

		case '.':
			*ep++ = CDOT;
#ifdef LOG
			++logstats.lp_dot;
#endif
			continue;

		case '*':
			if (lastep == 0 ||
			    *lastep == CBRA || *lastep == CKET)
				goto defchar;
			*lastep |= STAR;
#ifdef LOG
			++logstats.lp_star;
#endif
			continue;

		case '$':
			if ((peekc = getchar()) != eof && peekc != '\n')
				goto defchar;
			*ep++ = CDOL;
#ifdef LOG
			++logstats.lp_dol;
#endif
			continue;

		case '[':
			*ep++ = CCL;
			*ep++ = 0;
			cclcnt = 1;
			if ((c = getchar()) == '^') {
				c = getchar();
				ep[-2] = NCCL;
#ifdef LOG
				++logstats.lp_nccl;
#endif
			}
#ifdef LOG
			  else
				++logstats.lp_ccl;
#endif
			do {
				if (c == '\\')
					c = getchar();
				if (c == '\n') {
					peekc = c;
					break;
				}
				if (c < 0) {
					c = 59;
					goto cerror;
				}
				*ep++ = c;
				cclcnt++;
				if (ep >= &expbuf[ESIZE - 2]) {
					c = 49;
					goto cerror;
				}
			} while ((c = getchar()) != ']');
			lastep[1] = cclcnt;
			continue;

		case EOF:
			c = 59;
			goto cerror;
		}
	}
	c = 42;
   cerror:
	expbuf[0] = '\0';
	nbra = 0;
	errmsg(c);
}

compsub() {
	register charac seof, c;
	register char *p;

	if ((seof = getchar()) == '\n')
		errmsg(40);
	compile(seof);
	p = rhsbuf;
	for ever {
		c = getchar();
		if (c < 0)
			errmsg(59);
		if (c == '\\')
			c = getchar() | 0200;
		if (c == '\n') {
			*p = 0;
			peekc = 0;
			if (prompt2)
				pflag++;
			return(0);
		}
		if (c == seof)
			break;
		*p++ = c;
		if (p >= &rhsbuf[LBSIZE / 2 - 2])
			errmsg(41);
	}
	*p = '\0';
	p = 0;
	if ((peekc = getchar()) == 'g') {	/* if in 'glob' */
		peekc = 0;
		p = 1;
	} else if ('0' <= peekc && peekc <= '9')
		if ((s_cnt = getnum()) < 0)
			s_cnt = 0;
	newline();
	return(p);
}

create(as, am)
char *as;
{
	register savmask;
	register func savint, savqit;
	register ret;

	if (am == LMODE) {
		savint = signal(SIGINT, 1);
		savqit = signal(SIGQIT, 1);
		savmask = umask(LMASK);
	}
	ret = creat(as, am);
	if (am == LMODE) {
		umask(savmask);
		signal(SIGINT, savint);
		signal(SIGQIT, savqit);
	}
	return(ret);
}

delete() {
	register linep *a1, *a2, *a3;

	a1 = addr1;
	a2 = addr2 + 1;
#ifdef XDEL
	if (!globp)
		saveline();
#endif
	a3 = dol;
	dol -= a2 - a1;
	do {
		*a1++ = *a2++;
	} while (a2 <= a3);
	a1 = addr1;
	if (a1 > dol)
		a1 = dol;
	dot = a1;
}

delexit(aretcode) {
#ifdef LOG
#include <sys/times.h>
	struct tms t;
#endif

	unlink(tfname);
#ifdef LOG
	if ((io = open(LOG, 1)) >= 0) {
		time(&logstats.lt_end);
		times(&t);
		logstats.lt_usercpu = t.tms_utime;
		logstats.lt_syscpu = t.tms_stime;
		logstats.lt_kidscpu = t.tms_cutime + t.tms_cstime;
		lseek(io, 0L, 2);
		write(io, &logstats, sizeof logstats);
	}
#endif
	exit(aretcode);
}

dosub() {
	register char *lp, *sp, *rp;
	register charac c;

	lp = linebuf;
	sp = genbuf;
	rp = rhsbuf;
	while (lp < loc1)
		*sp++ = *lp++;
	while (c = *rp++) {
#ifdef DUMB
		if (!dumbf)
#endif
			if (c == '&') {
#ifdef LOG
				++logamp;
#endif
				sp = place(sp, loc1, loc2);
				continue;
			} else if (c < 0 && (c &= 0177) >= '1' &&
			    c < nbra + '1') {
				c -= '1';
				sp = place(sp,braslist[c],braelist[c]);
				continue;
			}
		*sp++ = c & 0177;
#ifndef ALLOC
		if (sp >= &genbuf[LBSIZE - 2])
#else
		if (sp >= &genbuf[lbsize - 2])
#endif
			errmsg(42);
	}
	lp = loc2;
	loc2 = sp + (linebuf - genbuf);
	while (*sp++ = *lp++)
#ifndef ALLOC
		if (sp >= &genbuf[LBSIZE - 2])
#else
		if (sp >= &genbuf[lbsize - 2])
#endif
			errmsg(43);
	lp = linebuf;
	sp = genbuf;
	while (*lp++ = *sp++);
}

#ifdef DEBUG
dump() {
	register linep *i;
	register b, o;

	setdot();
	nonzero();
	newline();
	line_num = addr1 - zero;
	for (i = addr1; i <= addr2; i++) {
#ifdef HUGE
		b = (*i >> (8 - hugef)) & _3[hugef];
		o = (*i << (1 + hugef)) & _4[hugef];
#else
		b = (*i >> 8) & _3;
		o = (*i << 1) & _4;
#endif
		printlno(line_num++);
#ifdef pdp11
		printf("%6o:%7o%6d/%d\n", i, *i, b, o);
#else
		printf("%6o:%7o%6d/%d\n", i, *i&(unsigned)(unsigned short)-1, b, o);
#endif
	}
	dot = addr2;
}
#endif

echo(ch)
charac ch;
{
#ifdef AGAIN
	static charac lastchar;
#endif
#ifdef USE
	if (eflg || alt && !eflg2)
#endif
#ifndef USE
	if (eflg)
#endif
		write(2, &ch, 1);
#ifdef AGAIN
	if (!agf && agp) {	/* save current command for "again" */
		if (agp >= &agbuf[GBSIZE - 2])
			agp = agbuf[0] = 0;
		else
			*agp++ = ch;
		if (ch == '\n' && lastchar != '\\')
			agp = *agp = 0;
	}
	lastchar = ch;
#endif
	return(ch);
}

errfunc() {
	if (io) {
		close(io);
		io = 0;
		io_w = 0;
	}
	if (overfile) {
		chmod(overfile, overmode);
		overfile = 0;
	}
#ifdef HELP
	if (doc) {
		close(doc);
		doc = 0;
	}
#endif
#ifdef PIPE
	if (pfile) {
		close(pfile);
		unlink(pfname);
		pfile = 0;
	}
#endif
/*	puts("?");	*/
	if (!seekf)
		lseek(0, 0L, 2);
	pflag = 0;
	listf = 0;
#ifdef PARENS
	parenf = 0;
#endif
#ifdef STRLEN
	quotef = 0;
#endif
	if (globp) {
		lastc = '\n';
		globp = 0;
	}
	peekc = lastc;
	skip_rest();
	eflg2 = 0;
	reset();
}

errmsg(n) {
	extern errno;

	listf = 0;
#ifdef PARENS
	parenf = 0;
#endif
#ifdef STRLEN
	quotef = 0;
#endif
	col = 0;
	if (n < 0) {
		puts2("\7******** ");
		printf("%d ", errno);
		n = -n;
	}
	if (curt)
		printf("?%d\n", n);
	else
		if (0 <= n && n < NERR)
			putsn(errtext[n]);
		else
			printf("bad error number: %d\n", n);
	error();
}

execute(gf, addr)
linep *addr;
{
	register char *p1, *p2;
	register charac c;

	if (gf) {
		if (circfl)
			return(0);
		p1 = linebuf;
		p2 = genbuf;
		while (*p1++ = *p2++);
		locs = p1 = loc2;
	} else {
		if (addr == zero)
			return(0);
		p1 = getline(*addr);
		locs = 0;
	}
	p2 = expbuf;
	c = NBRA;
	while (--c >= 0) {
		braslist[c] = 0;
		braelist[c] = 0;
	}
	if (circfl) {
		loc1 = p1;
		return(advance(p1, p2));
	}
	/* fast check for first character */
	if (*p2 == CCHR) {
		c = p2[1];
		do {
			if (*p1 != c)
				continue;
			if (advance(p1, p2)) {
				loc1 = p1;
				return(1);
			}
		} while (*p1++);
		return(0);
	}
	/* regular algorithm */
	do {
		if (advance(p1, p2)) {
			loc1 = p1;
			return(1);
		}
	} while (*p1++);
	return(0);
}

#ifdef TABS
exp() {
	register n;
	register linep p, *a1;

	setdot();
	nonzero();
	n = 0;
	for (a1 = addr1; a1 <= addr2; a1++) {
		getline(*a1);
		if (expand()) {
			n++;
			p = *a1;
			*a1 = putline();
			savemark(p, *a1);
		}
	}
	dot = addr2;
	return(n);
}

expand() {
	register char *p2;
	register charac c;
	register n;
	register char *p1;
	register cnt, i;
	register flag tabflg;

	p1 = linebuf;
	p2 = genbuf;
	while (*p2++ = *p1++);
	p2 = linebuf;
	p1 = genbuf;
	cnt = col = n = 0;
	while (c = *p1++) {
		if (c == tabc && col < maxtab) {
			n = col;
			c = tabfill;
			if (c == '\t') {
				n = col;
				tabflg = 0;
				while (n < maxtab) {
					if ((++n & 07) == 0) {
						*p2++ = c;
						tabflg++;
						if (p2 >=
#ifndef ALLOC
						    &linebuf[LBSIZE - 2]
#else
						    &linebuf[lbsize - 2]
#endif
						    || n >= TABS * BPW)
							goto experr;
					}
					if (tabs[n >> BPWC] >> (n & BPWM) & 01)
						if (*p1 == tabc &&
						    n < maxtab) {
							p1++;
							cnt++;
						} else
							break;
				}
				i = n;
				if (tabflg)
					n &= 07;
				else
					n -= col;
				col = i;
				while (n--) {
					*p2++ = ' ';
#ifndef ALLOC
					if (p2 >= &linebuf[LBSIZE - 2])
#else
					if (p2 >= &linebuf[lbsize - 2])
#endif
						goto experr;
				}
				cnt++;
				continue;
			}
			do {
				*p2++ = c;
#ifndef ALLOC
				if (p2 >= &linebuf[LBSIZE - 2]
#else
				if (p2 >= &linebuf[lbsize - 2]
#endif
				    || n >= TABS * BPW)
					goto experr;
				n++;
			} while (!(tabs[n >> BPWC] >> (n & BPWM) & 01));
			col = n;
			cnt++;
			continue;
		} else if ('\0' < c && c < ' ') {
			switch (c) {
			case '\b':
				col -= 2;
				break;
			case '\t':
				col += 7 - (col & 07);
				break;
			case '\r':
				col = -1;
				break;
			default:
				col--;
			}
		}
		if (c) {
			*p2++ = c;
			col++;
#ifndef ALLOC
			if (p2 >= &linebuf[LBSIZE - 2] ||
#else
			if (p2 >= &linebuf[lbsize - 2] ||
#endif
			    col >= TABS * BPW)
	experr:			errmsg(12);
		}
	}
	*p2++ = 0;
	return(cnt);
}
#endif

#ifdef DEBUG
#ifdef EXPDMP
expdmp() {
	register n;
	register char *ep, **p;
	register flag star;

	signal(SIGQIT, expdmp);
	ep = expbuf;
	putchar('"');
	if (circfl)
		putchar('^');
	while (*ep) {
		n = 0;
		star = 0;
		switch (*ep++) {
		case CCHR | STAR:
			star++;
		case CCHR:
			putchar(*ep++);
			break;
		case CDOT | STAR:
			star++;
		case CDOT:
			putchar('.');
			break;
		case CDOL:
			putchar('$');
			break;
		case CEOF:
			putchar('"');
			goto done;
		case NCCL | STAR:
			star++;
		case NCCL:
			n++;
			goto ccl;
		case CCL | STAR:
			star++;
		case CCL: ccl:
			putchar('[');
			if (n)
				putchar('^');
			n = *ep++;
			while (--n)
				putchar(*ep++);
			putchar(']');
			break;
		case CBRA:
			putchar('\\');
			putchar('(');
			ep++;
			break;
		case CKET:
			putchar('\\');
			putchar(')');
			ep++;
			break;
		case CBACK | STAR:
			star++;
		case CBACK:
			putchar('\\');
			putchar(*ep++ + '1');
			break;
		default:
			putchar('?');
			break;
		}
		if (star)
			putchar('*');
	}
done:	putchar('\n');
	if (reading)
		reset();
}
#endif
#endif

filename() {
	register char *p1, *p2;
	register charac c;

	appflg = 0;
	c = getchar();
	if (c < 0)
		errmsg(59);
	if (c == '\n') {
    noname:
		if (savedfile[0] == 0)
			errmsg(62);
		scopy(savedfile, file);
		return;
	}
	if (c != ' ' && c != '\t' && c != ',' && c != '>')
		errmsg(5);
	if (c != ',')
		peekc = c;
	white_space();
	if ((c = getchar()) == '>') {
		while ((c = getchar()) == '>');
		appflg++;
		if (c == '\n')
			goto noname;
		peekc = c;
		white_space();
		c = getchar();
	}
	if (c == '\n')
		errmsg(7);
	p1 = file;
	do {
		*p1++ = c;
		if (p1 >= &file[FNSIZE - 2])
			errmsg(11);
	} while ((c = getchar()) != '\n');
	*p1++ = 0;
	if (savedfile[0] == 0)
		scopy(file, savedfile);
}

linep *
findmark(alp, adflt)
linep alp, *adflt;
{
	register linep *a, v;
#ifdef HUGE
	register i;

	i = hugef ^ 01;
#endif
	v = alp;
	for (a = zero + 1; a <= dol; a++)
		if (v == (*a |
#ifdef HUGE
				i
#else
				1
#endif
				))
			return(a);
	return(adflt);
}

flush_buf() {
	register n;

	if (n = linp - line) {
		linp = line;
		write(fout, line, n);
	}
}

#ifdef G_VFY
gask(a1)
linep *a1;
{
	register charac c;

	col = 0;
	printlno(line_num = a1 - zero);
	puts(linebuf);
	puts2("Ok? ");
	flush_buf();
	if ((c = getchar()) < 0) {
		putchar('\n');
		return(-1);
	}
	if (c == '\n')
		return(1);
	skip_rest();
	return(c != 'n');
}
#endif

char *
getblock(atl, iof) {
	extern read(), write();
	register bno, off;
	register linep *a;
#ifdef HUGE
	register flag c;
	register func savint;

	bno = (atl >> (8 - hugef)) & _3[hugef];
	off = (atl << (1 + hugef)) & _4[hugef];
#else
	bno = (atl >> 8) & _3;
	off = (atl << 1) & _4;
#endif
	if (bno >=
#ifdef HUGE
		   _5[hugef]
#else
		   _5
#endif
			    ) {
#ifdef HUGE
		if (!hugef && !globp) {	/* let's try converting to huge */
			if (!curt) {
				putsn("File too large for normal editing.");
				puts2("Conversion to \"huge\" mode disallows ");
				puts2("use of the global command.");
			}
			c = yes_no(curt? "?huge" : "Do you wish to convert",
			    1, 0, 0);
			if (c) {
				savint = signal(SIGINT, 1);
				for (a = zero + 1; a <= dol; a++)
					*a = ((unsigned)*a) >> 1;
				hugef++;
				hugef2++;	/* conversion occurred */
				atl = (atl >> 1) & _6[hugef];
#ifdef XDEL
				ndeleted = 0;	/* useless pointers */
				deleted = 0;
#endif
				signal(SIGINT, savint);
				goto huger;
			}
		}
#endif
		errmsg(34);
	}
#ifdef HUGE
    huger:
#endif
	nleft = BLKSIZE - off;
	if (bno == iblock && !badf) {
		ichanged |= iof;
		return(ibuff + off);
	}
	if (bno == oblock)
		return(obuff + off);
	if (iof == READ) {
		if (ichanged) {
			blkio(iblock, ibuff, write);
			ichanged = 0;
		}
		iblock = bno;
		blkio(bno, ibuff, read);
		return(ibuff + off);
	}
	if (oblock >= 0)
		blkio(oblock, obuff, write);
	oblock = bno;
	return(obuff + off);
}

charac
getchar() {
	flush_buf();
	eof = 0;
	if (lastc = peekc) {
		peekc = 0;
		return(lastc);
	}
	if (globp) {
		if (lastc = *globp++) {
			if (globf2 && *globp == 0)
				globp = globf2 = 0;
			return(lastc);
		}
		globp = 0;
		return(EOF);
	}
#ifdef AGAIN
	if (agf
#ifdef USE
		&& !alt
#endif
			) {	/* "again" stuff */
		if (lastc = *agp++)
			return(lastc);
		agf = agp = 0;
	}
#endif
	reading++;
#ifdef USE
	if (read(alt, &lastc, 1) <= 0) {
#endif
#ifndef USE
	if (read(0, &lastc, 1) <= 0) {
#endif
		reading = 0;
		eof++;
		return(lastc = EOF);
	}
	reading = 0;
	lastc &= 0177;
#ifdef APLMAP
	if (aplmap && lastc > ' ')
		lastc = map_ascii[lastc - (' ' + 1)];
#endif
#ifdef EOL
	if (lastc == '\n')
		prompt3 = 1;
	else if (eol && lastc == eol) {
		lastc = '\n';
		prompt3 = 0;
	}
#endif
#ifdef CMDS
	if (cmd)
		write(cmd, &lastc, 1);
#endif
	eof = 0;
	return(echo(lastc));
}

getcopy() {
	if (addr1 > addr2)
		return(EOF);
	getline(*addr1++);
	return(0);
}

getfile() {
	register charac c;
	register char *lp, *fp;

	lp = linebuf;
	fp = nextip;
	do {
		if (--ninbuf < 0) {
#ifndef ALLOC
			if ((ninbuf = read(io, genbuf, LBSIZE) - 1) < 0)
#else
			if ((ninbuf = read(io, genbuf, lbsize) - 1) < 0)
#endif
				if (lp == linebuf)
					return(EOF);
				else {
					lp++;
					break;
				}
			fp = genbuf;
		}
#ifndef ALLOC
		if (lp >= &linebuf[LBSIZE - 2] && (*fp & 0177) != '\n') {
#else
		if (lp >= &linebuf[lbsize - 2] && (*fp & 0177) != '\n') {
#endif
			printf((curt? "?long%u\n" : "line %u in file too long\n"),
			    dot - zero + 1);
			flush_buf();
			lp++;
			ninbuf++;
			break;
		}
		if ((*lp++ = c = *fp++ & 0177) == 0) {
			lp--;
			continue;
		}
	} while (c != '\n');
	*--lp = 0;
	nextip = fp;
	return(0);
}

getline(tl) {
	register char *bp, *lp;
	register nl;

#ifdef DEBUG
	if (tflg)
		printf("getline:\t%o\n", tl);
#endif
	lp = linebuf;
	bp = getblock(tl, READ);
#ifdef HUGE
	if (hugef2) {
		hugef2 = 0;
		tl = (tl >> 1) & _6[hugef];
	}
	tl &= _1[hugef];
#else
	tl &= _1;
#endif
	nl = nleft;
	while (*lp++ = *bp++)
		if (--nl <= 0) {
#ifdef HUGE
			bp = getblock(tl += _2[hugef], READ);
#else
			bp = getblock(tl += _2, READ);
#endif
			nl = nleft;
		}
	return(linebuf);
}

getnum() {
	register n;
	register charac c;

	n = 0;
	while ('0' <= (c = getchar()) && c <= '9')
		n = n * 10 + c - '0';
	peekc = c;
	return(n);
}

getsnum() {
	register sign;

	if (sign = (peekc = getchar()) == '-')
		peekc = 0;
	return(sign? -getnum() : getnum());
}

getsub() {
	register char *p1, *p2;

	p1 = linebuf;
	if ((p2 = linebp) == 0)
		return(EOF);
	while (*p1++ = *p2++);
	linebp = 0;
	return(0);
}

gettty(single) {
	register charac c;
	register char *p, *gf;
#ifdef TABS
	int tabf;

	tabf = 0;
#endif
	p = linebuf;
	gf = globp;
#ifdef EOL
	if (prompt2 && prompt3 && !single) {
#endif
#ifndef EOL
	if (prompt2 && !single) {
#endif
		printlno(line_num);
		flush_buf();
	}
	line_num++;
	while ((c = getchar()) != '\n') {
		if (c < 0) {
			if (gf)
				peekc = c;
			else if (prompt2 && (prompt1 || !zflg))
				putchar('\n');
			if (p > linebuf)
				break;
			return(c);
		}
		if ((c &= 0177) == 0)
			continue;
#ifdef TABS
		if (tabc && c == tabc)
			tabf++;
#endif
		*p++ = c;
#ifndef ALLOC
		if (p >= &linebuf[LBSIZE - 2])
#else
		if (p >= &linebuf[lbsize - 2])
#endif
			errmsg(30);
	}
	*p++ = 0;
#ifdef TABS
	if (tabf)
		expand();
#endif
	if (!single && linebuf[0] == '.' && linebuf[1] == 0)
		return(EOF);
	return(0);
}

global(k) {
	register char *gp;
	register charac c;
	register linep *a1;
	register flag globpf;
	char globuf[GBSIZE];

#ifdef HUGE
	if (hugef)
		errmsg(10);
#endif
	if (globp)
		errmsg(37);
	setall();
	nonzero();
	if ((c = getchar()) == '\n')
		peekc = c;
	compile(c);
#ifdef G_VFY
	gaskf = 0;
	if ((peekc = getchar()) == 'v') {
		gaskf++;
		peekc = 0;
	}
#endif
	globpf = pflag;
	if (peekc == '\n')
		globpf = 0;
	pflag = 0;
	gp = globuf;
	if ((peekc = getchar()) < 0)
		errmsg(59);
	if (peekc == '\n') {
		*gp++ = 'p';
		peekc = 0;
	} else
		while ((c = getchar()) != '\n') {
			if (c == '\\') {
				c = getchar();
				if (c != '\n')
					*gp++ = '\\';
			}
			if (c < 0)
				errmsg(59);
			*gp++ = c;
			if (gp >= &globuf[GBSIZE - 2])
				errmsg(38);
		}
	*gp++ = '\n';
	*gp = 0;
	c = 0;
#ifdef LOG
#ifdef G_VFY
	if (gaskf)
		++logstats.lc_gvfy;
#endif
	if (k)
		++logstats.lc_global;
	else
		++logstats.lc_vglobal;
#endif
	for (a1 = zero + 1; a1 <= dol; a1++) {
		*a1 &= ~01;
		s_tmp = 0;
		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
#ifdef G_VFY
			if (!gaskf || (c = gask(a1)))
				if (c < 0)
					addr2 = a1;
				else
#endif
					*a1 |= 01;
	}
	for (a1 = zero + 1; a1 <= dol; a1++)
		if (*a1 & 01) {
			*a1 &= ~01;
			dot = a1;
			globp = globuf;
			pflag = globpf;
			commands(1);
			a1 = zero;
		}
}

hangup() {
	signal(SIGHUP, 1);
	if (reading) {
		backup(HUP);
		if (fout != 1) {
			flush_buf();
			fout = 1;
		}
		puts2(errtext[57]);
		delexit(1);
	}
	hupflag++;
}

header() {
	register colnum, number;
	register flag lf;

	number = 0;
	if ((peekc = getchar()) != '\n') {
		white_space();
		number = getnum();
	}
	if (!number)
		number = ccount - (prompt1? 8 : 0);
	newline();
	if (zero != dol)
		dot = addr2;
	lf = listf;
	listf = 0;
	if (prompt1)
		putchar('\t');
	for (colnum = 0; colnum < number / 10; colnum++)
		printf("%10d", colnum + 1);
	putchar('\n');
	if (prompt1)
		putchar('\t');
	for (colnum = 1; colnum <= number; colnum++)
#ifdef TABS
		if (colnum < (TABS << BPWC) &&
		    (tabs[(colnum - 1) >> BPWC] >>
		    ((colnum - 1) & BPWM) & 01))
			putchar('-');
		else
#endif
			putchar(colnum % 10 + '0');
	putchar('\n');
	listf = lf;
}

init() {
	register n;
	register char *p;

	if (tfile > 0)
		close(tfile);
	if (io) {
		close(io);
		io = 0;
		io_w = 0;
	}
#ifdef HELP
	if (doc) {
		close(doc);
		doc = 0;
	}
#endif
#ifdef USE
	if (alt) {
		close(alt);
		alt = 0;
		eflg2 = 0;
	}
#endif
#ifdef PIPE
	if (pfile) {
		close(pfile);
		unlink(pfname);
		pfile = 0;
	}
#endif
	tline = 0;
#ifdef XDEL
	deleted = 0;
	ndeleted = 0;
#endif
	num_reads = 0;
	text_modified = 0;
#ifdef YINT
	yplus = 0;
#endif
#ifdef UNDO
	undo_oldp = 0;
	undo_newp = 0;
#endif
#ifdef V7
	if (overfile) {
		chmod(overfile, overmode);
		overfile = 0;
	}
#endif
	iblock = oblock = -1;
	badf = 0;
	ichanged = 0;
	if ((n = create(tfname, LMODE)) < 0) {
		putsn(errtext[50]);
		exit(1);
	}
	close(n);
	if ((tfile = open(tfname, 2)) < 0) {
		putsn(errtext[36]);
		exit(1);
	}
	addr1 = addr2 = dot = dotdot = lastdot = zero = dol = fendcore;
	endcore = fendcore - 2;
	brk(fendcore);
	n = 26;
	while (--n >= 0) {	/* kill marks */
		names[n] = 0;
#ifdef EXTMARK
		names2[n] = 0;
#endif
	}
	p = globp;
	globp = 0;
	if (chk()) {
		if ((io = open(file, 0)) < 0) {
			io = 0;
			lastc = '\n';
			if (curt)
				putsn("?53");
			else {
				puts2(errtext[53]);
				putsn(file);
			}
			flush_buf();
		} else {
			n = append(getfile, addr1, 0, 0);
			if (prompt2)
				printf((curt? prcntu : errtext[55]),
				    n, (n == 1? null : quote_s));
			if (n) {
				num_reads++;
				text_modified++;
			}
			if (io) {
				close(io);
				io = 0;
				io_w = 0;
			}
		}
		return(1);
	}
	globp = p;
	return(0);
}

istty(fd) {
	register r;
	short buf[3];	/* naughty int's */

	buf[2] = BS1;
	r = 0;
	if (gtty(fd, buf) >= 0)
		++r;
#ifdef CLEAR
	zflg = (buf[2] & BS1) == 0;
#endif
	if (pipef
#ifdef V7
		  || getenv("_NO_STDIO_BUF")
#endif
					    )
		++r;
	return(r);
}

#ifdef XED
join() {
	register linep *a1;
	register char *p1, *p2;
	register charac c, ceof;

	setdot();
	nonzero();
	if (addr1 == addr2)
		--addr1;
	if (addr1 <= zero)
		errmsg(60);

	p2 = rhsbuf;
	if ((c = peekc = getchar()) < 0)
		errmsg(59);
	ceof = 0;
	if (peekc != '\n' && peekc != 'p' && peekc != 'l'
#ifdef PARENS
	    && peekc != 'b'
#endif
#ifdef STRLEN
			    && peekc != 'q'
#endif
					   ) {
		ceof = peekc;
		peekc = 0;
		while ((c = getchar()) != ceof && c != '\n') {
			if (c < 0)
				errmsg(59);
			if (c == '\\')
				if ((c = getchar()) == '\n')
					errmsg(46);
			*p2++ = c;
			if (p2 >= &rhsbuf[LBSIZE / 2 - 2])
				errmsg(42);
		}
		if (c != '\n')
			c = '\0';
		else
			if (prompt2)
				pflag++;
		if (p2 != rhsbuf)
			*p2 = '\0';
		if (*rhsbuf == 0)
			errmsg(27);
#ifdef LOG
		++logstats.lc_jglue;
#endif
	}
#ifdef LOG
	  else
		++logstats.lc_join;
#endif
	peekc = c;
	newline();

	p1 = rhsbuf;
	while (*p1)
		if (*p1++ == '\n')
			errmsg(46);

	p2 = genbuf;
	a1 = addr1;

	while (a1 <= addr2) {
		p1 = getline(*a1++);
		while (*p2++ = *p1++)
#ifndef ALLOC
			if (p2 >= &genbuf[LBSIZE - 2])
#else
			if (p2 >= &genbuf[lbsize - 2])
#endif
				errmsg(12);
		--p2;
		if (ceof && a1 <= addr2) {
			p1 = rhsbuf;
			while (*p2++ = *p1++)
#ifndef ALLOC
				if (p2 >= &genbuf[LBSIZE - 2])
#else
				if (p2 >= &genbuf[lbsize - 2])
#endif
					errmsg(12);
			--p2;
		}
	}
	*p2 = '\0';

	p1 = genbuf;
	p2 = linebuf;
	while (*p2++ = *p1++);

	a1 = putline();
	savemark(*addr1, a1);
	*addr1++ = a1;
	delete();
	dot = --addr1;
	if (dot > dol)
		dot = dol;
}
#endif

#ifdef TABS
listabs() {
	register n;

	if (maxtab < 0)
		errmsg(9);
	n = next_tab(-1);
	printf("tabs: %d", n + 1);
	while ((n = next_tab(n)) >= 0)
		printf(",%d", n + 1);
	putchar('\n');
}
#endif

mail() {
	delexit(1);
}

move(cflag) {
	extern getcopy();
	register linep *adt, *ad1, *ad2;

	setdot();
	nonzero();
	if ((adt = address()) == 0)
		errmsg(31);
	ad1 = addr1;
	ad2 = addr2;
	newline();
	if (cflag) {
		ad1 = dol;
		append(getcopy, ad1++, 0, 0);
		ad2 = dol;
	}
	ad2++;
	if (adt < ad1) {
		dot = adt + (ad2 - ad1);
		if (++adt == ad1)
			return;
		reverse(adt, ad1);
		reverse(ad1, ad2);
		reverse(adt, ad2);
	} else if (adt >= ad2) {
		dot = adt++;
		reverse(ad1, ad2);
		reverse(ad2, adt);
		reverse(ad1, adt);
	} else
		errmsg(28);
}

newline() {
	register charac c;

	if ((c = getchar()) == '\n')
		return;
	if (c == 'p' || c == 'l'
#ifdef PARENS
				 || c == 'b'
#endif
#ifdef STRLEN
					     || c == 'q'
#endif
							) {
		pflag++;
		if (c == 'l')
			listf++;
#ifdef PARENS
		else if (c == 'b')
			parenf++;
#endif
#ifdef STRLEN
		else if (c == 'q')
			quotef++;
#endif
		if (getchar() == '\n')
			return;
	}
	errmsg(25);
}

#ifdef TABS
next_tab(acol) {
	register n;

	if ((n = acol) < maxtab) {
		do {
			n++;
		} while (!(tabs[n >> BPWC] >> (n & BPWM) & 01));
		return(n);
	}
	return(-1);
}
#endif

nonzero() {
	if (addr1 <= zero)
		errmsg(23);
	if (addr2 > dol)
		errmsg(24);
}

#ifdef PIPE
oil_spilled() {
	if (!iflg) {
		signal(SIGINT, 1);
		signal(SIGQIT, 1);
	}
	signal(SIGPIP, 1);
	piperr++;
}
#endif

onintr() {
	register char *p1, *p2;

	signal(SIGINT, onintr);
#ifdef USE
	if (alt) {
		close(alt);
		alt = 0;
		eflg2 = 0;
	}
#endif
	if (io) {
		if (curt)
			putsn("?intI/O");
		else {
			puts2("\7Interrupted I/O!!!\7\nWarning: \"");
			puts2(file);
			if (io_w) {
				putsn("\" is probably truncated.");
				puts2("You should probably re-write it.");
			} else {
				putsn("\" was not read entirely.");
				puts2("If you write the buffer, ");
				puts2("part of the file may be lost.");
			}
		}
		flush_buf();
	}
#ifdef EOL
	prompt3 = 1;
#endif
	if (fout != 1) {
		close(fout);
		fout = 1;
	}
#ifdef YINT
	if (!globp && reading && yflg) {
		globp = ".:\n";
		if (yplus) {
			dot = findmark(yplus, 0);
		} else
			globp++;
		peekc = 0;
		putchar('\n');
		commands(1);
		reset();
	}
#endif
	if (iflg) {
		signal(SIGINT, 1);
		backup(INT);
		delexit(1);
	}
	putchar(lastc = '\n');
	errmsg(29);
}

override() {
	struct stat s;

	if (access(file, 02) < 0) {
		if (stat(file, &s) >= 0 && (s.st_mode & S_IFMT) == S_IFREG) {
			overmode = s.st_mode & 07777;
			if (chmod(file, overmode) < 0)
				return;
			if (immflg == 0) {
				if (curt) {
					puts2("?\"");
					puts2(file);
					puts2("\"  ");
				} else {
					puts2("The file \"");
					puts2(file);
					puts2("\" is write-protected.");
				}
				if (yes_no(curt? "override" :
				    "Do you wish to over-ride the permission",
				    0, 1, 1))
					return;
			}
			overfile = file;
			if (chmod(overfile, overmode | 0200) < 0)
				overfile = 0;
			else {
				putsn("[over-riding]");
#ifdef LOG
				++logstats.lm_overwrite;
#endif
			}
		}
	}
}

#ifdef PAGE
page() {
	register cl, n;
	register char *p, *pp;
	register linep *a, *b;
	register l;

	a = addr1;
	if (addr2 != addr1)
		b = addr2;
	else
		b = dol;
#ifdef PARENS
	parenc[0] = 0;
	parenc[1] = 0;
	parenc[2] = 0;
#endif
	for (n = pcount; n >= 0 && a <= b; n--) {
		pp = p = getline(*a);
		cl = prompt1? 8 : 0;
		l = 0;
		while (*p) {
			if (*p < ' ' || *p > '~')
				switch (*p) {
				case '\b':
					if (listf)
						cl++;
					else {
						cl--;
						if (aflg
#ifdef PARENS
							 && !parenf
#endif
#ifdef STRLEN
							 && !quotef
#endif
								   )
							l++;
					}
					break;
				case '\t':
					if (listf)
						cl++;
					else
						cl += 8 - cl % 8;
					break;
				case '\r':
					if (listf)
						cl += 2;
					else
						cl = 0;
					break;
				case ctrl('L'):	/* ADM-3A's */
					if (listf)
						cl++;
					cl++;
					break;
				default:
					if (listf || zflg)
						cl += 2;
				}
			else
				cl++;
#ifdef PARENS
			if (parenf && paren(*p))
				l++;
#endif
#ifdef STRLEN
			/* if (quotef && (*p == '"' || *p == '\'')) */
			if (quotef && (quotec? *p == quotec :
			    *p == '"' || *p == '\''))
				l++;
#endif
			if (cl < 0)
				cl = 0;
			else if (cl > ccount) {
				cl = 0;
				if (--n < 0)
					goto done;
			}
			p++;
		}
		if (l)
			if (--n < 0)
				goto done;
		col = 0;
		printlno(line_num = a - zero);
		puts(pp);
		a++;
	}
    done:
	dot = a - 1;
}
#endif

#ifdef PARENS
paren(ac) {
	switch (ac) {
	case '(':	return(1);
	case '[':	return(2);
	case '{':	return(3);
	case ')':	return(-1);
	case ']':	return(-2);
	case '}':	return(-3);
	}
	return(0);
}
#endif

place(asp, al1, al2) {
	register char *sp, *l1, *l2;

	sp = asp;
	l1 = al1;
	l2 = al2;
	while (l1 < l2) {
		*sp++ = *l1++;
#ifndef ALLOC
		if (sp >= &genbuf[LBSIZE - 2])
#else
		if (sp >= &genbuf[lbsize - 2])
#endif
			errmsg(42);
	}
	return(sp);
}

/*VARARGS*/
printf(as, aarglist)
char *as;
{
	register *args, w;
	register char *q;
	register flag f;

	args = &aarglist;
	while (*as) {
		if (*as != '%') {
			putchar(*as++);
			continue;
		}
		if (*++as == '\0')
			return;
		w = 0;	/* no default width */
		f = 0;	/* unsigned default */
		while ('0' <= *as && *as <= '9')
			w = w * 10 + *as++ - '0';
		if (*as == '\0')
			return;
		switch (*as++) {
		case 'c':	/* char */
			putchar(*args++);
			continue;
		case 'd':	/* signed decimal */
			f = 1;	/* signed */
		case 'u':	/* unsigned decimal */
			printfn(*args++, 10, f, w);
			continue;
		case 'o':	/* unsigned octal */
			printfn(*args++, 8, 0, w);
			continue;
		case 's':	/* string */
			q = *args++;
			while (*q) {
				putchar(*q++);
				--w;
			}
			while (--w > 0)
				putchar(' ');
			continue;
		default:
			putchar(as[-1]);
			continue;
		}
	}
}

printfn(an, ab, af, aw) {
	register w;
	register unsigned n;
	register char *p;
	char buf[(sizeof(int) != 2? 10 : 6) + 2];

	w = aw;
	p = &buf[sizeof buf];
	*--p = '\0';
	n = an;
	if (af)
		if (an < 0)
			n = -an;
		else
			af = 0;
	do {
		*--p = n % ab + '0';
		--w;
	} while (n /= ab);
	if (af) {
		*--p = '-';
		--w;
	}
	while (--w >= 0)
		putchar(' ');
	while (*p)
		putchar(*p++);
}

printlno(an) {
	register flag l;

	if (prompt1) {
		l = listf;
		listf = 0;
		printf(fmtlno, an - aflg);
		col = 8;
		listf = l;
	}
}

printmarks() {
	register linep *a1;
	register charac c;
	register n, i;

#ifdef HUGE
	i = hugef ^ 01;
#endif
	for (c = 'a' - 'a'; c <= 'z' - 'a'; c++) {
	    if (names[c] == 0)	/* zap marks to deleted lines */
		continue;
	    n = 0;
	    for (a1 = zero + 1; a1 <= dol; a1++)
		if (names[c] == (*a1 |
#ifdef HUGE
					i
#else
					01
#endif
					  )) {
		    n++;
		    printf("%c=%u", c + 'a', a1 - zero);
#ifdef EXTMARK
		    if (names2[c]) {
			for (a1++; a1 <= dol; a1++)
			    if (names2[c] == (*a1 | 01)) {
				printf(",%u", a1 - zero);
				break;
			    }
		    }
#endif
		    putchar(' ');
		    break;
		}
	    if (n == 0)
		names[c] = 0;	/* clear unknown marks */
	}
	putchar('\n');
}

putchar(ac)
charac ac;
{
	register char *lp;
	register charac c;

	lp = linp;
	c = ac;
#ifdef APLMAP
	if (aplmap && fout == 1 && c > ' ')
		c = map_apl[c - (' ' + 1)];
#endif
	if (listf) {
		if (++col >= ccount - 1) {
			col = 1;
			if (c != '\n') {
				*lp++ = '\\';
				*lp++ = '\n';
			}
		}
		if (c == '\t') {
			c = '>';
			goto esc;
		}
		if (c == '\b') {
			c = '<';
		esc:
			*lp++ = '-';
			*lp++ = '\b';
			*lp++ = c;
			goto out;
		}
		if (c < ' ' && c != '\n' || c == 0177) {
			*lp++ = '^';
			*lp++ = c ^ 0100;
			col++;
			goto out;
		}
	}
	*lp++ = c;
out:
	if (lp >= &line[TTSIZE]) {
		linp = line;
		write(fout, line, lp - line);
		return;
	}
	linp = lp;
}

putfile() {
	register char *fp, *lp;
	register nib;
	register linep *a1;

	nib = BLKSIZE;
	fp = genbuf;
	a1 = addr1;
	do {
		lp = getline(*a1++);
		for ever {
			if (--nib < 0) {
				wte(io, genbuf, fp - genbuf);
				nib = BLKSIZE - 1;
				fp = genbuf;
			}
			if ((*fp++ = *lp++) == 0) {
				fp[-1] = '\n';
				break;
			}
		}
	} while (a1 <= addr2);
	wte(io, genbuf, fp - genbuf);
}

putline() {
	register char *bp, *lp;
	register nl, tl;

	lp = linebuf;
	tl = tline;
#ifdef DEBUG
	if (tflg)
		printf("putline:\t%o\n", tl);
#endif
	bp = getblock(tl, WRITE);
#ifdef HUGE
	if (hugef2) {
		hugef2 = 0;
		tl = tline = (tline >> 1) & _6[hugef];
	}
	tl &= _1[hugef];
#else
	tl &= _1;
#endif
	nl = nleft;
	while (*bp = *lp++) {
		if (*bp++ == '\n') {
			*--bp = 0;
			linebp = lp;
			break;
		}
		if (--nl <= 0) {
#ifdef HUGE
			bp = getblock(tl += _2[hugef], WRITE);
#else
			bp = getblock(tl += _2, WRITE);
#endif
			nl = nleft;
		}
	}
	nl = tline;
#ifdef HUGE
	tline += (((lp - linebuf) + 03) >> (1 + hugef)) & _6[hugef];
#else
	tline += (((lp - linebuf) + 03) >> 1) & _6;
#endif
	return(nl);
}

#ifdef PARENS
putparen(an) {
	register c;

	an %= 10 + 26 + 26;
	if (an < 0)
		an += 10 + 26 + 26;
	c = '0';
	if (an > 9 + 26)
		c = 'a' - (10 + 26);
	else if (an > 9)
		c = 'A' - 10;
	putchar(c + an);
}
#endif

puts(as) {
	register n;
	register flag ovp;
	register char *sp, *s;

	sp = as;
	ovp = 0;
	while (*sp) {
		if (aflg &&
#ifdef PARENS
			    !parenf &&
#endif
#ifdef STRLEN
				       !quotef &&
#endif
						  !listf && *sp == '\b') {
			ovp = 1;
			sp += 2;
			continue;
		}
#ifdef PARENS
		if (!ovp && parenf && !listf && paren(*sp))
			ovp = 1;
#endif
#ifdef STRLEN
	/* if (!ovp && quotef && !listf && (*sp == '"' || *sp == '\'')) */
		if (!ovp && quotef && !listf && (
		    quotec? *sp == quotec : *sp == '"' || *sp == '\''))
			ovp = 1;
#endif
		putchar(*sp++);
	}
	sp = as;
	if (aflg && ovp &&
#ifdef PARENS
			   !parenf &&
#endif
#ifdef STRLEN
				      !quotef &&
#endif
						 !listf) {
		putchar('\n');
		if (prompt1)
			putchar('\t');
		for (; *sp; sp++)
			if (sp[1] == '\b' && sp[2]) {
				putchar(sp[2]);
				sp += 2;
			} else if (*sp == '\t')
				putchar('\t');
			else if (*sp >= ' ')
				putchar(' ');
		ovp = 0;
	}
#ifdef PARENS
	if (parenf && ovp && !listf) {
		putchar('\n');
		if (prompt1)
			putchar('\t');
		for (; *sp; sp++)
			if (n = paren(*sp)) {
				if (n < 0) {
					n = -n - 1;
					putparen(parenc[n]--);
				} else
					putparen(++parenc[--n]);
			} else if (*sp == '\t' || *sp >= ' ')
				putchar(*sp == '\t'? '\t' : ' ');
		ovp = 0;
	}
#endif
#ifdef STRLEN
	if (quotef && ovp && !listf) {
		s = null;
		n = 0;
		ovp = 0;
		putchar('\n');
		if (prompt1)
			putchar('\t');
		for (; *sp; sp++) {
		/* if (n == 0 && (*sp == '"' || *sp == '\'') || */
			if (n == 0 && (quotec? *sp == (ovp?
			    quotec : quotec2) : *sp == '"' || *sp == '\'') ||
			    *sp == n) {
				if (ovp) {
					ovp = 0;
					goto not;
				}
				if (n)
					n = 0;
				else {
					s = sp++;
					n = 0;
					while (*sp && *sp != *s) {
						if (*sp == '\\') {
						  if ('0' <= *++sp && *sp <= '7') {
						    if ('0' <= *++sp && *sp <= '7') 
						      if ('0' <= *++sp && *sp <= '7') 
							sp++;
						  } else
							sp++;
						} else
							sp++;
						n++;
					}
					sp = s;
					s = &"00000"[5];
					do {
						*--s = n % 10 + '0';
					} while (n /= 10);
					n = *sp;
				}
			}
    not:		if (*s)
				putchar(*s++);
			else
				putchar(*sp == '\t'? '\t' : ' ');
			if (*sp == '\\')
				ovp ^= 01;
		}
		ovp = 0;
	}
#endif
	putchar('\n');
}

puts2(as) {
	register char *sp;

	sp = as;
	while (*sp)
		putchar(*sp++);
}

#ifdef CKPT
recover() {
	extern etext;
	register filedes f;
	register char *p;
	register func savint, savqit;
	int n;

	savint = signal(SIGINT, 1);
	savqit = signal(SIGQIT, 1);
	if ((f = open(cfname, 0)) < 0 ||
	    read(f, &n, sizeof n) != sizeof n) {
		n = 67;
		goto cerror;
	}
	p = &etext;
	if (brk(p + n) == -1) {
		n = 67;
		goto cerror;
	}
#ifdef pdp11	/* 16 bit byte count only */
	if (n < 0) {
		if (read(f, p, 32256) != 32256) {
			n = 67;
			goto cerror;
		}
		n -= 32256;	/* 63 blocks, since 64 is < 0 */
		p += 32256;
	}
#endif
	if (read(f, p, n) != n ||
	    (tfile = open(tfname, 2)) < 0)
		n = 67;
	else
		n = 0;
	recovry = 1;	/* overwritten by reading data space */
    cerror:
	if (n) {
		puts(errtext[n]);
		exit(1);
	}
	if (f > 0)
		close(f);

	/*
	 * "initialize" special stuff to restore order
	 */

	globp = 0;
	io = 0;
	io_w = 0;
#ifdef HELP
	doc = 0;
#endif
#ifdef USE
	alt = 0;
#endif
#ifdef AGAIN
	agf = 0;
	agp = 0;
#endif
#ifdef EOL
	prompt3 = 1;
#endif
#ifdef PIPE
	if (pfile) {
		unlink(pfname);
		pfile = 0;
	}
#endif

	signal(SIGINT, savint);
	signal(SIGQIT, savqit);
}
#endif

reverse(aa1, aa2) {
	register linep *a1, *a2, t;

	a1 = aa1;
	a2 = aa2;
	for ever {
		t = *--a2;
		if (a2 <= a1)
			return;
		*a2 = *a1;
		*a1++ = t;
	}
}

#ifdef XDEL
saveline() {
	register linep *a1, *a2, *bp;
	register nl, tl;

	a1 = addr1;
	a2 = addr2;
	ndeleted = a2 - a1 + 1;
	tl = tline;
#ifdef DEBUG
	if (tflg)
		printf("saveline:\t%o\n", tl);
#endif
	bp = getblock(tl, WRITE);
#ifdef HUGE
	if (hugef2) {
		hugef2 = 0;
		tl = (tl >> 1) & _6[hugef];
	}
	tl &= _1[hugef];
#else
	tl &= _1;
#endif
	nl = nleft / sizeof(linep);
	while (a1 <= a2) {
		*bp++ = *a1++;
		if (--nl <= 0) {
#ifdef HUGE
			bp = getblock(tl += _2[hugef], WRITE);
			if (hugef2) {
				hugef2 = 0;
				tl = (tl >> 1) & _6[hugef];
			}
#else
			bp = getblock(tl += _2, WRITE);
#endif
			nl = nleft / sizeof(linep);
		}
	}
	deleted = tline;
#ifdef HUGE
	tline += ((a2 - addr1 + 1) << (1 - hugef)) & _6[hugef];
#else
	tline += ((a2 - addr1 + 1) << 1) & _6;
#endif
}
#endif

savemark(p1, p2)
linep p1, p2;
{
	register n;
#ifdef HUGE
	register i;

	i = hugef ^ 01;
	p1 |= i;
	p2 |= i;
#else
	p1 |= 01;
	p2 |= 01;
#endif
	/* save "marks" on lines so marked */
	for (n = 0; n <= 'z' - 'a'; n++) {
		if (names[n] == 0)	/* zap marks to deleted lines */
			continue;
		if (names[n] == p1)
			names[n] = p2;
#ifdef EXTMARK
		if (names2[n] && names2[n] == p1)
			names2[n] = p2;
#endif
	}
#ifdef YINT
	/* don't lose "y+" line either */
	if (yplus == p1)
		yplus = p2;
#endif
#ifdef UNDO
	/* and remember the line for "undo" */
	undo_oldp = p1;
	undo_newp = p2;
#endif
}

scopy(ass, ads)
char *ass, *ads;
{
	register char *p, *q;

	p = ass;
	q = ads;
	while (*q++ = *p++)
		;
	return(ads);
}

setall() {
	if (addr2 == 0) {
		addr1 = zero + (zero != dol);
		addr2 = dol;
	}
	setdot();
}

setchar(adflt) {
	register charac c;

	if ((c = getchar()) == '\\')
		c = getchar();
	if (c < 0)
		errmsg(59);
	if (c == '\n')
		return(adflt);
	newline();
	return(c);
}

setdot() {
	if (addr2 == 0)
		addr1 = addr2 = dot;
	if (addr1 > addr2)
		errmsg(21);
}

setnoaddr() {
	if (addr2)
		errmsg(22);
}

setnum(adflt) {
	register n;

	white_space();
	n = adflt;
	if ('0' <= (peekc = getchar()) && peekc <= '9')
		n = getnum();
	newline();
	return(n);
}

#ifdef TABS
settab(acs) {
	register *p, i, n;

	if (acs == 0) {
		maxtab = -1;
		n = TABS;
		p = tabs;
		while (--n >= 0)
			*p++ = 0;
		return;
	}
	i = 0;
	if (acs < 0) {
		acs = -acs;
		i++;
	}
	if (--acs < TABS * BPW) {
		p = &tabs[acs >> BPWC];
		*p |= 01 << (n = acs & BPWM);
		if (i) {
			*p ^= 01 << n;
			if (acs == maxtab) {	/* find new maxtab */
				for (n = TABS - 1; n >= 0; --n)
					if (tabs[n >> BPWC] >> (n & BPWM) & 01)
						break;
				maxtab = n;
			}
		} else if (acs > maxtab)
			maxtab = acs;
	}
}
#endif

shell() {
#ifdef PIPE
	extern oil_spilled();
#endif
	register pid, wpid;
	register linep *a;
	register dp, df, nopipe, c, e, savint, savqit;
	register linep *dest;
	int retcode, p[2];

#ifdef PIPE
	dp = 0;
	df = 0;
	if (addr2) {
#ifdef LOG
		++logstats.lc_pipe;
#endif
		dest = 0;
		nopipe = 0;
		if ((peekc = getchar()) == '|') {
			nonzero();
			peekc = 0;
			dp++;
			df++;
#ifdef LOG
			--logstats.lc_pipe;
			++logstats.lc_dpipe;
#endif
		}
		if ((peekc = getchar()) == '>') {
			nonzero();
#ifdef LOG
			--logstats.lc_pipe;
			++logstats.lc_pto;
#endif
			goto pi;
		} else if ((peekc = getchar()) == '<') {
			nopipe++;
#ifdef LOG
			--logstats.lc_pipe;
			++logstats.lc_pfrom;
#endif
    pi:			peekc = 0;
			dp++;
			dest = addr2;
		}
		if (dp && '0' <= (peekc = getchar()) && peekc <= '9') {
			c = getnum();
			dest = zero + c;
			if (dest < zero)
				dest = zero + 1;
			if (dest > dol)
				dest = dol;
		}
	}
#ifdef LOG
	  else
		++logstats.lc_shell;
#endif
	piperr = 0;
	if (!iflg)
		if (addr2) {
			savint = signal(SIGINT, oil_spilled);
			savqit = signal(SIGQIT, oil_spilled);
		} else {
#endif
			savint = signal(SIGINT, 1);
			savqit = signal(SIGQIT, 1);
#ifdef PIPE
		}
	if (addr2 && pipe(p) < 0) {
		c = 15;
    errm:	if (!iflg) {
			signal(SIGINT, savint);
			signal(SIGQIT, savqit);
		}
		if (c)
			errmsg(c);
		error();
	}
	if (dp) {
		if ((pfile = create(pfname, LMODE)) < 0) {
			pfile = 0;
			c = 64;
			goto errm;
		}
		if ((io = open(pfname, 0)) < 0) {
			io = 0;
			c = 65;
			goto errm;
		}
	}
#endif
	if ((pid = fork()) < 0) {
#ifdef PIPE
		if (addr2) {
			close(p[0]);
			close(p[1]);
		}
#endif
		c = 14;
		goto errm;
	}
	if (pid == 0) {
/* kid */	if (!iflg) {
/* kid */		signal(SIGHUP, 0);
/* kid */		signal(SIGINT, 0);
/* kid */		signal(SIGQIT, 0);
/* kid */	}
#ifdef PIPE
/* kid */	if (addr2) {
/* kid */		close(0);
/* kid */		dup(p[0]);
/* kid */		close(p[0]);
/* kid */		close(p[1]);
/* kid */		if (dp) {
/* kid */			close(1);
/* kid */			dup(pfile);
/* kid */			close(pfile);
/* kid */		}
/* kid */	}
#endif
/* kid */	execl("/bin/sh", "!sh", "-t", 0);
/* kid */	write(2, "No shell!\n", 10);
/* kid */	exit(0177);
	}
#ifdef CMDS
	if (cmd && !addr2)
		write(cmd, "<UNIX>\n", 7);
#endif
#ifdef PIPE
	if (addr2) {
		signal(SIGPIP, oil_spilled);
		close(p[0]);
		e = eflg2;
		eflg2++;
		fout = p[1];
		while ((c = getchar()) >= 0 && c != '\n')
			putchar(c);
		putchar('\n');
		if (!nopipe) {
			line_num = (a = addr1) - zero - aflg;
			do {
				if (pno >= 0)
					printlno(line_num++);
				puts(getline(*a++));
			} while (a <= addr2 && !piperr);
		}
		flush_buf();
		fout = 1;
		eflg2 = e;
		close(p[1]);
		if (!iflg) {
			signal(SIGINT, 1);
			signal(SIGQIT, 1);
		}
	}
#endif
	while ((wpid = wait(&retcode)) != pid && wpid >= 0);
#ifdef CMDS
	if (cmd)
		lseek(cmd, 0L, 2);
#endif
#ifdef PIPE
	if (addr2)
		signal(SIGPIP, 0);
#endif
	if (c = retcode & 0177) {
		if (0 < c && c < NSTR && status[c])
			puts2(status[c]);
		else
			printf("signal %d", c);
		if (retcode & 0200)
			puts2(" -- core dumped");
		putchar(lastc = '\n');
		c = 0;
		goto errm;
	} else if (df && strict && retcode >> 8) {
		printf("exit status %d\n", retcode >> 8);
		c = 0;
		goto errm;
	}
#ifdef PIPE
	  else if (addr2) {
		if (piperr) {
			putsn(status[SIGPIP]);
			c = 0;
			goto errm;
		}
		if (dp) {
			if (df) {
				c = addr2 != dol;
				delete();
				if (dest == 0)
					dest = dot - c;
			} else if (dest == 0)
				dest = addr2;
			if (dest < zero)
				dest = zero;
			if (c = append(getfile, dest, 0, 0))
				text_modified++;
			if (prompt2)
				printf((curt? prcntu : errtext[55]),
				    c, (c == 1? null : quote_s));
			close(io);
			io = 0;
			unlink(pfname);
			close(pfile);
			pfile = 0;
		}
	}
#endif
	if (!iflg) {
		signal(SIGINT, savint);
		signal(SIGQIT, savqit);
	}
	if (!addr2)
		putsn("!");
#ifdef CLEAR
	istty(1);	/* in case bs1 changed */
#endif
}

signals(ast)
struct sigtab *ast;
{
	register n;
	register struct sigtab *s;

	s = ast - 1;
	while (n = (++s)->s_sig)
		signal(n, s->s_func);
}

skip_rest() {
	register charac c;

	while ((c = getchar()) >= 0 && c != '\n');
}

substitute(inglob) {
	extern getsub();
	register linep *a1, p;
	register nl;
	register flag gsubf;

	gsubf = compsub();		/* 0 or 1 depending on 'g' */
	for (a1 = addr1; a1 <= addr2; a1++) {
		s_tmp = s_cnt;
		if (execute(0, a1) == 0)
			continue;
		inglob |= 01;
		dosub();
		if (gsubf)
			while (*loc2) {
				if (execute(1) == 0)
					break;
				dosub();
			}
		p = *a1;
		*a1 = putline();
		savemark(p, *a1);
		nl = append(getsub, a1, 0, 0);
		a1 += nl;
		addr2 += nl;
	}
	if (inglob == 0)
		errmsg(39);
}

#ifdef XED
tack(aeof, aflag)
char aeof;
{
	register n;
	register char *p1, *p2;
	register linep *a;
	register charac c;

	nonzero();
	setdot();
	p1 = rhsbuf;	/* i/TEXT screwed for long lines */
	while ((c = getchar()) != aeof && c != '\n') {
		if (c == '\\')
			if ((c = getchar()) == '\n')
				break;
		if (c < 0)
			errmsg(59);
		*p1++ = c;
		if (p1 >= &rhsbuf[LBSIZE / 2 - 2])
			errmsg(42);
	}
	if (*rhsbuf == 0)
		errmsg(27);
	if (c == '\n') {
		if (prompt2)
			pflag++;
	} else
		newline();
	if (p1 != rhsbuf)
		*p1 = 0;
	else
		while (*p1)
			p1++;
	n = p1 - rhsbuf;
	for (a = addr1; a <= addr2; a++) {
		getline(*a);
		for (p2 = linebuf; *p2; p2++);
#ifndef ALLOC
		if (p2 + n >= &linebuf[LBSIZE / 2 - 2])
#else
		if (p2 + n >= &linebuf[lbsize / 2 - 2])
#endif
			errmsg(30);
		if (aflag) {	/* $ */
			p1 = rhsbuf;
			while (*p2++ = *p1++);
		} else {	/* ^ */
			p1 = p2 + n;
			*p1 = *p2;
			while (p2 > linebuf)
				*--p1 = *--p2;
			p1 = linebuf;
			p2 = rhsbuf;
			while (*p2)
				*p1++ = *p2++;
		}
		p2 = *a;
		*a = putline();
		savemark(p2, *a);
	}
	dot = addr2;
	return(addr2 - addr1 + 1);
}
#endif

term() {
	signal(SIGTRM, 1);
	if (reading) {
		backup(TRM);
		if (fout != 1) {
			flush_buf();
			fout = 1;
		}
		puts2(errtext[58]);
		delexit(1);
	}
	termflg++;
}

tmpname(as, an)
char *as;
{
	register unsigned n;
	register char *p, c;

	p = as;
	n = an;
	while (*p)
		p++;
	while (--p >= as)
		if ((c = *p) == '0' || (c | 040) == 'x') {
			*p = n % 10 + '0';
			n /= 10;
#ifdef CKPT
			tfnum = p - as;
#endif
		}
	return(as);
}

#ifdef XDEL
undelete() {
	register linep *a1, *a2, *bp;
	register tl, nl, num;

	if ((tl = deleted) == 0)
		errmsg(16);
#ifdef DEBUG
	if (tflg)
		printf("undelete:\t%o\n", tl);
#endif
	setdot();
	a1 = dol + 1;
	a2 = a1 + ndeleted;
	bp = addr2 + 1;
	if (dol + ndeleted > endcore) {
		num = ((ndeleted * 2) + 1023) & ~01777;
		if (sbrk(num) == -1)
			errmsg(33);
		endcore = (int)endcore + num;
	}
	while (a1 > bp)
		*--a2 = *--a1;
	dol += ndeleted;
	a1 = addr2 + 1;
	a2 = a1 + ndeleted;
	bp = getblock(tl, READ);
#ifdef HUGE
	tl &= _1[hugef];
#else
	tl &= _1;
#endif
	nl = nleft / sizeof(linep);
	while (a1 < a2) {
		*a1++ = *bp++;
		if (--nl <= 0) {
#ifdef HUGE
			bp = getblock(tl += _2[hugef], READ);
#else
			bp = getblock(tl += _2, READ);
#endif
			nl = nleft / sizeof(linep);
		}
	}
	dot = a2 - 1;
	return(ndeleted);
}
#endif

#ifdef UNDO
undo() {
	register linep *a, t, o;

	if (undo_newp == 0 || (a = findmark(undo_newp, 0)) == 0)
		errmsg(13);
	t = *a |
#ifdef HUGE
		 hugef ^
#endif
			 01;
	o = undo_oldp;
	savemark(*a, o);
	*a = o;
	undo_newp = o;
	undo_oldp = t;
	dot = a;
	if (text_modified == 0)
		text_modified++;
}
#endif

white_space() {
	register charac c;

	while ((c = getchar()) == ' ' || c == '\t');
	peekc = c;
}

wte(fd, buf, len)
char buf[];
{
	if (write(fd, buf, len) != len)
		errmsg(-32);
}

/*
 * as	a prompt string
 * ay	yes response, !no response
 * ad	default (\n) response, <0 means no default allowed
 * aef	end-of-file response
 */
yes_no(as, ay, ad, aef)
char *as;
{
	register charac c, p;
	register n;
	register flag l;

	l = listf;
	listf = 0;
	p = peekc;
	peekc = 0;
	for ever {
		putchar('\n');
		puts2(as);
		puts2("? ");
		for (n = 0; n < 5; n++) {
			flush_buf();
			if ((c = getchar()) < 0) {
				putchar('\n');
				n = aef;
				goto ret;
			}
			if (c != '\n')
				skip_rest();
			else if (ad >= 0) {
				n = ad;
				goto ret;
			}
			if (c == 'y' || c == 'n') {
				n = ay;
				if (c != 'y')
					n ^= 01;
				goto ret;
			}
			puts2("yes or no? ");
		}
	}
    ret:
	listf = l;
	peekc = p;
	return(n);
}