xref: /onnv-gate/usr/src/cmd/ed/ed.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*13093SRoger.Faulkner@Oracle.COM  * Common Development and Distribution License (the "License").
6*13093SRoger.Faulkner@Oracle.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
26*13093SRoger.Faulkner@Oracle.COM /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27*13093SRoger.Faulkner@Oracle.COM /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Editor
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include	<crypt.h>
340Sstevel@tonic-gate #include	<libgen.h>
350Sstevel@tonic-gate #include	<wait.h>
360Sstevel@tonic-gate #include	<string.h>
370Sstevel@tonic-gate #include	<sys/types.h>
380Sstevel@tonic-gate #include	<locale.h>
390Sstevel@tonic-gate #include	<regexpr.h>
400Sstevel@tonic-gate #include	<regex.h>
410Sstevel@tonic-gate #include	<errno.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static const 	char	*msgtab[] =
440Sstevel@tonic-gate {
450Sstevel@tonic-gate 	"write or open on pipe failed",			/*  0 */
460Sstevel@tonic-gate 	"warning: expecting `w'",			/*  1 */
470Sstevel@tonic-gate 	"mark not lower case ascii",			/*  2 */
480Sstevel@tonic-gate 	"Cannot open input file",			/*  3 */
490Sstevel@tonic-gate 	"PWB spec problem",				/*  4 */
500Sstevel@tonic-gate 	"nothing to undo",				/*  5 */
510Sstevel@tonic-gate 	"restricted shell",				/*  6 */
520Sstevel@tonic-gate 	"cannot create output file",			/*  7 */
530Sstevel@tonic-gate 	"filesystem out of space!",			/*  8 */
540Sstevel@tonic-gate 	"cannot open file",				/*  9 */
550Sstevel@tonic-gate 	"cannot link",					/* 10 */
560Sstevel@tonic-gate 	"Range endpoint too large",			/* 11 */
570Sstevel@tonic-gate 	"unknown command",				/* 12 */
580Sstevel@tonic-gate 	"search string not found",			/* 13 */
590Sstevel@tonic-gate 	"-",						/* 14 */
600Sstevel@tonic-gate 	"line out of range",				/* 15 */
610Sstevel@tonic-gate 	"bad number",					/* 16 */
620Sstevel@tonic-gate 	"bad range",					/* 17 */
630Sstevel@tonic-gate 	"Illegal address count",			/* 18 */
640Sstevel@tonic-gate 	"incomplete global expression",			/* 19 */
650Sstevel@tonic-gate 	"illegal suffix",				/* 20 */
660Sstevel@tonic-gate 	"illegal or missing filename",			/* 21 */
670Sstevel@tonic-gate 	"no space after command",			/* 22 */
680Sstevel@tonic-gate 	"fork failed - try again",			/* 23 */
690Sstevel@tonic-gate 	"maximum of 64 characters in file names",	/* 24 */
700Sstevel@tonic-gate 	"`\\digit' out of range",			/* 25 */
710Sstevel@tonic-gate 	"interrupt",					/* 26 */
720Sstevel@tonic-gate 	"line too long",				/* 27 */
730Sstevel@tonic-gate 	"illegal character in input file",		/* 28 */
740Sstevel@tonic-gate 	"write error",					/* 29 */
750Sstevel@tonic-gate 	"out of memory for append",			/* 30 */
760Sstevel@tonic-gate 	"temp file too big",				/* 31 */
770Sstevel@tonic-gate 	"I/O error on temp file",			/* 32 */
780Sstevel@tonic-gate 	"multiple globals not allowed",			/* 33 */
790Sstevel@tonic-gate 	"global too long",				/* 34 */
800Sstevel@tonic-gate 	"no match",					/* 35 */
810Sstevel@tonic-gate 	"illegal or missing delimiter",			/* 36 */
820Sstevel@tonic-gate 	"-",						/* 37 */
830Sstevel@tonic-gate 	"replacement string too long",			/* 38 */
840Sstevel@tonic-gate 	"illegal move destination",			/* 39 */
850Sstevel@tonic-gate 	"-",						/* 40 */
860Sstevel@tonic-gate 	"no remembered search string",			/* 41 */
870Sstevel@tonic-gate 	"'\\( \\)' imbalance",				/* 42 */
880Sstevel@tonic-gate 	"Too many `\\(' s",				/* 43 */
890Sstevel@tonic-gate 	"more than 2 numbers given",			/* 44 */
900Sstevel@tonic-gate 	"'\\}' expected",				/* 45 */
910Sstevel@tonic-gate 	"first number exceeds second",			/* 46 */
920Sstevel@tonic-gate 	"incomplete substitute",			/* 47 */
930Sstevel@tonic-gate 	"newline unexpected",				/* 48 */
940Sstevel@tonic-gate 	"'[ ]' imbalance",				/* 49 */
950Sstevel@tonic-gate 	"regular expression overflow",			/* 50 */
960Sstevel@tonic-gate 	"regular expression error",			/* 51 */
970Sstevel@tonic-gate 	"command expected",				/* 52 */
980Sstevel@tonic-gate 	"a, i, or c not allowed in G",			/* 53 */
990Sstevel@tonic-gate 	"end of line expected",				/* 54 */
1000Sstevel@tonic-gate 	"no remembered replacement string",		/* 55 */
1010Sstevel@tonic-gate 	"no remembered command",			/* 56 */
1020Sstevel@tonic-gate 	"illegal redirection",				/* 57 */
1030Sstevel@tonic-gate 	"possible concurrent update",			/* 58 */
1040Sstevel@tonic-gate 	"-",						/* 59 */
1050Sstevel@tonic-gate 	"the x command has become X (upper case)",	/* 60 */
1060Sstevel@tonic-gate 	"Warning: 'w' may destroy input file "
1070Sstevel@tonic-gate 	"(due to `illegal char' read earlier)",
1080Sstevel@tonic-gate 							/* 61 */
1090Sstevel@tonic-gate 	"Caution: 'q' may lose data in buffer;"
1100Sstevel@tonic-gate 	" 'w' may destroy input file",
1110Sstevel@tonic-gate 							/* 62 */
1120Sstevel@tonic-gate 	"Encryption of string failed",			/* 63 */
1130Sstevel@tonic-gate 	"Encryption facility not available",		/* 64 */
1140Sstevel@tonic-gate 	"Cannot encrypt temporary file",		/* 65 */
1150Sstevel@tonic-gate 	"Enter key:",					/* 66 */
1160Sstevel@tonic-gate 	"Illegal byte sequence",			/* 67 */
1170Sstevel@tonic-gate 	"File does not exist",				/* 68 */
1180Sstevel@tonic-gate 	"tempnam failed",				/* 69 */
1190Sstevel@tonic-gate 	"Cannot open temporary file",			/* 70 */
1200Sstevel@tonic-gate 	0
1210Sstevel@tonic-gate };
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #include <stdlib.h>
1240Sstevel@tonic-gate #include <limits.h>
1250Sstevel@tonic-gate #include <stdio.h>
1260Sstevel@tonic-gate #include <signal.h>
1270Sstevel@tonic-gate #include <sys/types.h>
1280Sstevel@tonic-gate #include <sys/stat.h>
1290Sstevel@tonic-gate #include <sys/statvfs.h>
1300Sstevel@tonic-gate #include <unistd.h>
1310Sstevel@tonic-gate #include <termio.h>
1320Sstevel@tonic-gate #include <ctype.h>
1330Sstevel@tonic-gate #include <setjmp.h>
1340Sstevel@tonic-gate #include <fcntl.h>
1350Sstevel@tonic-gate #include <wchar.h>	/* I18N */
1360Sstevel@tonic-gate #include <wctype.h>	/* I18N */
1370Sstevel@tonic-gate #include <widec.h>	/* I18N */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate #define	FTYPE(A)	(A.st_mode)
1400Sstevel@tonic-gate #define	FMODE(A)	(A.st_mode)
1410Sstevel@tonic-gate #define	IDENTICAL(A, B)	(A.st_dev == B.st_dev && A.st_ino == B.st_ino)
1420Sstevel@tonic-gate #define	ISBLK(A)	((A.st_mode & S_IFMT) == S_IFBLK)
1430Sstevel@tonic-gate #define	ISCHR(A)	((A.st_mode & S_IFMT) == S_IFCHR)
1440Sstevel@tonic-gate #define	ISDIR(A)	((A.st_mode & S_IFMT) == S_IFDIR)
1450Sstevel@tonic-gate #define	ISFIFO(A)	((A.st_mode & S_IFMT) == S_IFIFO)
1460Sstevel@tonic-gate #define	ISREG(A)	((A.st_mode & S_IFMT) == S_IFREG)
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate #define	PUTM()	if (xcode >= 0) puts(gettext(msgtab[xcode]))
1490Sstevel@tonic-gate #define	UNGETC(c)	(peekc = c)
1500Sstevel@tonic-gate #define	FNSIZE	PATH_MAX
1510Sstevel@tonic-gate #define	LBSIZE	LINE_MAX
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /* size of substitution replacement pattern buffer */
1540Sstevel@tonic-gate #define	RHSIZE	(LINE_MAX*2)
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate #define	KSIZE	8
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate #define	READ	0
1590Sstevel@tonic-gate #define	WRITE	1
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate extern  char	*optarg;	/* Value of argument */
1620Sstevel@tonic-gate extern  int	optind;		/* Indicator of argument */
1630Sstevel@tonic-gate extern	int __xpg4;	/* defined in xpg4.c; 0 if not xpg4-compiled program */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate struct  Fspec   {
1660Sstevel@tonic-gate 	char    Ftabs[22];
1670Sstevel@tonic-gate 	char    Fdel;
1680Sstevel@tonic-gate 	unsigned char   Flim;
1690Sstevel@tonic-gate 	char    Fmov;
1700Sstevel@tonic-gate 	char    Ffill;
1710Sstevel@tonic-gate };
1720Sstevel@tonic-gate static struct  Fspec   fss;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate static char	*fsp;
1750Sstevel@tonic-gate static int	fsprtn;
1760Sstevel@tonic-gate static char	line[70];
1770Sstevel@tonic-gate static char	*linp = line;
1780Sstevel@tonic-gate static int	sig;
1790Sstevel@tonic-gate static int	Xqt = 0;
1800Sstevel@tonic-gate static int	lastc;
1810Sstevel@tonic-gate static char	savedfile[FNSIZE];
1820Sstevel@tonic-gate static char	file[FNSIZE];
1830Sstevel@tonic-gate static char	funny[FNSIZE];
1840Sstevel@tonic-gate static int	funlink = 0;
1850Sstevel@tonic-gate static char	linebuf[LBSIZE];
1860Sstevel@tonic-gate static char	*tstring = linebuf;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate static char *expbuf;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate static char	rhsbuf[RHSIZE];
1910Sstevel@tonic-gate struct	lin	{
1920Sstevel@tonic-gate 	long cur;
1930Sstevel@tonic-gate 	long sav;
1940Sstevel@tonic-gate };
1950Sstevel@tonic-gate typedef struct lin *LINE;
1960Sstevel@tonic-gate static LINE	zero;
1970Sstevel@tonic-gate static LINE	dot;
1980Sstevel@tonic-gate static LINE	dol;
1990Sstevel@tonic-gate static LINE	endcore;
2000Sstevel@tonic-gate static LINE	fendcore;
2010Sstevel@tonic-gate static LINE	addr1;
2020Sstevel@tonic-gate static LINE	addr2;
2030Sstevel@tonic-gate static LINE	savdol, savdot;
2040Sstevel@tonic-gate static int	globflg;
2050Sstevel@tonic-gate static int	initflg;
2060Sstevel@tonic-gate static char	genbuf[LBSIZE];
2070Sstevel@tonic-gate static long	count;
2080Sstevel@tonic-gate static int	numpass;	/* Number of passes thru dosub(). */
2090Sstevel@tonic-gate static int	gsubf;		/* Occurrence value. LBSIZE-1=all. */
2100Sstevel@tonic-gate static int	ocerr1;	/* Allows lines NOT changed by dosub() to NOT be put */
2110Sstevel@tonic-gate 			/* out. Retains last line changed as current line. */
2120Sstevel@tonic-gate static int	ocerr2;	/* Flags if ANY line changed by substitute(). 0=nc. */
2130Sstevel@tonic-gate static char	*nextip;
2140Sstevel@tonic-gate static char	*linebp;
2150Sstevel@tonic-gate static int	ninbuf;
2160Sstevel@tonic-gate static int	peekc;
2170Sstevel@tonic-gate static int	io;
2180Sstevel@tonic-gate static void	(*oldhup)(), (*oldintr)();
2190Sstevel@tonic-gate static void	(*oldquit)(), (*oldpipe)();
2200Sstevel@tonic-gate static void	quit(int);
2210Sstevel@tonic-gate static int	vflag = 1;
2220Sstevel@tonic-gate static int	xflag;
2230Sstevel@tonic-gate static int	xtflag;
2240Sstevel@tonic-gate static int	kflag;
2250Sstevel@tonic-gate static int	crflag;
2260Sstevel@tonic-gate 		/* Flag for determining if file being read is encrypted */
2270Sstevel@tonic-gate static int	hflag;
2280Sstevel@tonic-gate static int	xcode = -1;
2290Sstevel@tonic-gate static char	crbuf[LBSIZE];
2300Sstevel@tonic-gate static	int	perm[2];
2310Sstevel@tonic-gate static int	tperm[2];
2320Sstevel@tonic-gate static int	permflag;
2330Sstevel@tonic-gate static int	tpermflag;
2340Sstevel@tonic-gate static int	col;
2350Sstevel@tonic-gate static char	*globp;
2360Sstevel@tonic-gate static int	tfile = -1;
2370Sstevel@tonic-gate static int	tline;
2380Sstevel@tonic-gate static char	*tfname;
2390Sstevel@tonic-gate extern char	*locs;
2400Sstevel@tonic-gate static char	ibuff[LBSIZE];
2410Sstevel@tonic-gate static int	iblock = -1;
2420Sstevel@tonic-gate static char	obuff[LBSIZE];
2430Sstevel@tonic-gate static int	oblock = -1;
2440Sstevel@tonic-gate static int	ichanged;
2450Sstevel@tonic-gate static int	nleft;
2460Sstevel@tonic-gate static long	savnames[26], names[26];
2470Sstevel@tonic-gate static int	anymarks;
2480Sstevel@tonic-gate static long	subnewa;
2490Sstevel@tonic-gate static int	fchange;
2500Sstevel@tonic-gate static int	nline;
2510Sstevel@tonic-gate static int	fflg, shflg;
2520Sstevel@tonic-gate static char	prompt[16] = "*";
2530Sstevel@tonic-gate static int	rflg;
2540Sstevel@tonic-gate static int	readflg;
2550Sstevel@tonic-gate static int 	eflg;
2560Sstevel@tonic-gate static int 	qflg = 0;
2570Sstevel@tonic-gate static int 	ncflg;
2580Sstevel@tonic-gate static int 	listn;
2590Sstevel@tonic-gate static int 	listf;
2600Sstevel@tonic-gate static int 	pflag;
2610Sstevel@tonic-gate static int 	flag28 = 0; /* Prevents write after a partial read */
2620Sstevel@tonic-gate static int 	save28 = 0; /* Flag whether buffer empty at start of read */
2630Sstevel@tonic-gate static long 	savtime;
2640Sstevel@tonic-gate static char	*name = "SHELL";
2650Sstevel@tonic-gate static char	*rshell = "/usr/lib/rsh";
2660Sstevel@tonic-gate static	char	*shpath; /* pointer to correct shell for execution */
2670Sstevel@tonic-gate 			/* of execlp() */
2680Sstevel@tonic-gate static char	*val;
2690Sstevel@tonic-gate static char	*home;
2700Sstevel@tonic-gate static int	nodelim;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate int	makekey(int *);
2730Sstevel@tonic-gate int	_mbftowc(char *, wchar_t *, int (*)(), int *);
2740Sstevel@tonic-gate static int	error(int code);
2750Sstevel@tonic-gate static void	tlist(struct Fspec *);
2760Sstevel@tonic-gate static void	tstd(struct Fspec *);
2770Sstevel@tonic-gate static void	gdelete(void);
2780Sstevel@tonic-gate static void	delete(void);
2790Sstevel@tonic-gate static void	exfile(void);
2800Sstevel@tonic-gate static void	filename(int comm);
2810Sstevel@tonic-gate static void	newline(void);
2820Sstevel@tonic-gate static int	gettty(void);
2830Sstevel@tonic-gate static void	commands(void);
2840Sstevel@tonic-gate static void	undo(void);
2850Sstevel@tonic-gate static void	save(void);
2860Sstevel@tonic-gate static void	strcopy(char *source, char *dest);
2870Sstevel@tonic-gate static int	strequal(char **scan1, char *str);
2880Sstevel@tonic-gate static int	stdtab(char *, char *);
2890Sstevel@tonic-gate static int	lenchk(char *, struct Fspec *);
2900Sstevel@tonic-gate static void	clear(struct Fspec *);
2910Sstevel@tonic-gate static int	expnd(char *, char *, int *, struct Fspec *);
2920Sstevel@tonic-gate static void	tincr(int, struct Fspec *);
2930Sstevel@tonic-gate static void	targ(struct Fspec *);
2940Sstevel@tonic-gate static int	numb(void);
2950Sstevel@tonic-gate static int	fspec(char *, struct Fspec *, int);
2960Sstevel@tonic-gate static void	red(char *);
2970Sstevel@tonic-gate static void	newtime(void);
2980Sstevel@tonic-gate static void	chktime(void);
2990Sstevel@tonic-gate static void	getime(void);
3000Sstevel@tonic-gate static void	mkfunny(void);
3010Sstevel@tonic-gate static int	eopen(char *, int);
3020Sstevel@tonic-gate static void	eclose(int f);
3030Sstevel@tonic-gate static void	globaln(int);
3040Sstevel@tonic-gate static char	*getkey(const char *);
3050Sstevel@tonic-gate static int	execute(int, LINE);
3060Sstevel@tonic-gate static void	error1(int);
3070Sstevel@tonic-gate static int	getcopy(void);
3080Sstevel@tonic-gate static void	move(int);
3090Sstevel@tonic-gate static void	dosub(void);
3100Sstevel@tonic-gate static int	getsub(void);
3110Sstevel@tonic-gate static int	compsub(void);
3120Sstevel@tonic-gate static void	substitute(int);
3130Sstevel@tonic-gate static void	join(void);
3140Sstevel@tonic-gate static void	global(int);
3150Sstevel@tonic-gate static void	init(void);
3160Sstevel@tonic-gate static void	rdelete(LINE, LINE);
3170Sstevel@tonic-gate static void	append(int (*)(void), LINE);
3180Sstevel@tonic-gate static int	getfile(void);
3190Sstevel@tonic-gate static void	putfile(void);
3200Sstevel@tonic-gate static void	onpipe(int);
3210Sstevel@tonic-gate static void	onhup(int);
3220Sstevel@tonic-gate static void	onintr(int);
3230Sstevel@tonic-gate static void	setdot(void);
3240Sstevel@tonic-gate static void	setall(void);
3250Sstevel@tonic-gate static void	setnoaddr(void);
3260Sstevel@tonic-gate static void	nonzero(void);
3270Sstevel@tonic-gate static void	setzeroasone(void);
3280Sstevel@tonic-gate static long	putline(void);
3290Sstevel@tonic-gate static LINE	address(void);
330*13093SRoger.Faulkner@Oracle.COM static char	*getaline(long);
3310Sstevel@tonic-gate static char	*getblock(long, long);
3320Sstevel@tonic-gate static char	*place(char *, char *, char *);
3330Sstevel@tonic-gate static void	comple(wchar_t);
3340Sstevel@tonic-gate static void	putchr(unsigned char);
3350Sstevel@tonic-gate static void	putwchr(wchar_t);
3360Sstevel@tonic-gate static int	getchr(void);
3370Sstevel@tonic-gate static void	unixcom(void);
3380Sstevel@tonic-gate static void	blkio(int, char *, ssize_t (*)());
3390Sstevel@tonic-gate static void	reverse(LINE, LINE);
3400Sstevel@tonic-gate static void	putd();
3410Sstevel@tonic-gate static wchar_t	get_wchr(void);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate static struct stat	Fl, Tf;
3440Sstevel@tonic-gate #ifndef RESEARCH
3450Sstevel@tonic-gate static struct statvfs	U;
3460Sstevel@tonic-gate static int	Short = 0;
3470Sstevel@tonic-gate static mode_t	oldmask; /* No umask while writing */
3480Sstevel@tonic-gate #endif
3490Sstevel@tonic-gate static jmp_buf	savej;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate #ifdef	NULLS
3520Sstevel@tonic-gate int	nulls;	/* Null count */
3530Sstevel@tonic-gate #endif
3540Sstevel@tonic-gate static long	ccount;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate static int	errcnt = 0;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate static void
onpipe(int sig)3600Sstevel@tonic-gate onpipe(int sig)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	(int)error(0);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate int
main(int argc,char ** argv)3660Sstevel@tonic-gate main(int argc, char **argv)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	char *p1, *p2;
3690Sstevel@tonic-gate 	int c;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3720Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
3730Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
3740Sstevel@tonic-gate #endif
3750Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	oldquit = signal(SIGQUIT, SIG_IGN);
3780Sstevel@tonic-gate 	oldhup = signal(SIGHUP, SIG_IGN);
3790Sstevel@tonic-gate 	oldintr = signal(SIGINT, SIG_IGN);
3800Sstevel@tonic-gate 	oldpipe = signal(SIGPIPE, onpipe);
3810Sstevel@tonic-gate 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
3820Sstevel@tonic-gate 		signal(SIGTERM, quit);
3830Sstevel@tonic-gate 	p1 = *argv;
3840Sstevel@tonic-gate 	while (*p1++);
3850Sstevel@tonic-gate 	while (--p1 >= *argv)
3860Sstevel@tonic-gate 		if (*p1 == '/')
3870Sstevel@tonic-gate 			break;
3880Sstevel@tonic-gate 	*argv = p1 + 1;
3890Sstevel@tonic-gate 	/* if SHELL set in environment and is /usr/lib/rsh, set rflg */
3900Sstevel@tonic-gate 	if ((val = getenv(name)) != NULL)
3910Sstevel@tonic-gate 		if (strcmp(val, rshell) == 0)
3920Sstevel@tonic-gate 			rflg++;
3930Sstevel@tonic-gate 	if (**argv == 'r')
3940Sstevel@tonic-gate 		rflg++;
3950Sstevel@tonic-gate 	home = getenv("HOME");
3960Sstevel@tonic-gate 	while (1) {
3970Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "sp:qxC")) != EOF) {
3980Sstevel@tonic-gate 			switch (c) {
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 			case 's':
4010Sstevel@tonic-gate 				vflag = 0;
4020Sstevel@tonic-gate 				break;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 			case 'p':
4050Sstevel@tonic-gate 				strncpy(prompt, optarg, sizeof (prompt)-1);
4060Sstevel@tonic-gate 				shflg = 1;
4070Sstevel@tonic-gate 				break;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 			case 'q':
4100Sstevel@tonic-gate 				signal(SIGQUIT, SIG_DFL);
4110Sstevel@tonic-gate 				vflag = 1;
4120Sstevel@tonic-gate 				break;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 			case 'x':
4150Sstevel@tonic-gate 				crflag = -1;
4160Sstevel@tonic-gate 				xflag = 1;
4170Sstevel@tonic-gate 				break;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 			case 'C':
4200Sstevel@tonic-gate 				crflag = 1;
4210Sstevel@tonic-gate 				xflag = 1;
4220Sstevel@tonic-gate 				break;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 			case '?':
4250Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
4260Sstevel@tonic-gate 		"Usage:   ed [- | -s] [-p string] [-x] [-C] [file]\n"
4270Sstevel@tonic-gate 		"	  red [- | -s] [-p string] [-x] [-C] [file]\n"));
4280Sstevel@tonic-gate 				exit(2);
4290Sstevel@tonic-gate 			}
4300Sstevel@tonic-gate 		}
4310Sstevel@tonic-gate 		if (argv[optind] && strcmp(argv[optind], "-") == 0 &&
4320Sstevel@tonic-gate 			strcmp(argv[optind-1], "--") != 0) {
4330Sstevel@tonic-gate 			vflag = 0;
4340Sstevel@tonic-gate 			optind++;
4350Sstevel@tonic-gate 			continue;
4360Sstevel@tonic-gate 		}
4370Sstevel@tonic-gate 		break;
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 	argc = argc - optind;
4400Sstevel@tonic-gate 	argv = &argv[optind];
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (xflag) {
4430Sstevel@tonic-gate 		if (permflag)
4440Sstevel@tonic-gate 			crypt_close(perm);
4450Sstevel@tonic-gate 		permflag = 1;
4460Sstevel@tonic-gate 		if ((kflag = run_setkey(&perm[0], getkey(msgtab[66])))
4470Sstevel@tonic-gate 			== -1) {
4480Sstevel@tonic-gate 			puts(gettext(msgtab[64]));
4490Sstevel@tonic-gate 			xflag = 0;
4500Sstevel@tonic-gate 			kflag = 0;
4510Sstevel@tonic-gate 		}
4520Sstevel@tonic-gate 		if (kflag == 0)
4530Sstevel@tonic-gate 			crflag = 0;
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if (argc > 0) {
4570Sstevel@tonic-gate 		p1 = *argv;
4580Sstevel@tonic-gate 		if (strlen(p1) >= (size_t)FNSIZE) {
4590Sstevel@tonic-gate 			puts(gettext("file name too long"));
4600Sstevel@tonic-gate 			if (kflag)
4610Sstevel@tonic-gate 				crypt_close(perm);
4620Sstevel@tonic-gate 			exit(2);
4630Sstevel@tonic-gate 		}
4640Sstevel@tonic-gate 		p2 = savedfile;
4650Sstevel@tonic-gate 		while (*p2++ = *p1++);
4660Sstevel@tonic-gate 		globp = "e";
4670Sstevel@tonic-gate 		fflg++;
4680Sstevel@tonic-gate 	} else 	/* editing with no file so set savtime to 0 */
4690Sstevel@tonic-gate 		savtime = 0;
4700Sstevel@tonic-gate 	eflg++;
4710Sstevel@tonic-gate 	if ((tfname = tempnam("", "ea")) == NULL) {
4720Sstevel@tonic-gate 		puts(gettext(msgtab[69]));
4730Sstevel@tonic-gate 		exit(2);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	fendcore = (LINE)sbrk(0);
4770Sstevel@tonic-gate 	init();
4780Sstevel@tonic-gate 	if (oldintr != SIG_IGN)
4790Sstevel@tonic-gate 		signal(SIGINT, onintr);
4800Sstevel@tonic-gate 	if (oldhup != SIG_IGN)
4810Sstevel@tonic-gate 		signal(SIGHUP, onhup);
4820Sstevel@tonic-gate 	setjmp(savej);
4830Sstevel@tonic-gate 	commands();
4840Sstevel@tonic-gate 	quit(sig);
4850Sstevel@tonic-gate 	return (0);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate static void
commands(void)4890Sstevel@tonic-gate commands(void)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate 	LINE a1;
4920Sstevel@tonic-gate 	int c;
4930Sstevel@tonic-gate 	char *p1, *p2;
4940Sstevel@tonic-gate 	int fsave, m, n;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	for (;;) {
4970Sstevel@tonic-gate 	nodelim = 0;
4980Sstevel@tonic-gate 	if (pflag) {
4990Sstevel@tonic-gate 		pflag = 0;
5000Sstevel@tonic-gate 		addr1 = addr2 = dot;
5010Sstevel@tonic-gate 		goto print;
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 	if (shflg && globp == 0)
5040Sstevel@tonic-gate 		write(1, gettext(prompt), strlen(gettext(prompt)));
5050Sstevel@tonic-gate 	addr1 = 0;
5060Sstevel@tonic-gate 	addr2 = 0;
5070Sstevel@tonic-gate 	if ((c = getchr()) == ',') {
5080Sstevel@tonic-gate 		addr1 = zero + 1;
5090Sstevel@tonic-gate 		addr2 = dol;
5100Sstevel@tonic-gate #ifdef XPG6
5110Sstevel@tonic-gate 	/* XPG4 - it was an error if the second address was */
5120Sstevel@tonic-gate 	/* input and the first address was ommitted	*/
5130Sstevel@tonic-gate 	/* Parse second address	*/
5140Sstevel@tonic-gate 		if ((a1 = address()) != 0) {
5150Sstevel@tonic-gate 			addr2 = a1;
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate #endif
5180Sstevel@tonic-gate 		c = getchr();
5190Sstevel@tonic-gate 		goto swch;
5200Sstevel@tonic-gate 	} else if (c == ';') {
5210Sstevel@tonic-gate 		addr1 = dot;
5220Sstevel@tonic-gate 		addr2 = dol;
5230Sstevel@tonic-gate #ifdef XPG6
5240Sstevel@tonic-gate 	/* XPG4 - it was an error if the second address was */
5250Sstevel@tonic-gate 	/* input and the first address was ommitted	*/
5260Sstevel@tonic-gate 	/* Parse second address	*/
5270Sstevel@tonic-gate 		if ((a1 = address()) != 0) {
5280Sstevel@tonic-gate 			addr2 = a1;
5290Sstevel@tonic-gate 		}
5300Sstevel@tonic-gate #endif
5310Sstevel@tonic-gate 		c = getchr();
5320Sstevel@tonic-gate 		goto swch;
5330Sstevel@tonic-gate 	} else
5340Sstevel@tonic-gate 		peekc = c;
5350Sstevel@tonic-gate 	do {
5360Sstevel@tonic-gate 		addr1 = addr2;
5370Sstevel@tonic-gate 		if ((a1 = address()) == 0) {
5380Sstevel@tonic-gate 			c = getchr();
5390Sstevel@tonic-gate 			break;
5400Sstevel@tonic-gate 		}
5410Sstevel@tonic-gate 		addr2 = a1;
5420Sstevel@tonic-gate 		if ((c = getchr()) == ';') {
5430Sstevel@tonic-gate 			c = ',';
5440Sstevel@tonic-gate 			dot = a1;
5450Sstevel@tonic-gate 		}
5460Sstevel@tonic-gate 	} while (c == ',');
5470Sstevel@tonic-gate 	if (addr1 == 0)
5480Sstevel@tonic-gate 		addr1 = addr2;
5490Sstevel@tonic-gate swch:
5500Sstevel@tonic-gate 	switch (c) {
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	case 'a':
5530Sstevel@tonic-gate 		setdot();
5540Sstevel@tonic-gate 		newline();
5550Sstevel@tonic-gate 		if (!globflg) save();
5560Sstevel@tonic-gate 		append(gettty, addr2);
5570Sstevel@tonic-gate 		continue;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	case 'c':
5600Sstevel@tonic-gate #ifdef XPG6
5610Sstevel@tonic-gate 		setzeroasone();
5620Sstevel@tonic-gate #endif
5630Sstevel@tonic-gate 		delete();
5640Sstevel@tonic-gate 		append(gettty, addr1-1);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		/* XPG4 - If no new lines are inserted, then the current */
5670Sstevel@tonic-gate 		/* line becomes the line after the lines deleted. */
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		if (((linebuf[0] != '.') || (dot == (addr1-1))) &&
5700Sstevel@tonic-gate 			(addr2 <= dol))
5710Sstevel@tonic-gate 			dot = addr1;
5720Sstevel@tonic-gate 		continue;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	case 'd':
5750Sstevel@tonic-gate 		delete();
5760Sstevel@tonic-gate 		continue;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	case 'E':
5790Sstevel@tonic-gate 		fchange = 0;
5800Sstevel@tonic-gate 		c = 'e';
5810Sstevel@tonic-gate 	case 'e':
5820Sstevel@tonic-gate 		fflg++;
5830Sstevel@tonic-gate 		setnoaddr();
5840Sstevel@tonic-gate 		if (vflag && fchange) {
5850Sstevel@tonic-gate 			fchange = 0;
5860Sstevel@tonic-gate 			(void) error(1);
5870Sstevel@tonic-gate 		}
5880Sstevel@tonic-gate 		filename(c);
5890Sstevel@tonic-gate 		eflg++;
5900Sstevel@tonic-gate 		init();
5910Sstevel@tonic-gate 		addr2 = zero;
5920Sstevel@tonic-gate 		goto caseread;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	case 'f':
5950Sstevel@tonic-gate 		setnoaddr();
5960Sstevel@tonic-gate 		filename(c);
5970Sstevel@tonic-gate 		if (!ncflg)  /* there is a filename */
5980Sstevel@tonic-gate 			getime();
5990Sstevel@tonic-gate 		else
6000Sstevel@tonic-gate 			ncflg--;
6010Sstevel@tonic-gate 		puts(savedfile);
6020Sstevel@tonic-gate 		continue;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	case 'g':
6050Sstevel@tonic-gate 		global(1);
6060Sstevel@tonic-gate 		continue;
6070Sstevel@tonic-gate 	case 'G':
6080Sstevel@tonic-gate 		globaln(1);
6090Sstevel@tonic-gate 		continue;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	case 'h':
6120Sstevel@tonic-gate 		newline();
6130Sstevel@tonic-gate 		setnoaddr();
6140Sstevel@tonic-gate 		PUTM();
6150Sstevel@tonic-gate 		continue;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	case 'H':
6180Sstevel@tonic-gate 		newline();
6190Sstevel@tonic-gate 		setnoaddr();
6200Sstevel@tonic-gate 		if (!hflag) {
6210Sstevel@tonic-gate 			hflag = 1;
6220Sstevel@tonic-gate 			PUTM();
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 		else
6250Sstevel@tonic-gate 			hflag = 0;
6260Sstevel@tonic-gate 		continue;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	case 'i':
6290Sstevel@tonic-gate #ifdef XPG6
6300Sstevel@tonic-gate 		setzeroasone();
6310Sstevel@tonic-gate #endif
6320Sstevel@tonic-gate 		setdot();
6330Sstevel@tonic-gate 		nonzero();
6340Sstevel@tonic-gate 		newline();
6350Sstevel@tonic-gate 		if (!globflg) save();
6360Sstevel@tonic-gate 		append(gettty, addr2-1);
6370Sstevel@tonic-gate 		if (dot == addr2-1)
6380Sstevel@tonic-gate 			dot += 1;
6390Sstevel@tonic-gate 		continue;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	case 'j':
6420Sstevel@tonic-gate 		if (addr2 == 0) {
6430Sstevel@tonic-gate 			addr1 = dot;
6440Sstevel@tonic-gate 			addr2 = dot+1;
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 		setdot();
6470Sstevel@tonic-gate 		newline();
6480Sstevel@tonic-gate 		nonzero();
6490Sstevel@tonic-gate 		if (!globflg) save();
6500Sstevel@tonic-gate 		join();
6510Sstevel@tonic-gate 		continue;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	case 'k':
6540Sstevel@tonic-gate 		if ((c = getchr()) < 'a' || c > 'z')
6550Sstevel@tonic-gate 			(void) error(2);
6560Sstevel@tonic-gate 		newline();
6570Sstevel@tonic-gate 		setdot();
6580Sstevel@tonic-gate 		nonzero();
6590Sstevel@tonic-gate 		names[c-'a'] = addr2->cur & ~01;
6600Sstevel@tonic-gate 		anymarks |= 01;
6610Sstevel@tonic-gate 		continue;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	case 'm':
6640Sstevel@tonic-gate 		move(0);
6650Sstevel@tonic-gate 		continue;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	case '\n':
6680Sstevel@tonic-gate 		if (addr2 == 0)
6690Sstevel@tonic-gate 			addr2 = dot+1;
6700Sstevel@tonic-gate 		addr1 = addr2;
6710Sstevel@tonic-gate 		goto print;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	case 'n':
6740Sstevel@tonic-gate 		listn++;
6750Sstevel@tonic-gate 		newline();
6760Sstevel@tonic-gate 		goto print;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	case 'l':
6790Sstevel@tonic-gate 		listf++;
6800Sstevel@tonic-gate 	case 'p':
6810Sstevel@tonic-gate 		newline();
6820Sstevel@tonic-gate 	print:
6830Sstevel@tonic-gate 		setdot();
6840Sstevel@tonic-gate 		nonzero();
6850Sstevel@tonic-gate 		a1 = addr1;
6860Sstevel@tonic-gate 		do {
6870Sstevel@tonic-gate 			if (listn) {
6880Sstevel@tonic-gate 				count = a1 - zero;
6890Sstevel@tonic-gate 				putd();
6900Sstevel@tonic-gate 				putchr('\t');
6910Sstevel@tonic-gate 			}
692*13093SRoger.Faulkner@Oracle.COM 			puts(getaline((a1++)->cur));
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		while (a1 <= addr2);
6950Sstevel@tonic-gate 		dot = addr2;
6960Sstevel@tonic-gate 		pflag = 0;
6970Sstevel@tonic-gate 		listn = 0;
6980Sstevel@tonic-gate 		listf = 0;
6990Sstevel@tonic-gate 		continue;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	case 'Q':
7020Sstevel@tonic-gate 		fchange = 0;
7030Sstevel@tonic-gate 	case 'q':
7040Sstevel@tonic-gate 		setnoaddr();
7050Sstevel@tonic-gate 		newline();
7060Sstevel@tonic-gate 		quit(sig);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	case 'r':
7090Sstevel@tonic-gate 		filename(c);
7100Sstevel@tonic-gate 	caseread:
7110Sstevel@tonic-gate 		readflg = 1;
7120Sstevel@tonic-gate 		save28 = (dol != fendcore);
7130Sstevel@tonic-gate 		if (crflag == 2 || crflag == -2)
7140Sstevel@tonic-gate 			crflag = -1; /* restore crflag for next file */
7150Sstevel@tonic-gate 		errno = 0;
7160Sstevel@tonic-gate 		if ((io = eopen(file, O_RDONLY)) < 0) {
7170Sstevel@tonic-gate 			lastc = '\n';
7180Sstevel@tonic-gate 			/* if first entering editor and file does not exist */
7190Sstevel@tonic-gate 			/* set saved access time to 0 */
7200Sstevel@tonic-gate 			if (eflg) {
7210Sstevel@tonic-gate 				savtime = 0;
7220Sstevel@tonic-gate 				eflg  = 0;
7230Sstevel@tonic-gate 				if (c == 'e' && vflag == 0)
7240Sstevel@tonic-gate 					qflg = 1;
7250Sstevel@tonic-gate 			}
7260Sstevel@tonic-gate 			if (errno == ENOENT) {
7270Sstevel@tonic-gate 				(void) error(68);
7280Sstevel@tonic-gate 			} else {
7290Sstevel@tonic-gate 				(void) error(3);
7300Sstevel@tonic-gate 			}
7310Sstevel@tonic-gate 		}
7320Sstevel@tonic-gate 		/* get last mod time of file */
7330Sstevel@tonic-gate 		/* eflg - entered editor with ed or e  */
7340Sstevel@tonic-gate 		if (eflg) {
7350Sstevel@tonic-gate 			eflg = 0;
7360Sstevel@tonic-gate 			getime();
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 		setall();
7390Sstevel@tonic-gate 		ninbuf = 0;
7400Sstevel@tonic-gate 		n = zero != dol;
7410Sstevel@tonic-gate #ifdef NULLS
7420Sstevel@tonic-gate 		nulls = 0;
7430Sstevel@tonic-gate #endif
7440Sstevel@tonic-gate 		if (!globflg && (c == 'r')) save();
7450Sstevel@tonic-gate 		append(getfile, addr2);
7460Sstevel@tonic-gate 		exfile();
7470Sstevel@tonic-gate 		readflg = 0;
7480Sstevel@tonic-gate 		fchange = n;
7490Sstevel@tonic-gate 		continue;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	case 's':
7520Sstevel@tonic-gate 		setdot();
7530Sstevel@tonic-gate 		nonzero();
7540Sstevel@tonic-gate 		if (!globflg) save();
7550Sstevel@tonic-gate 		substitute(globp != 0);
7560Sstevel@tonic-gate 		continue;
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	case 't':
7590Sstevel@tonic-gate 		move(1);
7600Sstevel@tonic-gate 		continue;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	case 'u':
7630Sstevel@tonic-gate 		setdot();
7640Sstevel@tonic-gate 		newline();
7650Sstevel@tonic-gate 		if (!initflg)
7660Sstevel@tonic-gate 			undo();
7670Sstevel@tonic-gate 		else
7680Sstevel@tonic-gate 			(void) error(5);
7690Sstevel@tonic-gate 		fchange = 1;
7700Sstevel@tonic-gate 		continue;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	case 'v':
7730Sstevel@tonic-gate 		global(0);
7740Sstevel@tonic-gate 		continue;
7750Sstevel@tonic-gate 	case 'V':
7760Sstevel@tonic-gate 		globaln(0);
7770Sstevel@tonic-gate 		continue;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	case 'W':
7800Sstevel@tonic-gate 	case 'w':
7810Sstevel@tonic-gate 		if (flag28) {
7820Sstevel@tonic-gate 			flag28 = 0;
7830Sstevel@tonic-gate 			fchange = 0;
7840Sstevel@tonic-gate 			(void) error(61);
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 		setall();
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 		/* on NULL-RE condition do not generate error */
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		if ((linebuf[0] != '.') && (zero != dol) &&
7910Sstevel@tonic-gate 			(addr1 <= zero || addr2 > dol))
7920Sstevel@tonic-gate 			(void) error(15);
7930Sstevel@tonic-gate 		filename(c);
7940Sstevel@tonic-gate 		if (Xqt) {
7950Sstevel@tonic-gate 			io = eopen(file, O_WRONLY);
7960Sstevel@tonic-gate 			n = 1;	/* set n so newtime will not execute */
7970Sstevel@tonic-gate 		} else {
7980Sstevel@tonic-gate 			struct stat lFl;
7990Sstevel@tonic-gate 			fstat(tfile, &Tf);
8000Sstevel@tonic-gate 			if (stat(file, &Fl) < 0) {
8010Sstevel@tonic-gate 				if ((io = creat(file, S_IRUSR|S_IWUSR|S_IRGRP
8020Sstevel@tonic-gate 					|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
8030Sstevel@tonic-gate 					(void) error(7);
8040Sstevel@tonic-gate 				fstat(io, &Fl);
8050Sstevel@tonic-gate 				Fl.st_mtime = 0;
8060Sstevel@tonic-gate 				lFl = Fl;
8070Sstevel@tonic-gate 				close(io);
8080Sstevel@tonic-gate 			} else {
8090Sstevel@tonic-gate #ifndef	RESEARCH
8100Sstevel@tonic-gate 				oldmask = umask(0);
8110Sstevel@tonic-gate 				/*
8120Sstevel@tonic-gate 				 * Must determine if file is
8130Sstevel@tonic-gate 				 * a symbolic link
8140Sstevel@tonic-gate 				 */
8150Sstevel@tonic-gate 				lstat(file, &lFl);
8160Sstevel@tonic-gate #endif
8170Sstevel@tonic-gate 			}
8180Sstevel@tonic-gate #ifndef RESEARCH
8190Sstevel@tonic-gate 			/*
8200Sstevel@tonic-gate 			 * Determine if there are enough free blocks on system
8210Sstevel@tonic-gate 			 */
8220Sstevel@tonic-gate 			if (!Short && statvfs(file, &U) == 0 &&
8230Sstevel@tonic-gate 			    U.f_bfree < ((Tf.st_size/U.f_frsize) + 100)) {
8240Sstevel@tonic-gate 				Short = 1;
8250Sstevel@tonic-gate 				(void) error(8);
8260Sstevel@tonic-gate 			}
8270Sstevel@tonic-gate 			Short = 0;
8280Sstevel@tonic-gate #endif
8290Sstevel@tonic-gate 			p1 = savedfile;		/* The current filename */
8300Sstevel@tonic-gate 			p2 = file;
8310Sstevel@tonic-gate 			m = strcmp(p1, p2);
8320Sstevel@tonic-gate 			if (c == 'w' && Fl.st_nlink == 1 && ISREG(lFl)) {
8330Sstevel@tonic-gate 				if (close(open(file, O_WRONLY)) < 0)
8340Sstevel@tonic-gate 					(void) error(9);
8350Sstevel@tonic-gate 				if (!(n = m))
8360Sstevel@tonic-gate 					chktime();
8370Sstevel@tonic-gate 				mkfunny();
8380Sstevel@tonic-gate 				/*
8390Sstevel@tonic-gate 				 * If funlink equals one it means that
8400Sstevel@tonic-gate 				 * funny points to a valid file which must
8410Sstevel@tonic-gate 				 * be unlinked when interrupted.
8420Sstevel@tonic-gate 				 */
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 				funlink = 1;
8450Sstevel@tonic-gate 				if ((io = creat(funny, FMODE(Fl))) >= 0) {
8460Sstevel@tonic-gate 					chown(funny, Fl.st_uid, Fl.st_gid);
8470Sstevel@tonic-gate 					chmod(funny, FMODE(Fl));
8480Sstevel@tonic-gate 					putfile();
8490Sstevel@tonic-gate 					exfile();
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 					if (rename(funny, file))
8520Sstevel@tonic-gate 						(void) error(10);
8530Sstevel@tonic-gate 					funlink = 0;
8540Sstevel@tonic-gate 					/* if filenames are the same */
8550Sstevel@tonic-gate 					if (!n)
8560Sstevel@tonic-gate 						newtime();
8570Sstevel@tonic-gate 					/* check if entire buffer was written */
8580Sstevel@tonic-gate 					fsave = fchange;
8590Sstevel@tonic-gate 		fchange = (((addr1 == zero) || (addr1 == (zero + 1))) &&
8600Sstevel@tonic-gate 			(addr2 == dol)) ? 0 : 1;
8610Sstevel@tonic-gate 			if (fchange == 1 && m != 0) fchange = fsave;
8620Sstevel@tonic-gate 					continue;
8630Sstevel@tonic-gate 				}
8640Sstevel@tonic-gate 			} else
8650Sstevel@tonic-gate 				n = 1;	/* set n so newtime will not execute */
8660Sstevel@tonic-gate 			if ((io = open(file,
8670Sstevel@tonic-gate 				(c == 'w') ? O_WRONLY|O_CREAT|O_TRUNC
8680Sstevel@tonic-gate 				: O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR
8690Sstevel@tonic-gate 				|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
8700Sstevel@tonic-gate 				(void) error(7);
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate 		putfile();
8730Sstevel@tonic-gate 		exfile();
8740Sstevel@tonic-gate 		if (!n) newtime();
8750Sstevel@tonic-gate 		fsave = fchange;
8760Sstevel@tonic-gate 		fchange = (((addr1 == zero) || (addr1 == (zero + 1))) &&
8770Sstevel@tonic-gate 			(addr2 == dol)) ? 0 : 1;
8780Sstevel@tonic-gate 	/* Leave fchange alone if partial write was to another file */
8790Sstevel@tonic-gate 		if (fchange == 1 && m != 0) fchange = fsave;
8800Sstevel@tonic-gate 		continue;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	case 'C':
8830Sstevel@tonic-gate 		crflag = 1;
8840Sstevel@tonic-gate 			/*
8850Sstevel@tonic-gate 			 * C is same as X, but always assume input files are
8860Sstevel@tonic-gate 			 * ciphertext
8870Sstevel@tonic-gate 			 */
8880Sstevel@tonic-gate 		goto encrypt;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	case 'X':
8910Sstevel@tonic-gate 		crflag = -1;
8920Sstevel@tonic-gate encrypt:
8930Sstevel@tonic-gate 		setnoaddr();
8940Sstevel@tonic-gate 		newline();
8950Sstevel@tonic-gate 		xflag = 1;
8960Sstevel@tonic-gate 		if (permflag)
8970Sstevel@tonic-gate 			(void) crypt_close(perm);
8980Sstevel@tonic-gate 		permflag = 1;
8990Sstevel@tonic-gate 		if ((kflag = run_setkey(&perm[0], getkey(msgtab[66])))
9000Sstevel@tonic-gate 			== -1) {
9010Sstevel@tonic-gate 			xflag = 0;
9020Sstevel@tonic-gate 			kflag = 0;
9030Sstevel@tonic-gate 			crflag = 0;
9040Sstevel@tonic-gate 			(void) error(64);
9050Sstevel@tonic-gate 		}
9060Sstevel@tonic-gate 		if (kflag == 0)
9070Sstevel@tonic-gate 			crflag = 0;
9080Sstevel@tonic-gate 		continue;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	case '=':
9110Sstevel@tonic-gate 		setall();
9120Sstevel@tonic-gate 		newline();
9130Sstevel@tonic-gate 		count = (addr2-zero)&077777;
9140Sstevel@tonic-gate 		putd();
9150Sstevel@tonic-gate 		putchr('\n');
9160Sstevel@tonic-gate 		continue;
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	case '!':
9190Sstevel@tonic-gate 		unixcom();
9200Sstevel@tonic-gate 		continue;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	case EOF:
9230Sstevel@tonic-gate 		return;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	case 'P':
9260Sstevel@tonic-gate 		setnoaddr();
9270Sstevel@tonic-gate 		newline();
9280Sstevel@tonic-gate 		if (shflg)
9290Sstevel@tonic-gate 			shflg = 0;
9300Sstevel@tonic-gate 		else
9310Sstevel@tonic-gate 			shflg++;
9320Sstevel@tonic-gate 		continue;
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate 	if (c == 'x')
9350Sstevel@tonic-gate 		(void) error(60);
9360Sstevel@tonic-gate 	else
9370Sstevel@tonic-gate 		(void) error(12);
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate LINE
address(void)9420Sstevel@tonic-gate address(void)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate 	int minus, c;
9450Sstevel@tonic-gate 	LINE a1;
9460Sstevel@tonic-gate 	int n, relerr, retval;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	minus = 0;
9490Sstevel@tonic-gate 	a1 = 0;
9500Sstevel@tonic-gate 	for (;;) {
9510Sstevel@tonic-gate 		c = getchr();
9520Sstevel@tonic-gate 		if ('0' <= c && c <= '9') {
9530Sstevel@tonic-gate 			n = 0;
9540Sstevel@tonic-gate 			do {
9550Sstevel@tonic-gate 				n *= 10;
9560Sstevel@tonic-gate 				n += c - '0';
9570Sstevel@tonic-gate 			} while ((c = getchr()) >= '0' && c <= '9');
9580Sstevel@tonic-gate 			peekc = c;
9590Sstevel@tonic-gate 			if (a1 == 0)
9600Sstevel@tonic-gate 				a1 = zero;
9610Sstevel@tonic-gate 			if (minus < 0)
9620Sstevel@tonic-gate 				n = -n;
9630Sstevel@tonic-gate 			a1 += n;
9640Sstevel@tonic-gate 			minus = 0;
9650Sstevel@tonic-gate 			continue;
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 		relerr = 0;
9680Sstevel@tonic-gate 		if (a1 || minus)
9690Sstevel@tonic-gate 			relerr++;
9700Sstevel@tonic-gate 		switch (c) {
9710Sstevel@tonic-gate 		case ' ':
9720Sstevel@tonic-gate 		case '\t':
9730Sstevel@tonic-gate 			continue;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		case '+':
9760Sstevel@tonic-gate 			minus++;
9770Sstevel@tonic-gate 			if (a1 == 0)
9780Sstevel@tonic-gate 				a1 = dot;
9790Sstevel@tonic-gate 			continue;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 		case '-':
9820Sstevel@tonic-gate 		case '^':
9830Sstevel@tonic-gate 			minus--;
9840Sstevel@tonic-gate 			if (a1 == 0)
9850Sstevel@tonic-gate 				a1 = dot;
9860Sstevel@tonic-gate 			continue;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		case '?':
9890Sstevel@tonic-gate 		case '/':
9900Sstevel@tonic-gate 			comple(c);
9910Sstevel@tonic-gate 			a1 = dot;
9920Sstevel@tonic-gate 			for (;;) {
9930Sstevel@tonic-gate 				if (c == '/') {
9940Sstevel@tonic-gate 					a1++;
9950Sstevel@tonic-gate 					if (a1 > dol)
9960Sstevel@tonic-gate 						a1 = zero;
9970Sstevel@tonic-gate 				} else {
9980Sstevel@tonic-gate 					a1--;
9990Sstevel@tonic-gate 					if (a1 < zero)
10000Sstevel@tonic-gate 						a1 = dol;
10010Sstevel@tonic-gate 				}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 				if (execute(0, a1))
10040Sstevel@tonic-gate 					break;
10050Sstevel@tonic-gate 				if (a1 == dot)
10060Sstevel@tonic-gate 					(void) error(13);
10070Sstevel@tonic-gate 			}
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 		case '$':
10110Sstevel@tonic-gate 			a1 = dol;
10120Sstevel@tonic-gate 			break;
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 		case '.':
10150Sstevel@tonic-gate 			a1 = dot;
10160Sstevel@tonic-gate 			break;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		case '\'':
10190Sstevel@tonic-gate 			if ((c = getchr()) < 'a' || c > 'z')
10200Sstevel@tonic-gate 				(void) error(2);
10210Sstevel@tonic-gate 			for (a1 = zero; a1 <= dol; a1++)
10220Sstevel@tonic-gate 				if (names[c-'a'] == (a1->cur & ~01))
10230Sstevel@tonic-gate 					break;
10240Sstevel@tonic-gate 			break;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		default:
10270Sstevel@tonic-gate 			peekc = c;
10280Sstevel@tonic-gate 			if (a1 == 0)
10290Sstevel@tonic-gate 				return (0);
10300Sstevel@tonic-gate 			a1 += minus;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 			/* on NULL-RE condition do not generate error */
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 			if ((linebuf[0] != '.') && (a1 < zero || a1 > dol))
10350Sstevel@tonic-gate 				(void) error(15);
10360Sstevel@tonic-gate 			return (a1);
10370Sstevel@tonic-gate 		}
10380Sstevel@tonic-gate 		if (relerr)
10390Sstevel@tonic-gate 			(void) error(16);
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate static void
setdot(void)10440Sstevel@tonic-gate setdot(void)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	if (addr2 == 0)
10470Sstevel@tonic-gate 		addr1 = addr2 = dot;
10480Sstevel@tonic-gate 	if (addr1 > addr2)
10490Sstevel@tonic-gate 		(void) error(17);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate static void
setall(void)10530Sstevel@tonic-gate setall(void)
10540Sstevel@tonic-gate {
10550Sstevel@tonic-gate 	if (addr2 == 0) {
10560Sstevel@tonic-gate 		addr1 = zero+1;
10570Sstevel@tonic-gate 		addr2 = dol;
10580Sstevel@tonic-gate 		if (dol == zero)
10590Sstevel@tonic-gate 			addr1 = zero;
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 	setdot();
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate static void
setnoaddr(void)10650Sstevel@tonic-gate setnoaddr(void)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	if (addr2)
10680Sstevel@tonic-gate 		(void) error(18);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate static void
nonzero(void)10720Sstevel@tonic-gate nonzero(void)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate 	/* on NULL-RE condition do not generate error */
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	if ((linebuf[0] != '.') && (addr1 <= zero || addr2 > dol))
10770Sstevel@tonic-gate 		(void) error(15);
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate static void
setzeroasone(void)10810Sstevel@tonic-gate setzeroasone(void)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate /* for the c and i commands 0 equal to 1 address */
10840Sstevel@tonic-gate 	if (addr1 == zero) {
10850Sstevel@tonic-gate 		addr1 = zero+1;
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate 	if (addr2 == zero) {
10880Sstevel@tonic-gate 		addr2 = zero+1;
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate static void
newline(void)10940Sstevel@tonic-gate newline(void)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	int c;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if ((c = getchr()) == '\n')
10990Sstevel@tonic-gate 		return;
11000Sstevel@tonic-gate 	if (c == 'p' || c == 'l' || c == 'n') {
11010Sstevel@tonic-gate 		pflag++;
11020Sstevel@tonic-gate 		if (c == 'l') listf++;
11030Sstevel@tonic-gate 		if (c == 'n') listn++;
11040Sstevel@tonic-gate 		if ((c = getchr()) == '\n')
11050Sstevel@tonic-gate 			return;
11060Sstevel@tonic-gate 	}
11070Sstevel@tonic-gate 	(void) error(20);
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate static void
filename(int comm)11110Sstevel@tonic-gate filename(int comm)
11120Sstevel@tonic-gate {
11130Sstevel@tonic-gate 	char *p1, *p2;
11140Sstevel@tonic-gate 	int c;
11150Sstevel@tonic-gate 	int i = 0;
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	count = 0;
11180Sstevel@tonic-gate 	c = getchr();
11190Sstevel@tonic-gate 	if (c == '\n' || c == EOF) {
11200Sstevel@tonic-gate 		p1 = savedfile;
11210Sstevel@tonic-gate 		if (*p1 == 0 && comm != 'f')
11220Sstevel@tonic-gate 			(void) error(21);
11230Sstevel@tonic-gate 		/* ncflg set means do not get mod time of file */
11240Sstevel@tonic-gate 		/* since no filename followed f */
11250Sstevel@tonic-gate 		if (comm == 'f')
11260Sstevel@tonic-gate 			ncflg++;
11270Sstevel@tonic-gate 		p2 = file;
11280Sstevel@tonic-gate 		while (*p2++ = *p1++);
11290Sstevel@tonic-gate 		red(savedfile);
11300Sstevel@tonic-gate 		return;
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 	if (c != ' ')
11330Sstevel@tonic-gate 		(void) error(22);
11340Sstevel@tonic-gate 	while ((c = getchr()) == ' ');
11350Sstevel@tonic-gate 	if (c == '!')
11360Sstevel@tonic-gate 		++Xqt, c = getchr();
11370Sstevel@tonic-gate 	if (c == '\n')
11380Sstevel@tonic-gate 		(void) error(21);
11390Sstevel@tonic-gate 	p1 = file;
11400Sstevel@tonic-gate 	do {
11410Sstevel@tonic-gate 		if (++i >= FNSIZE)
11420Sstevel@tonic-gate 			(void) error(24);
11430Sstevel@tonic-gate 		*p1++ = c;
11440Sstevel@tonic-gate 		if (c == EOF || (c == ' ' && !Xqt))
11450Sstevel@tonic-gate 			(void) error(21);
11460Sstevel@tonic-gate 	} while ((c = getchr()) != '\n');
11470Sstevel@tonic-gate 	*p1++ = 0;
11480Sstevel@tonic-gate 	if (Xqt)
11490Sstevel@tonic-gate 		if (comm == 'f') {
11500Sstevel@tonic-gate 			--Xqt;
11510Sstevel@tonic-gate 			(void) error(57);
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 		else
11540Sstevel@tonic-gate 			return;
11550Sstevel@tonic-gate 	if (savedfile[0] == 0 || comm == 'e' || comm == 'f') {
11560Sstevel@tonic-gate 		p1 = savedfile;
11570Sstevel@tonic-gate 		p2 = file;
11580Sstevel@tonic-gate 		while (*p1++ = *p2++);
11590Sstevel@tonic-gate 	}
11600Sstevel@tonic-gate 	red(file);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate static void
exfile(void)11650Sstevel@tonic-gate exfile(void)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate #ifdef NULLS
11680Sstevel@tonic-gate 	int c;
11690Sstevel@tonic-gate #endif
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate #ifndef RESEARCH
11720Sstevel@tonic-gate 	if (oldmask) {
11730Sstevel@tonic-gate 		umask(oldmask);
11740Sstevel@tonic-gate 		oldmask = 0;
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate #endif
11770Sstevel@tonic-gate 	eclose(io);
11780Sstevel@tonic-gate 	io = -1;
11790Sstevel@tonic-gate 	if (vflag) {
11800Sstevel@tonic-gate 		putd();
11810Sstevel@tonic-gate 		putchr('\n');
11820Sstevel@tonic-gate #ifdef NULLS
11830Sstevel@tonic-gate 		if (nulls) {
11840Sstevel@tonic-gate 			c = count;
11850Sstevel@tonic-gate 			count = nulls;
11860Sstevel@tonic-gate 			nulls = 0;
11870Sstevel@tonic-gate 			putd();
11880Sstevel@tonic-gate 			puts(gettext(" nulls replaced by '\\0'"));
11890Sstevel@tonic-gate 			count = c;
11900Sstevel@tonic-gate 		}
11910Sstevel@tonic-gate #endif
11920Sstevel@tonic-gate 	}
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate static void
onintr(int sig)11960Sstevel@tonic-gate onintr(int sig)
11970Sstevel@tonic-gate {
11980Sstevel@tonic-gate 	signal(SIGINT, onintr);
11990Sstevel@tonic-gate 	putchr('\n');
12000Sstevel@tonic-gate 	lastc = '\n';
12010Sstevel@tonic-gate 	globflg = 0;
12020Sstevel@tonic-gate 	if (funlink) unlink(funny); /* remove tmp file */
12030Sstevel@tonic-gate 	/* if interrupted a read, only part of file may be in buffer */
12040Sstevel@tonic-gate 	if (readflg) {
12050Sstevel@tonic-gate 		sprintf(tstring, "\007read may be incomplete - beware!\007");
12060Sstevel@tonic-gate 		puts(gettext(tstring));
12070Sstevel@tonic-gate 		fchange = 0;
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 	(void) error(26);
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate static void
onhup(int sig)12130Sstevel@tonic-gate onhup(int sig)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
12160Sstevel@tonic-gate 	signal(SIGHUP, SIG_IGN);
12170Sstevel@tonic-gate 	/*
12180Sstevel@tonic-gate 	 * if there are lines in file and file was not written
12190Sstevel@tonic-gate 	 * since last update, save in ed.hup, or $HOME/ed.hup
12200Sstevel@tonic-gate 	 */
12210Sstevel@tonic-gate 	if (dol > zero && fchange == 1) {
12220Sstevel@tonic-gate 		addr1 = zero+1;
12230Sstevel@tonic-gate 		addr2 = dol;
12240Sstevel@tonic-gate 		io = creat("ed.hup",
12250Sstevel@tonic-gate 			S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
12260Sstevel@tonic-gate 		if (io < 0 && home) {
12270Sstevel@tonic-gate 			char	*fn;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 			fn = (char *)calloc(strlen(home) + 8, sizeof (char));
12300Sstevel@tonic-gate 			if (fn) {
12310Sstevel@tonic-gate 				strcpy(fn, home);
12320Sstevel@tonic-gate 				strcat(fn, "/ed.hup");
12330Sstevel@tonic-gate 				io = creat(fn, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
12340Sstevel@tonic-gate 						|S_IROTH|S_IWOTH);
12350Sstevel@tonic-gate 				free(fn);
12360Sstevel@tonic-gate 			}
12370Sstevel@tonic-gate 		}
12380Sstevel@tonic-gate 		if (io > 0)
12390Sstevel@tonic-gate 			putfile();
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 	fchange = 0;
12420Sstevel@tonic-gate 	++errcnt;
12430Sstevel@tonic-gate 	quit(sig);
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate static int
error(int code)12470Sstevel@tonic-gate error(int code)
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate 	int c;
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	if (code == 28 && save28 == 0) {
12520Sstevel@tonic-gate 		fchange = 0;
12530Sstevel@tonic-gate 		flag28++;
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 	readflg = 0;
12560Sstevel@tonic-gate 	++errcnt;
12570Sstevel@tonic-gate 	listf = listn = 0;
12580Sstevel@tonic-gate 	pflag = 0;
12590Sstevel@tonic-gate #ifndef RESEARCH
12600Sstevel@tonic-gate 	if (oldmask) {
12610Sstevel@tonic-gate 		umask(oldmask);
12620Sstevel@tonic-gate 		oldmask = 0;
12630Sstevel@tonic-gate 	}
12640Sstevel@tonic-gate #endif
12650Sstevel@tonic-gate #ifdef NULLS	/* Not really nulls, but close enough */
12660Sstevel@tonic-gate 	/* This is a bug because of buffering */
12670Sstevel@tonic-gate 	if (code == 28) /* illegal char. */
12680Sstevel@tonic-gate 		putd();
12690Sstevel@tonic-gate #endif
12700Sstevel@tonic-gate 	/* Cant open file or file does not exist */
12710Sstevel@tonic-gate 	if ((code == 3) || (code == 68)) {
12720Sstevel@tonic-gate 		if (qflg == 0) {
12730Sstevel@tonic-gate 			putchr('?');
12740Sstevel@tonic-gate 			puts(file);
12750Sstevel@tonic-gate 		}
12760Sstevel@tonic-gate 		else
12770Sstevel@tonic-gate 			qflg = 0;
12780Sstevel@tonic-gate 	}
12790Sstevel@tonic-gate 	else
12800Sstevel@tonic-gate 	{
12810Sstevel@tonic-gate 		putchr('?');
12820Sstevel@tonic-gate 		putchr('\n');
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 	count = 0;
12850Sstevel@tonic-gate 	lseek(0, (long)0, 2);
12860Sstevel@tonic-gate 	if (globp)
12870Sstevel@tonic-gate 		lastc = '\n';
12880Sstevel@tonic-gate 	globp = 0;
12890Sstevel@tonic-gate 	peekc = lastc;
12900Sstevel@tonic-gate 	if (lastc)
12910Sstevel@tonic-gate 		while ((c = getchr()) != '\n' && c != EOF);
12920Sstevel@tonic-gate 	if (io) {
12930Sstevel@tonic-gate 		eclose(io);
12940Sstevel@tonic-gate 		io = -1;
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 	xcode = code;
12970Sstevel@tonic-gate 	if (hflag)
12980Sstevel@tonic-gate 		PUTM();
12990Sstevel@tonic-gate 	if (code == 4)
13000Sstevel@tonic-gate 		return (0);	/* Non-fatal error. */
13010Sstevel@tonic-gate 	longjmp(savej, 1);
13020Sstevel@tonic-gate 	/* NOTREACHED */
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate static int
getchr(void)13060Sstevel@tonic-gate getchr(void)
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate 	char c;
13090Sstevel@tonic-gate 	if (lastc = peekc) {
13100Sstevel@tonic-gate 		peekc = 0;
13110Sstevel@tonic-gate 		return (lastc);
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 	if (globp) {
13140Sstevel@tonic-gate 		if ((lastc = (unsigned char)*globp++) != 0)
13150Sstevel@tonic-gate 			return (lastc);
13160Sstevel@tonic-gate 		globp = 0;
13170Sstevel@tonic-gate 		return (EOF);
13180Sstevel@tonic-gate 	}
13190Sstevel@tonic-gate 	if (read(0, &c, 1) <= 0)
13200Sstevel@tonic-gate 		return (lastc = EOF);
13210Sstevel@tonic-gate 	lastc = (unsigned char)c;
13220Sstevel@tonic-gate 	return (lastc);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate static int
gettty(void)13260Sstevel@tonic-gate gettty(void)
13270Sstevel@tonic-gate {
13280Sstevel@tonic-gate 	int c;
13290Sstevel@tonic-gate 	char *gf;
13300Sstevel@tonic-gate 	char *p;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	p = linebuf;
13330Sstevel@tonic-gate 	gf = globp;
13340Sstevel@tonic-gate 	while ((c = getchr()) != '\n') {
13350Sstevel@tonic-gate 		if (c == EOF) {
13360Sstevel@tonic-gate 			if (gf)
13370Sstevel@tonic-gate 				peekc = c;
13380Sstevel@tonic-gate 			return (c);
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 		if (c == 0)
13410Sstevel@tonic-gate 			continue;
13420Sstevel@tonic-gate 		*p++ = c;
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 		if (p > &linebuf[LBSIZE-1])
13450Sstevel@tonic-gate 			(void) error(27);
13460Sstevel@tonic-gate 	}
13470Sstevel@tonic-gate 	*p++ = 0;
13480Sstevel@tonic-gate 	if (linebuf[0] == '.' && linebuf[1] == 0)
13490Sstevel@tonic-gate 		return (EOF);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	/*
13520Sstevel@tonic-gate 	 * POSIX.2/XPG4 explicitly says no to this:
13530Sstevel@tonic-gate 	 *
13540Sstevel@tonic-gate 	 * in Solaris backslash followed by special character "." is
13550Sstevel@tonic-gate 	 * special character "." itself; (so terminating input mode can be
13560Sstevel@tonic-gate 	 * "\.\n").
13570Sstevel@tonic-gate 	 *
13580Sstevel@tonic-gate 	 * however, POSIX2/XPG4 says, input mode is terminated by
13590Sstevel@tonic-gate 	 * entering line consisting of only 2 characters: ".\n"
13600Sstevel@tonic-gate 	 *
13610Sstevel@tonic-gate 	 * if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) {
13620Sstevel@tonic-gate 	 *	linebuf[0] = '.';
13630Sstevel@tonic-gate 	 *	linebuf[1] = 0;
13640Sstevel@tonic-gate 	 * }
13650Sstevel@tonic-gate 	 */
13660Sstevel@tonic-gate 	return (0);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate static int
getfile(void)13700Sstevel@tonic-gate getfile(void)
13710Sstevel@tonic-gate {
13720Sstevel@tonic-gate 	char c;
13730Sstevel@tonic-gate 	char *lp, *fp;
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 	lp = linebuf;
13760Sstevel@tonic-gate 	fp = nextip;
13770Sstevel@tonic-gate 	do {
13780Sstevel@tonic-gate 		if (--ninbuf < 0) {
13790Sstevel@tonic-gate 			if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
13800Sstevel@tonic-gate 				if (lp > linebuf) {
13810Sstevel@tonic-gate 					puts(gettext("'\\n' appended"));
13820Sstevel@tonic-gate 					*genbuf = '\n';
13830Sstevel@tonic-gate 				}
13840Sstevel@tonic-gate 				else
13850Sstevel@tonic-gate 					return (EOF);
13860Sstevel@tonic-gate 			if (crflag == -1) {
13870Sstevel@tonic-gate 				if (isencrypt(genbuf, ninbuf + 1))
13880Sstevel@tonic-gate 					crflag = 2;
13890Sstevel@tonic-gate 				else
13900Sstevel@tonic-gate 					crflag = -2;
13910Sstevel@tonic-gate 			}
13920Sstevel@tonic-gate 			fp = genbuf;
13930Sstevel@tonic-gate 			if (crflag > 0)
13940Sstevel@tonic-gate 			if (run_crypt(count, genbuf, ninbuf+1, perm) == -1)
13950Sstevel@tonic-gate 				(void) error(63);
13960Sstevel@tonic-gate 		}
13970Sstevel@tonic-gate 		if (lp >= &linebuf[LBSIZE]) {
13980Sstevel@tonic-gate 			lastc = '\n';
13990Sstevel@tonic-gate 			(void) error(27);
14000Sstevel@tonic-gate 		}
14010Sstevel@tonic-gate 		if ((*lp++ = c = *fp++) == 0) {
14020Sstevel@tonic-gate #ifdef NULLS
14030Sstevel@tonic-gate 			lp[-1] = '\\';
14040Sstevel@tonic-gate 			*lp++ = '0';
14050Sstevel@tonic-gate 			nulls++;
14060Sstevel@tonic-gate #else
14070Sstevel@tonic-gate 			lp--;
14080Sstevel@tonic-gate 			continue;
14090Sstevel@tonic-gate #endif
14100Sstevel@tonic-gate 		}
14110Sstevel@tonic-gate 		count++;
14120Sstevel@tonic-gate 	} while (c != '\n');
14130Sstevel@tonic-gate 	*--lp = 0;
14140Sstevel@tonic-gate 	nextip = fp;
14150Sstevel@tonic-gate 	if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
14160Sstevel@tonic-gate 		write(1, gettext("line too long: lno = "),
14170Sstevel@tonic-gate 			strlen(gettext("line too long: lno = ")));
14180Sstevel@tonic-gate 		ccount = count;
14190Sstevel@tonic-gate 		count = (++dot-zero)&077777;
14200Sstevel@tonic-gate 		dot--;
14210Sstevel@tonic-gate 		putd();
14220Sstevel@tonic-gate 		count = ccount;
14230Sstevel@tonic-gate 		putchr('\n');
14240Sstevel@tonic-gate 	}
14250Sstevel@tonic-gate 	return (0);
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate static void
putfile(void)14290Sstevel@tonic-gate putfile(void)
14300Sstevel@tonic-gate {
14310Sstevel@tonic-gate 	int n;
14320Sstevel@tonic-gate 	LINE a1;
14330Sstevel@tonic-gate 	char *fp, *lp;
14340Sstevel@tonic-gate 	int nib;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	nib = LBSIZE;
14370Sstevel@tonic-gate 	fp = genbuf;
14380Sstevel@tonic-gate 	a1 = addr1;
14390Sstevel@tonic-gate 	do {
1440*13093SRoger.Faulkner@Oracle.COM 		lp = getaline(a1++->cur);
14410Sstevel@tonic-gate 		if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
14420Sstevel@tonic-gate 			write(1, gettext("line too long: lno = "),
14430Sstevel@tonic-gate 				strlen(gettext("line too long: lno = ")));
14440Sstevel@tonic-gate 			ccount = count;
14450Sstevel@tonic-gate 			count = (a1-zero-1)&077777;
14460Sstevel@tonic-gate 			putd();
14470Sstevel@tonic-gate 			count = ccount;
14480Sstevel@tonic-gate 			putchr('\n');
14490Sstevel@tonic-gate 		}
14500Sstevel@tonic-gate 		for (;;) {
14510Sstevel@tonic-gate 			if (--nib < 0) {
14520Sstevel@tonic-gate 				n = fp-genbuf;
14530Sstevel@tonic-gate 				if (kflag)
14540Sstevel@tonic-gate 				if (run_crypt(count-n, genbuf, n, perm) == -1)
14550Sstevel@tonic-gate 					(void) error(63);
14560Sstevel@tonic-gate 				if (write(io, genbuf, n) != n)
14570Sstevel@tonic-gate 					(void) error(29);
14580Sstevel@tonic-gate 				nib = LBSIZE - 1;
14590Sstevel@tonic-gate 				fp = genbuf;
14600Sstevel@tonic-gate 			}
14610Sstevel@tonic-gate 			if (dol->cur == 0L)break; /* Allow write of null file */
14620Sstevel@tonic-gate 			count++;
14630Sstevel@tonic-gate 			if ((*fp++ = *lp++) == 0) {
14640Sstevel@tonic-gate 				fp[-1] = '\n';
14650Sstevel@tonic-gate 				break;
14660Sstevel@tonic-gate 			}
14670Sstevel@tonic-gate 		}
14680Sstevel@tonic-gate 	} while (a1 <= addr2);
14690Sstevel@tonic-gate 	n = fp-genbuf;
14700Sstevel@tonic-gate 	if (kflag)
14710Sstevel@tonic-gate 		if (run_crypt(count-n, genbuf, n, perm) == -1)
14720Sstevel@tonic-gate 			(void) error(63);
14730Sstevel@tonic-gate 	if (write(io, genbuf, n) != n)
14740Sstevel@tonic-gate 		(void) error(29);
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate static void
append(int (* f)(void),LINE a)14780Sstevel@tonic-gate append(int (*f)(void), LINE a)
14790Sstevel@tonic-gate {
14800Sstevel@tonic-gate 	LINE a1, a2, rdot;
14810Sstevel@tonic-gate 	long tl;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	nline = 0;
14840Sstevel@tonic-gate 	dot = a;
14850Sstevel@tonic-gate 	while ((*f)() == 0) {
14860Sstevel@tonic-gate 		if (dol >= endcore) {
14870Sstevel@tonic-gate 			if ((int)sbrk(512 * sizeof (struct lin)) == -1) {
14880Sstevel@tonic-gate 				lastc = '\n';
14890Sstevel@tonic-gate 				(void) error(30);
14900Sstevel@tonic-gate 			}
14910Sstevel@tonic-gate 			endcore += 512;
14920Sstevel@tonic-gate 		}
14930Sstevel@tonic-gate 		tl = putline();
14940Sstevel@tonic-gate 		nline++;
14950Sstevel@tonic-gate 		a1 = ++dol;
14960Sstevel@tonic-gate 		a2 = a1+1;
14970Sstevel@tonic-gate 		rdot = ++dot;
14980Sstevel@tonic-gate 		while (a1 > rdot)
14990Sstevel@tonic-gate 			(--a2)->cur = (--a1)->cur;
15000Sstevel@tonic-gate 		rdot->cur = tl;
15010Sstevel@tonic-gate 	}
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate static void
unixcom(void)15050Sstevel@tonic-gate unixcom(void)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate 	void (*savint)();
15080Sstevel@tonic-gate 	pid_t	pid, rpid;
15090Sstevel@tonic-gate 	int retcode;
15100Sstevel@tonic-gate 	static char savcmd[LBSIZE];	/* last command */
15110Sstevel@tonic-gate 	char curcmd[LBSIZE];		/* current command */
15120Sstevel@tonic-gate 	char *psavcmd, *pcurcmd, *psavedfile;
15130Sstevel@tonic-gate 	int endflg = 1, shflg = 0;
15140Sstevel@tonic-gate 	wchar_t	c;
15150Sstevel@tonic-gate 	int	len;
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	setnoaddr();
15180Sstevel@tonic-gate 	if (rflg)
15190Sstevel@tonic-gate 		(void) error(6);
15200Sstevel@tonic-gate 	pcurcmd = curcmd;
15210Sstevel@tonic-gate 	/* read command til end */
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	/*
15240Sstevel@tonic-gate 	 * a '!' found in beginning of command is replaced with the saved
15250Sstevel@tonic-gate 	 * command.  a '%' found in command is replaced with the current
15260Sstevel@tonic-gate 	 * filename
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	c = getchr();
15300Sstevel@tonic-gate 	if (c == '!') {
15310Sstevel@tonic-gate 		if (savcmd[0] == 0)
15320Sstevel@tonic-gate 			(void) error(56);
15330Sstevel@tonic-gate 		else {
15340Sstevel@tonic-gate 			psavcmd = savcmd;
15350Sstevel@tonic-gate 			while (*pcurcmd++ = *psavcmd++);
15360Sstevel@tonic-gate 			--pcurcmd;
15370Sstevel@tonic-gate 			shflg = 1;
15380Sstevel@tonic-gate 		}
15390Sstevel@tonic-gate 	} else
15400Sstevel@tonic-gate 		UNGETC(c);  /* put c back */
15410Sstevel@tonic-gate 	while (endflg == 1) {
15420Sstevel@tonic-gate 		while ((c = get_wchr()) != '\n' && c != '%' && c != '\\') {
15430Sstevel@tonic-gate 			if ((len = wctomb(pcurcmd, c)) <= 0) {
15440Sstevel@tonic-gate 				*pcurcmd = (unsigned char)c;
15450Sstevel@tonic-gate 				len = 1;
15460Sstevel@tonic-gate 			}
15470Sstevel@tonic-gate 			pcurcmd += len;
15480Sstevel@tonic-gate 		}
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 		if (c == '%') {
15510Sstevel@tonic-gate 			if (savedfile[0] == 0)
15520Sstevel@tonic-gate 				(void) error(21);
15530Sstevel@tonic-gate 			else {
15540Sstevel@tonic-gate 				psavedfile = savedfile;
15550Sstevel@tonic-gate 				while (pcurcmd < curcmd + LBSIZE &&
15560Sstevel@tonic-gate 					(*pcurcmd++ = *psavedfile++));
15570Sstevel@tonic-gate 				--pcurcmd;
15580Sstevel@tonic-gate 				shflg = 1;
15590Sstevel@tonic-gate 			}
15600Sstevel@tonic-gate 		} else if (c == '\\') {
15610Sstevel@tonic-gate 			c = get_wchr();
15620Sstevel@tonic-gate 			if (c != '%')
15630Sstevel@tonic-gate 				*pcurcmd++ = '\\';
15640Sstevel@tonic-gate 			if ((len = wctomb(pcurcmd, c)) <= 0) {
15650Sstevel@tonic-gate 				*pcurcmd = (unsigned char)c;
15660Sstevel@tonic-gate 				len = 1;
15670Sstevel@tonic-gate 			}
15680Sstevel@tonic-gate 			pcurcmd += len;
15690Sstevel@tonic-gate 		}
15700Sstevel@tonic-gate 		else
15710Sstevel@tonic-gate 			/* end of command hit */
15720Sstevel@tonic-gate 			endflg = 0;
15730Sstevel@tonic-gate 	}
15740Sstevel@tonic-gate 	*pcurcmd++ = 0;
15750Sstevel@tonic-gate 	if (shflg == 1)
15760Sstevel@tonic-gate 		puts(curcmd);
15770Sstevel@tonic-gate 	/* save command */
15780Sstevel@tonic-gate 	strcpy(savcmd, curcmd);
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	if ((pid = fork()) == 0) {
15810Sstevel@tonic-gate 		signal(SIGHUP, oldhup);
15820Sstevel@tonic-gate 		signal(SIGQUIT, oldquit);
15830Sstevel@tonic-gate 		close(tfile);
15840Sstevel@tonic-gate 		if (__xpg4 == 0) {	/* not XPG4 */
15850Sstevel@tonic-gate 			shpath = "/usr/bin/sh";
15860Sstevel@tonic-gate 		} else {
15870Sstevel@tonic-gate 			/* XPG4 */
15880Sstevel@tonic-gate 			shpath = "/usr/xpg4/bin/sh";
15890Sstevel@tonic-gate 		}
15900Sstevel@tonic-gate 		execlp((const char *)shpath, "sh", "-c", curcmd, (char *)0);
15910Sstevel@tonic-gate 		exit(0100);
15920Sstevel@tonic-gate 	}
15930Sstevel@tonic-gate 	savint = signal(SIGINT, SIG_IGN);
15940Sstevel@tonic-gate 	while ((rpid = wait(&retcode)) != pid && rpid != (pid_t)-1);
15950Sstevel@tonic-gate 	signal(SIGINT, savint);
15960Sstevel@tonic-gate 	if (vflag) puts("!");
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate static void
quit(int sig)16000Sstevel@tonic-gate quit(int sig)
16010Sstevel@tonic-gate {
16020Sstevel@tonic-gate 	if (vflag && fchange) {
16030Sstevel@tonic-gate 		fchange = 0;
16040Sstevel@tonic-gate 		if (flag28) {
16050Sstevel@tonic-gate 			flag28 = 0;
16060Sstevel@tonic-gate 			(void) error(62);
16070Sstevel@tonic-gate 		}
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 		/*
16100Sstevel@tonic-gate 		 * For case where user reads in BOTH a good
16110Sstevel@tonic-gate 		 * file & a bad file
16120Sstevel@tonic-gate 		 */
16130Sstevel@tonic-gate 		(void) error(1);
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 	unlink(tfname);
16160Sstevel@tonic-gate 	if (kflag)
16170Sstevel@tonic-gate 		crypt_close(perm);
16180Sstevel@tonic-gate 	if (xtflag)
16190Sstevel@tonic-gate 		crypt_close(tperm);
16200Sstevel@tonic-gate 	exit(errcnt? 2: 0);
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate static void
delete(void)16240Sstevel@tonic-gate delete(void)
16250Sstevel@tonic-gate {
16260Sstevel@tonic-gate 	setdot();
16270Sstevel@tonic-gate 	newline();
16280Sstevel@tonic-gate 	nonzero();
16290Sstevel@tonic-gate 	if (!globflg) save();
16300Sstevel@tonic-gate 	rdelete(addr1, addr2);
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate static void
rdelete(LINE ad1,LINE ad2)16340Sstevel@tonic-gate rdelete(LINE ad1, LINE ad2)
16350Sstevel@tonic-gate {
16360Sstevel@tonic-gate 	LINE a1, a2, a3;
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	a1 = ad1;
16390Sstevel@tonic-gate 	a2 = ad2+1;
16400Sstevel@tonic-gate 	a3 = dol;
16410Sstevel@tonic-gate 	dol -= a2 - a1;
16420Sstevel@tonic-gate 	do
16430Sstevel@tonic-gate 		(a1++)->cur = (a2++)->cur;
16440Sstevel@tonic-gate 	while (a2 <= a3);
16450Sstevel@tonic-gate 	a1 = ad1;
16460Sstevel@tonic-gate 	if (a1 > dol)
16470Sstevel@tonic-gate 		a1 = dol;
16480Sstevel@tonic-gate 	dot = a1;
16490Sstevel@tonic-gate 	fchange = 1;
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate static void
gdelete(void)16530Sstevel@tonic-gate gdelete(void)
16540Sstevel@tonic-gate {
16550Sstevel@tonic-gate 	LINE a1, a2, a3;
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	a3 = dol;
16580Sstevel@tonic-gate 	for (a1 = zero+1; (a1->cur&01) == 0; a1++)
16590Sstevel@tonic-gate 		if (a1 >= a3)
16600Sstevel@tonic-gate 			return;
16610Sstevel@tonic-gate 	for (a2 = a1 + 1; a2 <= a3; ) {
16620Sstevel@tonic-gate 		if (a2->cur & 01) {
16630Sstevel@tonic-gate 			a2++;
16640Sstevel@tonic-gate 			dot = a1;
16650Sstevel@tonic-gate 		} else
16660Sstevel@tonic-gate 			(a1++)->cur = (a2++)->cur;
16670Sstevel@tonic-gate 	}
16680Sstevel@tonic-gate 	dol = a1-1;
16690Sstevel@tonic-gate 	if (dot > dol)
16700Sstevel@tonic-gate 		dot = dol;
16710Sstevel@tonic-gate 	fchange = 1;
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate static char *
getaline(long tl)1675*13093SRoger.Faulkner@Oracle.COM getaline(long tl)
16760Sstevel@tonic-gate {
16770Sstevel@tonic-gate 	char *bp, *lp;
16780Sstevel@tonic-gate 	int nl;
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	lp = linebuf;
16810Sstevel@tonic-gate 	bp = getblock(tl, READ);
16820Sstevel@tonic-gate 	nl = nleft;
16830Sstevel@tonic-gate 	tl &= ~0377;
16840Sstevel@tonic-gate 	while (*lp++ = *bp++)
16850Sstevel@tonic-gate 		if (--nl == 0) {
16860Sstevel@tonic-gate 			bp = getblock(tl += 0400, READ);
16870Sstevel@tonic-gate 			nl = nleft;
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 	return (linebuf);
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate static long
putline(void)16930Sstevel@tonic-gate putline(void)
16940Sstevel@tonic-gate {
16950Sstevel@tonic-gate 	char *bp, *lp;
16960Sstevel@tonic-gate 	int nl;
16970Sstevel@tonic-gate 	long tl;
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	fchange = 1;
17000Sstevel@tonic-gate 	lp = linebuf;
17010Sstevel@tonic-gate 	tl = tline;
17020Sstevel@tonic-gate 	bp = getblock(tl, WRITE);
17030Sstevel@tonic-gate 	nl = nleft;
17040Sstevel@tonic-gate 	tl &= ~0377;
17050Sstevel@tonic-gate 	while (*bp = *lp++) {
17060Sstevel@tonic-gate 		if (*bp++ == '\n') {
17070Sstevel@tonic-gate 			*--bp = 0;
17080Sstevel@tonic-gate 			linebp = lp;
17090Sstevel@tonic-gate 			break;
17100Sstevel@tonic-gate 		}
17110Sstevel@tonic-gate 		if (--nl == 0) {
17120Sstevel@tonic-gate 			bp = getblock(tl += 0400, WRITE);
17130Sstevel@tonic-gate 			nl = nleft;
17140Sstevel@tonic-gate 		}
17150Sstevel@tonic-gate 	}
17160Sstevel@tonic-gate 	nl = tline;
17170Sstevel@tonic-gate 	tline += (((lp-linebuf)+03)>>1)&077776;
17180Sstevel@tonic-gate 	return (nl);
17190Sstevel@tonic-gate }
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate static char *
getblock(long atl,long iof)17220Sstevel@tonic-gate getblock(long atl, long iof)
17230Sstevel@tonic-gate {
17240Sstevel@tonic-gate 	int bno, off;
17250Sstevel@tonic-gate 	char *p1, *p2;
17260Sstevel@tonic-gate 	int n;
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	bno = atl >> 8;
17290Sstevel@tonic-gate 	off = (atl<<1)&0774;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/* bno is limited to 16 bits */
17320Sstevel@tonic-gate 	if (bno >= 65535) {
17330Sstevel@tonic-gate 		lastc = '\n';
17340Sstevel@tonic-gate 		(void) error(31);
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate 	nleft = 512 - off;
17370Sstevel@tonic-gate 	if (bno == iblock) {
17380Sstevel@tonic-gate 		ichanged |= iof;
17390Sstevel@tonic-gate 		return (ibuff+off);
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate 	if (bno == oblock)
17420Sstevel@tonic-gate 		return (obuff+off);
17430Sstevel@tonic-gate 	if (iof == READ) {
17440Sstevel@tonic-gate 		if (ichanged) {
17450Sstevel@tonic-gate 			if (xtflag)
17460Sstevel@tonic-gate 				if (run_crypt(0L, ibuff, 512, tperm) == -1)
17470Sstevel@tonic-gate 					(void) error(63);
17480Sstevel@tonic-gate 			blkio(iblock, ibuff, write);
17490Sstevel@tonic-gate 		}
17500Sstevel@tonic-gate 		ichanged = 0;
17510Sstevel@tonic-gate 		iblock = bno;
17520Sstevel@tonic-gate 		blkio(bno, ibuff, read);
17530Sstevel@tonic-gate 		if (xtflag)
17540Sstevel@tonic-gate 			if (run_crypt(0L, ibuff, 512, tperm) == -1)
17550Sstevel@tonic-gate 				(void) error(63);
17560Sstevel@tonic-gate 		return (ibuff+off);
17570Sstevel@tonic-gate 	}
17580Sstevel@tonic-gate 	if (oblock >= 0) {
17590Sstevel@tonic-gate 		if (xtflag) {
17600Sstevel@tonic-gate 			p1 = obuff;
17610Sstevel@tonic-gate 			p2 = crbuf;
17620Sstevel@tonic-gate 			n = 512;
17630Sstevel@tonic-gate 			while (n--)
17640Sstevel@tonic-gate 				*p2++ = *p1++;
17650Sstevel@tonic-gate 			if (run_crypt(0L, crbuf, 512, tperm) == -1)
17660Sstevel@tonic-gate 				(void) error(63);
17670Sstevel@tonic-gate 			blkio(oblock, crbuf, write);
17680Sstevel@tonic-gate 		} else
17690Sstevel@tonic-gate 			blkio(oblock, obuff, write);
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 	oblock = bno;
17720Sstevel@tonic-gate 	return (obuff+off);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate static void
blkio(int b,char * buf,ssize_t (* iofcn)())17760Sstevel@tonic-gate blkio(int b, char *buf, ssize_t (*iofcn)())
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate 	lseek(tfile, (long)b<<9, 0);
17790Sstevel@tonic-gate 	if ((*iofcn)(tfile, buf, 512) != 512) {
17800Sstevel@tonic-gate 		if (dol != zero)
17810Sstevel@tonic-gate 			(void) error(32); /* Bypass this if writing null file */
17820Sstevel@tonic-gate 	}
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate static void
init(void)17860Sstevel@tonic-gate init(void)
17870Sstevel@tonic-gate {
17880Sstevel@tonic-gate 	long *markp;
17890Sstevel@tonic-gate 	mode_t omask;
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	if (tfile != -1) {
17920Sstevel@tonic-gate 		(void) close(tfile);
17930Sstevel@tonic-gate 		(void) unlink(tfname);
17940Sstevel@tonic-gate 	}
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	tline = 2;
17970Sstevel@tonic-gate 	for (markp = names; markp < &names[26]; )
17980Sstevel@tonic-gate 		*markp++ = 0L;
17990Sstevel@tonic-gate 	subnewa = 0L;
18000Sstevel@tonic-gate 	anymarks = 0;
18010Sstevel@tonic-gate 	iblock = -1;
18020Sstevel@tonic-gate 	oblock = -1;
18030Sstevel@tonic-gate 	ichanged = 0;
18040Sstevel@tonic-gate 	initflg = 1;
18050Sstevel@tonic-gate 	omask = umask(0);
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 	if ((tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR,
18080Sstevel@tonic-gate 	    S_IRUSR|S_IWUSR)) < 0) {
18090Sstevel@tonic-gate 		puts(gettext(msgtab[70]));
18100Sstevel@tonic-gate 		exit(2);
18110Sstevel@tonic-gate 	}
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	umask(omask);
18140Sstevel@tonic-gate 	if (xflag) {
18150Sstevel@tonic-gate 		xtflag = 1;
18160Sstevel@tonic-gate 		if (tpermflag)
18170Sstevel@tonic-gate 			(void) crypt_close(tperm);
18180Sstevel@tonic-gate 		tpermflag = 1;
18190Sstevel@tonic-gate 		if (makekey(tperm)) {
18200Sstevel@tonic-gate 			xtflag = 0;
18210Sstevel@tonic-gate 			puts(gettext(msgtab[65]));
18220Sstevel@tonic-gate 		}
18230Sstevel@tonic-gate 	}
18240Sstevel@tonic-gate 	brk((char *)fendcore);
18250Sstevel@tonic-gate 	dot = zero = dol = savdot = savdol = fendcore;
18260Sstevel@tonic-gate 	flag28 = save28 = 0;
18270Sstevel@tonic-gate 	endcore = fendcore - sizeof (struct lin);
18280Sstevel@tonic-gate }
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate static void
global(int k)18310Sstevel@tonic-gate global(int k)
18320Sstevel@tonic-gate {
18330Sstevel@tonic-gate 	char *gp;
18340Sstevel@tonic-gate 	wchar_t l;
18350Sstevel@tonic-gate 	char multic[MB_LEN_MAX];
18360Sstevel@tonic-gate 	wchar_t c;
18370Sstevel@tonic-gate 	LINE a1;
18380Sstevel@tonic-gate 	char globuf[LBSIZE];
18390Sstevel@tonic-gate 	int n;
18400Sstevel@tonic-gate 	int	len;
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	if (globp)
18430Sstevel@tonic-gate 		(void) error(33);
18440Sstevel@tonic-gate 	setall();
18450Sstevel@tonic-gate 	nonzero();
18460Sstevel@tonic-gate 	if ((n = _mbftowc(multic, &l, getchr, &peekc)) <= 0)
18470Sstevel@tonic-gate 		(void) error(67);
18480Sstevel@tonic-gate 	if (l == '\n')
18490Sstevel@tonic-gate 		(void) error(19);
18500Sstevel@tonic-gate 	save();
18510Sstevel@tonic-gate 	comple(l);
18520Sstevel@tonic-gate 	gp = globuf;
18530Sstevel@tonic-gate 	while ((c = get_wchr()) != '\n') {
18540Sstevel@tonic-gate 		if (c == EOF)
18550Sstevel@tonic-gate 			(void) error(19);
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 		/* '\\' has special meaning only if preceding a '\n' */
18580Sstevel@tonic-gate 		if (c == '\\') {
18590Sstevel@tonic-gate 			c = get_wchr();
18600Sstevel@tonic-gate 			if (c != '\n')
18610Sstevel@tonic-gate 				*gp++ = '\\';
18620Sstevel@tonic-gate 		}
18630Sstevel@tonic-gate 		if ((gp + (unsigned int)MB_CUR_MAX) >= &globuf[LBSIZE-1])
18640Sstevel@tonic-gate 			(void) error(34);
18650Sstevel@tonic-gate 		if ((len = wctomb(gp, c)) <= 0) {
18660Sstevel@tonic-gate 			*gp = (unsigned char)c;
18670Sstevel@tonic-gate 			len = 1;
18680Sstevel@tonic-gate 		}
18690Sstevel@tonic-gate 		gp += len;
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 	if (gp == globuf)
18720Sstevel@tonic-gate 		*gp++ = 'p';
18730Sstevel@tonic-gate 	*gp++ = '\n';
18740Sstevel@tonic-gate 	*gp++ = 0;
18750Sstevel@tonic-gate 	for (a1 = zero; a1 <= dol; a1++) {
18760Sstevel@tonic-gate 		a1->cur &= ~01;
18770Sstevel@tonic-gate 		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
18780Sstevel@tonic-gate 			a1->cur |= 01;
18790Sstevel@tonic-gate 	}
18800Sstevel@tonic-gate 	/*
18810Sstevel@tonic-gate 	 * Special case: g/.../d (avoid n^2 algorithm)
18820Sstevel@tonic-gate 	 */
18830Sstevel@tonic-gate 	if (globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == '\0') {
18840Sstevel@tonic-gate 		gdelete();
18850Sstevel@tonic-gate 		return;
18860Sstevel@tonic-gate 	}
18870Sstevel@tonic-gate 	for (a1 = zero; a1 <= dol; a1++) {
18880Sstevel@tonic-gate 		if (a1->cur & 01) {
18890Sstevel@tonic-gate 			a1->cur &= ~01;
18900Sstevel@tonic-gate 			dot = a1;
18910Sstevel@tonic-gate 			globp = globuf;
18920Sstevel@tonic-gate 			globflg = 1;
18930Sstevel@tonic-gate 			commands();
18940Sstevel@tonic-gate 			globflg = 0;
18950Sstevel@tonic-gate 			a1 = zero;
18960Sstevel@tonic-gate 		}
18970Sstevel@tonic-gate 	}
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate static void
join(void)19010Sstevel@tonic-gate join(void)
19020Sstevel@tonic-gate {
19030Sstevel@tonic-gate 	char *gp, *lp;
19040Sstevel@tonic-gate 	LINE a1;
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	if (addr1 == addr2)
19070Sstevel@tonic-gate 		return;
19080Sstevel@tonic-gate 	gp = genbuf;
19090Sstevel@tonic-gate 	for (a1 = addr1; a1 <= addr2; a1++) {
1910*13093SRoger.Faulkner@Oracle.COM 		lp = getaline(a1->cur);
19110Sstevel@tonic-gate 		while (*gp = *lp++)
19120Sstevel@tonic-gate 			if (gp++ > &genbuf[LBSIZE-1])
19130Sstevel@tonic-gate 				(void) error(27);
19140Sstevel@tonic-gate 	}
19150Sstevel@tonic-gate 	lp = linebuf;
19160Sstevel@tonic-gate 	gp = genbuf;
19170Sstevel@tonic-gate 	while (*lp++ = *gp++);
19180Sstevel@tonic-gate 	addr1->cur = putline();
19190Sstevel@tonic-gate 	if (addr1 < addr2)
19200Sstevel@tonic-gate 		rdelete(addr1+1, addr2);
19210Sstevel@tonic-gate 	dot = addr1;
19220Sstevel@tonic-gate }
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate static void
substitute(int inglob)19250Sstevel@tonic-gate substitute(int inglob)
19260Sstevel@tonic-gate {
19270Sstevel@tonic-gate 	int nl;
19280Sstevel@tonic-gate 	LINE a1;
19290Sstevel@tonic-gate 	long *markp;
19300Sstevel@tonic-gate 	int ingsav;		/* For saving arg. */
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	ingsav = inglob;
19330Sstevel@tonic-gate 	ocerr2 = 0;
19340Sstevel@tonic-gate 	gsubf = compsub();
19350Sstevel@tonic-gate 	for (a1 = addr1; a1 <= addr2; a1++) {
19360Sstevel@tonic-gate 		if (execute(0, a1) == 0)
19370Sstevel@tonic-gate 			continue;
19380Sstevel@tonic-gate 		numpass = 0;
19390Sstevel@tonic-gate 		ocerr1 = 0;
19400Sstevel@tonic-gate 		inglob |= 01;
19410Sstevel@tonic-gate 		dosub();
19420Sstevel@tonic-gate 		if (gsubf) {
19430Sstevel@tonic-gate 			while (*loc2) {
19440Sstevel@tonic-gate 				if (execute(1, (LINE)0) == 0)
19450Sstevel@tonic-gate 					break;
19460Sstevel@tonic-gate 				dosub();
19470Sstevel@tonic-gate 			}
19480Sstevel@tonic-gate 		}
19490Sstevel@tonic-gate 		if (ocerr1 == 0)continue;	/* Don't put out-not changed. */
19500Sstevel@tonic-gate 		subnewa = putline();
19510Sstevel@tonic-gate 		a1->cur &= ~01;
19520Sstevel@tonic-gate 		if (anymarks) {
19530Sstevel@tonic-gate 			for (markp = names; markp < &names[26]; markp++)
19540Sstevel@tonic-gate 				if (*markp == a1->cur)
19550Sstevel@tonic-gate 					*markp = subnewa;
19560Sstevel@tonic-gate 		}
19570Sstevel@tonic-gate 		a1->cur = subnewa;
19580Sstevel@tonic-gate 		append(getsub, a1);
19590Sstevel@tonic-gate 		nl = nline;
19600Sstevel@tonic-gate 		a1 += nl;
19610Sstevel@tonic-gate 		addr2 += nl;
19620Sstevel@tonic-gate 	}
19630Sstevel@tonic-gate 	if (ingsav)
19640Sstevel@tonic-gate 		return;	/* Was in global-no error msg allowed. */
19650Sstevel@tonic-gate 	if (inglob == 0)
19660Sstevel@tonic-gate 		(void) error(35);	/* Not in global, but not found. */
19670Sstevel@tonic-gate 	if (ocerr2 == 0)
19680Sstevel@tonic-gate 		(void) error(35); /* RE found, but occurrence match failed. */
19690Sstevel@tonic-gate }
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate static int
compsub(void)19720Sstevel@tonic-gate compsub(void)
19730Sstevel@tonic-gate {
19740Sstevel@tonic-gate 	int c;
19750Sstevel@tonic-gate 	wchar_t seof;
19760Sstevel@tonic-gate 	char *p;
19770Sstevel@tonic-gate 	char multic[MB_LEN_MAX];
19780Sstevel@tonic-gate 	int n;
19790Sstevel@tonic-gate 	static char remem[RHSIZE];
19800Sstevel@tonic-gate 	static int remflg = -1;
19810Sstevel@tonic-gate 	int i;
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	if ((n = _mbftowc(multic, &seof, getchr, &peekc)) <= 0)
19840Sstevel@tonic-gate 		(void) error(67);
19850Sstevel@tonic-gate 	if (seof == '\n' || seof == ' ')
19860Sstevel@tonic-gate 		(void) error(36);
19870Sstevel@tonic-gate 	comple(seof);
19880Sstevel@tonic-gate 	p = rhsbuf;
19890Sstevel@tonic-gate 	for (;;) {
19900Sstevel@tonic-gate 		wchar_t cl;
19910Sstevel@tonic-gate 		if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
19920Sstevel@tonic-gate 			(void) error(67);
19930Sstevel@tonic-gate 		if (cl == '\\') {
19940Sstevel@tonic-gate 			*p++ = '\\';
19950Sstevel@tonic-gate 			if (p >= &rhsbuf[RHSIZE])
19960Sstevel@tonic-gate 				(void) error(38);
19970Sstevel@tonic-gate 			if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
19980Sstevel@tonic-gate 				(void) error(67);
19990Sstevel@tonic-gate 		} else if (cl == '\n') {
20000Sstevel@tonic-gate 			if (nodelim == 1) {
20010Sstevel@tonic-gate 				nodelim = 0;
20020Sstevel@tonic-gate 				(void) error(36);
20030Sstevel@tonic-gate 			}
20040Sstevel@tonic-gate 			if (!(globp && globp[0])) {
20050Sstevel@tonic-gate 				UNGETC('\n');
20060Sstevel@tonic-gate 				pflag++;
20070Sstevel@tonic-gate 				break;
20080Sstevel@tonic-gate 			}
20090Sstevel@tonic-gate 		} else if (cl == seof)
20100Sstevel@tonic-gate 			break;
20110Sstevel@tonic-gate 		if (p + n > &rhsbuf[RHSIZE])
20120Sstevel@tonic-gate 			(void) error(38);
20130Sstevel@tonic-gate 		(void) strncpy(p, multic, n);
20140Sstevel@tonic-gate 		p += n;
20150Sstevel@tonic-gate 	}
20160Sstevel@tonic-gate 	*p++ = 0;
20170Sstevel@tonic-gate 	if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
20180Sstevel@tonic-gate 		/*
20190Sstevel@tonic-gate 		 * If there isn't a remembered string, it is an error;
20200Sstevel@tonic-gate 		 * otherwise the right hand side is the previous right
20210Sstevel@tonic-gate 		 * hand side.
20220Sstevel@tonic-gate 		 */
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 		if (remflg == -1)
20250Sstevel@tonic-gate 			(void) error(55);
20260Sstevel@tonic-gate 		else
20270Sstevel@tonic-gate 			strcpy(rhsbuf, remem);
20280Sstevel@tonic-gate 	else {
20290Sstevel@tonic-gate 		strcpy(remem, rhsbuf);
20300Sstevel@tonic-gate 		remflg = 0;
20310Sstevel@tonic-gate 	}
20320Sstevel@tonic-gate 	c = 0;
20330Sstevel@tonic-gate 	peekc = getchr();	/* Gets char after third delimiter. */
20340Sstevel@tonic-gate 	if (peekc == 'g') {
20350Sstevel@tonic-gate 		c = LBSIZE; peekc = 0;
20360Sstevel@tonic-gate 	}
20370Sstevel@tonic-gate 	if (peekc >= '1' && peekc <= '9') {
20380Sstevel@tonic-gate 		c = peekc-'0';
20390Sstevel@tonic-gate 		peekc = 0;	/* Allows getchr() to get next char. */
20400Sstevel@tonic-gate 		while (1) {
20410Sstevel@tonic-gate 			i = getchr();
20420Sstevel@tonic-gate 			if (i < '0' || i > '9')
20430Sstevel@tonic-gate 				break;
20440Sstevel@tonic-gate 			c = c*10 + i-'0';
20450Sstevel@tonic-gate 			if (c > LBSIZE-1)
20460Sstevel@tonic-gate 				(void) error(20);	/* "Illegal suffix" */
20470Sstevel@tonic-gate 			}
20480Sstevel@tonic-gate 		peekc = i;	/* Effectively an unget. */
20490Sstevel@tonic-gate 		}
20500Sstevel@tonic-gate 	newline();
20510Sstevel@tonic-gate 	return (c);
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	/*
20540Sstevel@tonic-gate 	 * Returns occurrence value. 0 & 1 both do first occurrence
20550Sstevel@tonic-gate 	 * only: c = 0 if ordinary substitute; c = 1
20560Sstevel@tonic-gate 	 * if use 1 in global sub(s/a/b/1). 0 in global form is illegal.
20570Sstevel@tonic-gate 	 */
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate static int
getsub(void)20610Sstevel@tonic-gate getsub(void)
20620Sstevel@tonic-gate {
20630Sstevel@tonic-gate 	char *p1, *p2;
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	p1 = linebuf;
20660Sstevel@tonic-gate 	if ((p2 = linebp) == 0)
20670Sstevel@tonic-gate 		return (EOF);
20680Sstevel@tonic-gate 	while (*p1++ = *p2++);
20690Sstevel@tonic-gate 	linebp = 0;
20700Sstevel@tonic-gate 	return (0);
20710Sstevel@tonic-gate }
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate static void
dosub(void)20740Sstevel@tonic-gate dosub(void)
20750Sstevel@tonic-gate {
20760Sstevel@tonic-gate 	char *lp, *sp, *rp;
20770Sstevel@tonic-gate 	int c;
20780Sstevel@tonic-gate 
20790Sstevel@tonic-gate 	if (gsubf > 0 && gsubf < LBSIZE) {
20800Sstevel@tonic-gate 		numpass++;
20810Sstevel@tonic-gate 		if (gsubf != numpass)
20820Sstevel@tonic-gate 			return;
20830Sstevel@tonic-gate 	}
20840Sstevel@tonic-gate 	ocerr1++;
20850Sstevel@tonic-gate 	ocerr2++;
20860Sstevel@tonic-gate 	lp = linebuf;
20870Sstevel@tonic-gate 	sp = genbuf;
20880Sstevel@tonic-gate 	rp = rhsbuf;
20890Sstevel@tonic-gate 	while (lp < loc1)
20900Sstevel@tonic-gate 		*sp++ = *lp++;
20910Sstevel@tonic-gate 	while (c = *rp++) {
20920Sstevel@tonic-gate 		if (c == '&') {
20930Sstevel@tonic-gate 			sp = place(sp, loc1, loc2);
20940Sstevel@tonic-gate 			continue;
20950Sstevel@tonic-gate 		} else if (c == '\\') {
20960Sstevel@tonic-gate 			c = *rp++;
20970Sstevel@tonic-gate 			if (c >= '1' && c < nbra + '1') {
20980Sstevel@tonic-gate 			sp = place(sp, braslist[c-'1'], braelist[c-'1']);
20990Sstevel@tonic-gate 				continue;
21000Sstevel@tonic-gate 			}
21010Sstevel@tonic-gate 		}
21020Sstevel@tonic-gate 		*sp++ = c;
21030Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
21040Sstevel@tonic-gate 			(void) error(27);
21050Sstevel@tonic-gate 	}
21060Sstevel@tonic-gate 	lp = loc2;
21070Sstevel@tonic-gate 	loc2 = sp - genbuf + linebuf;
21080Sstevel@tonic-gate 	while (*sp++ = *lp++)
21090Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
21100Sstevel@tonic-gate 			(void) error(27);
21110Sstevel@tonic-gate 	lp = linebuf;
21120Sstevel@tonic-gate 	sp = genbuf;
21130Sstevel@tonic-gate 	while (*lp++ = *sp++);
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate static char *
place(char * sp,char * l1,char * l2)21170Sstevel@tonic-gate place(char *sp, char *l1, char *l2)
21180Sstevel@tonic-gate {
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 	while (l1 < l2) {
21210Sstevel@tonic-gate 		*sp++ = *l1++;
21220Sstevel@tonic-gate 		if (sp >= &genbuf[LBSIZE])
21230Sstevel@tonic-gate 			(void) error(27);
21240Sstevel@tonic-gate 	}
21250Sstevel@tonic-gate 	return (sp);
21260Sstevel@tonic-gate }
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate static void
comple(wchar_t seof)21290Sstevel@tonic-gate comple(wchar_t seof)
21300Sstevel@tonic-gate {
21310Sstevel@tonic-gate 	int cclass = 0;
21320Sstevel@tonic-gate 	wchar_t c;
21330Sstevel@tonic-gate 	int n;
21340Sstevel@tonic-gate 	char *cp = genbuf;
21350Sstevel@tonic-gate 	char multic[MB_LEN_MAX];
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 	while (1) {
21380Sstevel@tonic-gate 		if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
21390Sstevel@tonic-gate 			error1(67);
21400Sstevel@tonic-gate 		if (n == 0 || c == '\n') {
21410Sstevel@tonic-gate 			if (cclass)
21420Sstevel@tonic-gate 				error1(49);
21430Sstevel@tonic-gate 			else
21440Sstevel@tonic-gate 				break;
21450Sstevel@tonic-gate 		}
21460Sstevel@tonic-gate 		if (c == seof && !cclass)
21470Sstevel@tonic-gate 			break;
21480Sstevel@tonic-gate 		if (cclass && c == ']') {
21490Sstevel@tonic-gate 			cclass = 0;
21500Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE-1])
21510Sstevel@tonic-gate 				error1(50);
21520Sstevel@tonic-gate 			*cp++ = ']';
21530Sstevel@tonic-gate 			continue;
21540Sstevel@tonic-gate 		}
21550Sstevel@tonic-gate 		if (c == '[' && !cclass) {
21560Sstevel@tonic-gate 			cclass = 1;
21570Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE-1])
21580Sstevel@tonic-gate 				error1(50);
21590Sstevel@tonic-gate 			*cp++ = '[';
21600Sstevel@tonic-gate 			if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
21610Sstevel@tonic-gate 				error1(67);
21620Sstevel@tonic-gate 			if (n == 0 || c == '\n')
21630Sstevel@tonic-gate 				error1(49);
21640Sstevel@tonic-gate 		}
21650Sstevel@tonic-gate 		if (c == '\\' && !cclass) {
21660Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE-1])
21670Sstevel@tonic-gate 				error1(50);
21680Sstevel@tonic-gate 			*cp++ = '\\';
21690Sstevel@tonic-gate 			if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
21700Sstevel@tonic-gate 				error1(67);
21710Sstevel@tonic-gate 			if (n == 0 || c == '\n')
21720Sstevel@tonic-gate 				error1(36);
21730Sstevel@tonic-gate 		}
21740Sstevel@tonic-gate 		if (cp + n > &genbuf[LBSIZE-1])
21750Sstevel@tonic-gate 			error1(50);
21760Sstevel@tonic-gate 		(void) strncpy(cp, multic, n);
21770Sstevel@tonic-gate 		cp += n;
21780Sstevel@tonic-gate 	}
21790Sstevel@tonic-gate 	*cp = '\0';
21800Sstevel@tonic-gate 	if (n != 0 && c == '\n')
21810Sstevel@tonic-gate 		UNGETC('\n');
21820Sstevel@tonic-gate 	if (n == 0 || c == '\n')
21830Sstevel@tonic-gate 		nodelim = 1;
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	/*
21860Sstevel@tonic-gate 	 * NULL RE: do not compile a null regular expression; but process
21870Sstevel@tonic-gate 	 * input with last regular expression encountered
21880Sstevel@tonic-gate 	 */
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	if (genbuf[0] != '\0') {
21910Sstevel@tonic-gate 		if (expbuf)
21920Sstevel@tonic-gate 			free(expbuf);
21930Sstevel@tonic-gate 		expbuf = compile(genbuf, (char *)0, (char *)0);
21940Sstevel@tonic-gate 	}
21950Sstevel@tonic-gate 	if (regerrno)
21960Sstevel@tonic-gate 		error1(regerrno);
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate static void
move(int cflag)22000Sstevel@tonic-gate move(int cflag)
22010Sstevel@tonic-gate {
22020Sstevel@tonic-gate 	LINE adt, ad1, ad2;
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	setdot();
22050Sstevel@tonic-gate 	nonzero();
22060Sstevel@tonic-gate 	if ((adt = address()) == 0)
22070Sstevel@tonic-gate 		(void) error(39);
22080Sstevel@tonic-gate 	newline();
22090Sstevel@tonic-gate 	if (!globflg) save();
22100Sstevel@tonic-gate 	if (cflag) {
22110Sstevel@tonic-gate 		ad1 = dol;
22120Sstevel@tonic-gate 		append(getcopy, ad1++);
22130Sstevel@tonic-gate 		ad2 = dol;
22140Sstevel@tonic-gate 	} else {
22150Sstevel@tonic-gate 		ad2 = addr2;
22160Sstevel@tonic-gate 		for (ad1 = addr1; ad1 <= ad2; )
22170Sstevel@tonic-gate 			(ad1++)->cur &= ~01;
22180Sstevel@tonic-gate 		ad1 = addr1;
22190Sstevel@tonic-gate 	}
22200Sstevel@tonic-gate 	ad2++;
22210Sstevel@tonic-gate 	if (adt < ad1) {
22220Sstevel@tonic-gate 		dot = adt + (ad2-ad1);
22230Sstevel@tonic-gate 		if ((++adt) == ad1)
22240Sstevel@tonic-gate 			return;
22250Sstevel@tonic-gate 		reverse(adt, ad1);
22260Sstevel@tonic-gate 		reverse(ad1, ad2);
22270Sstevel@tonic-gate 		reverse(adt, ad2);
22280Sstevel@tonic-gate 	} else if (adt >= ad2) {
22290Sstevel@tonic-gate 		dot = adt++;
22300Sstevel@tonic-gate 		reverse(ad1, ad2);
22310Sstevel@tonic-gate 		reverse(ad2, adt);
22320Sstevel@tonic-gate 		reverse(ad1, adt);
22330Sstevel@tonic-gate 	} else
22340Sstevel@tonic-gate 		(void) error(39);
22350Sstevel@tonic-gate 	fchange = 1;
22360Sstevel@tonic-gate }
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate static void
reverse(LINE a1,LINE a2)22390Sstevel@tonic-gate reverse(LINE a1, LINE a2)
22400Sstevel@tonic-gate {
22410Sstevel@tonic-gate 	long t;
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	for (;;) {
22440Sstevel@tonic-gate 		t = (--a2)->cur;
22450Sstevel@tonic-gate 		if (a2 <= a1)
22460Sstevel@tonic-gate 			return;
22470Sstevel@tonic-gate 		a2->cur = a1->cur;
22480Sstevel@tonic-gate 		(a1++)->cur = t;
22490Sstevel@tonic-gate 	}
22500Sstevel@tonic-gate }
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate static int
getcopy(void)22530Sstevel@tonic-gate getcopy(void)
22540Sstevel@tonic-gate {
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	if (addr1 > addr2)
22570Sstevel@tonic-gate 		return (EOF);
2258*13093SRoger.Faulkner@Oracle.COM 	(void) getaline((addr1++)->cur);
22590Sstevel@tonic-gate 	return (0);
22600Sstevel@tonic-gate }
22610Sstevel@tonic-gate 
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate /*
22640Sstevel@tonic-gate  * Handles error code returned from comple() routine: regular expression
22650Sstevel@tonic-gate  * compile and match routines
22660Sstevel@tonic-gate  */
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate static void
error1(int code)22690Sstevel@tonic-gate error1(int code)
22700Sstevel@tonic-gate {
22710Sstevel@tonic-gate 	nbra = 0;
22720Sstevel@tonic-gate 	(void) error(code);
22730Sstevel@tonic-gate }
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate static int
execute(int gf,LINE addr)22770Sstevel@tonic-gate execute(int gf, LINE addr)
22780Sstevel@tonic-gate {
22790Sstevel@tonic-gate 	char *p1;
22800Sstevel@tonic-gate 	int c;
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	for (c = 0; c < nbra; c++) {
22830Sstevel@tonic-gate 		braslist[c] = 0;
22840Sstevel@tonic-gate 		braelist[c] = 0;
22850Sstevel@tonic-gate 	}
22860Sstevel@tonic-gate 	if (gf)
22870Sstevel@tonic-gate 		locs = p1 = loc2;
22880Sstevel@tonic-gate 	else {
22890Sstevel@tonic-gate 		if (addr == zero)
22900Sstevel@tonic-gate 			return (0);
2291*13093SRoger.Faulkner@Oracle.COM 		p1 = getaline(addr->cur);
22920Sstevel@tonic-gate 		locs = 0;
22930Sstevel@tonic-gate 	}
22940Sstevel@tonic-gate 	return (step(p1, expbuf));
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 
22980Sstevel@tonic-gate static void
putd()22990Sstevel@tonic-gate putd()
23000Sstevel@tonic-gate {
23010Sstevel@tonic-gate 	int r;
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	r = (int)(count%10);
23040Sstevel@tonic-gate 	count /= 10;
23050Sstevel@tonic-gate 	if (count)
23060Sstevel@tonic-gate 		putd();
23070Sstevel@tonic-gate 	putchr(r + '0');
23080Sstevel@tonic-gate }
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate int
puts(const char * sp)23120Sstevel@tonic-gate puts(const char *sp)
23130Sstevel@tonic-gate {
23140Sstevel@tonic-gate 	int n;
23150Sstevel@tonic-gate 	wchar_t c;
23160Sstevel@tonic-gate 	int sz, i;
23170Sstevel@tonic-gate 	if (fss.Ffill && (listf == 0)) {
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 		/* deliberate attempt to remove constness of sp because */
23200Sstevel@tonic-gate 		/* it needs to be expanded */
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 		if ((i = expnd((char *)sp, funny, &sz, &fss)) == -1) {
23230Sstevel@tonic-gate 			write(1, funny, fss.Flim & 0377);
23240Sstevel@tonic-gate 			putchr('\n');
23250Sstevel@tonic-gate 			write(1, gettext("too long"),
23260Sstevel@tonic-gate 				strlen(gettext("too long")));
23270Sstevel@tonic-gate 		}
23280Sstevel@tonic-gate 		else
23290Sstevel@tonic-gate 			write(1, funny, sz);
23300Sstevel@tonic-gate 		putchr('\n');
23310Sstevel@tonic-gate 		if (i == -2)
23320Sstevel@tonic-gate 			write(1, gettext("tab count\n"),
23330Sstevel@tonic-gate 				strlen(gettext("tab count\n")));
23340Sstevel@tonic-gate 		return (0);
23350Sstevel@tonic-gate 	}
23360Sstevel@tonic-gate 	col = 0;
23370Sstevel@tonic-gate 	while (*sp) {
23380Sstevel@tonic-gate 		n = mbtowc(&c, sp, MB_LEN_MAX);
23390Sstevel@tonic-gate 		if (listf) {
23400Sstevel@tonic-gate 			if (n < 1)
23410Sstevel@tonic-gate 				(void) error(28);
23420Sstevel@tonic-gate 			else if (n == 1)
23430Sstevel@tonic-gate 				putchr((unsigned char)*sp++);
23440Sstevel@tonic-gate 			else {
23450Sstevel@tonic-gate 				sp += n;
23460Sstevel@tonic-gate 				putwchr(c);
23470Sstevel@tonic-gate 			}
23480Sstevel@tonic-gate 		} else {
23490Sstevel@tonic-gate 			putchr((unsigned char)*sp++);
23500Sstevel@tonic-gate 		}
23510Sstevel@tonic-gate 	}
23520Sstevel@tonic-gate #ifndef XPG6
23530Sstevel@tonic-gate 	if (listf)
23540Sstevel@tonic-gate 		putchr('$');    /* end of line is marked with a $ */
23550Sstevel@tonic-gate #else
23560Sstevel@tonic-gate 	if (listf) {
23570Sstevel@tonic-gate 	/* xpg6 - ensure that the end of line $ is not preceeded with a "\" */
23580Sstevel@tonic-gate 	/* by doing a putchr() with listf=0, thereby avoiding the $ case */
23590Sstevel@tonic-gate 	/* statement  in putchr() */
23600Sstevel@tonic-gate 		listf = 0;
23610Sstevel@tonic-gate 		putchr('$');    /* end of line is marked with a $ */
23620Sstevel@tonic-gate 		listf++;
23630Sstevel@tonic-gate 	}
23640Sstevel@tonic-gate #endif
23650Sstevel@tonic-gate 	putchr('\n');
23660Sstevel@tonic-gate 	return (1);
23670Sstevel@tonic-gate }
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate static void
putwchr(wchar_t ac)23710Sstevel@tonic-gate putwchr(wchar_t ac)
23720Sstevel@tonic-gate {
23730Sstevel@tonic-gate 	char buf[MB_LEN_MAX], *p;
23740Sstevel@tonic-gate 	char *lp;
23750Sstevel@tonic-gate 	wchar_t c;
23760Sstevel@tonic-gate 	short len;
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 	lp = linp;
23790Sstevel@tonic-gate 	c = ac;
23800Sstevel@tonic-gate 	if (listf) {
23810Sstevel@tonic-gate 		if (!iswprint(c)) {
23820Sstevel@tonic-gate 			p = &buf[0];
23830Sstevel@tonic-gate 			if ((len = wctomb(p, c)) <= 0) {
23840Sstevel@tonic-gate 				*p = (unsigned char)c;
23850Sstevel@tonic-gate 				len = 1;
23860Sstevel@tonic-gate 			};
23870Sstevel@tonic-gate 			while (len--) {
23880Sstevel@tonic-gate 				if (col + 4 >= 72) {
23890Sstevel@tonic-gate 					col = 0;
23900Sstevel@tonic-gate 					*lp++ = '\\';
23910Sstevel@tonic-gate 					*lp++ = '\n';
23920Sstevel@tonic-gate 				}
23930Sstevel@tonic-gate 				(void) sprintf(lp, "\\%03o",
23940Sstevel@tonic-gate 					*(unsigned char *)p++);
23950Sstevel@tonic-gate 				col += 4;
23960Sstevel@tonic-gate 				lp += 4;
23970Sstevel@tonic-gate 			}
23980Sstevel@tonic-gate 		} else {
23990Sstevel@tonic-gate 			if ((len = wcwidth(c)) <= 0)
24000Sstevel@tonic-gate 				len = 0;
24010Sstevel@tonic-gate 			if (col + len >= 72) {
24020Sstevel@tonic-gate 				col = 0;
24030Sstevel@tonic-gate 				*lp++ = '\\';
24040Sstevel@tonic-gate 				*lp++ = '\n';
24050Sstevel@tonic-gate 			}
24060Sstevel@tonic-gate 			col += len;
24070Sstevel@tonic-gate 			if ((len = wctomb(lp, c)) <= 0) {
24080Sstevel@tonic-gate 				*lp = (unsigned char)c;
24090Sstevel@tonic-gate 				len = 1;
24100Sstevel@tonic-gate 			}
24110Sstevel@tonic-gate 			lp += len;
24120Sstevel@tonic-gate 		}
24130Sstevel@tonic-gate 	} else {
24140Sstevel@tonic-gate 		if ((len = wctomb(lp, c)) <= 0) {
24150Sstevel@tonic-gate 			*lp = (unsigned char)c;
24160Sstevel@tonic-gate 			len = 1;
24170Sstevel@tonic-gate 		}
24180Sstevel@tonic-gate 		lp += len;
24190Sstevel@tonic-gate 	}
24200Sstevel@tonic-gate 	if (c == '\n' || lp >= &line[64]) {
24210Sstevel@tonic-gate 		linp = line;
24220Sstevel@tonic-gate 		len = lp - line;
24230Sstevel@tonic-gate 		write(1, line, len);
24240Sstevel@tonic-gate 		return;
24250Sstevel@tonic-gate 	}
24260Sstevel@tonic-gate 	linp = lp;
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate static void
putchr(unsigned char c)24310Sstevel@tonic-gate putchr(unsigned char c)
24320Sstevel@tonic-gate {
24330Sstevel@tonic-gate 	char *lp;
24340Sstevel@tonic-gate 	int len;
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 	lp = linp;
24370Sstevel@tonic-gate 	if (listf && c != '\n') {
24380Sstevel@tonic-gate 		switch (c) {
24390Sstevel@tonic-gate 			case '\\' :
24400Sstevel@tonic-gate 				*lp++ = '\\';
24410Sstevel@tonic-gate 				*lp++ = '\\';
24420Sstevel@tonic-gate 				col += 2;
24430Sstevel@tonic-gate 				break;
24440Sstevel@tonic-gate 			case '\007' :
24450Sstevel@tonic-gate 				*lp++ = '\\';
24460Sstevel@tonic-gate 				*lp++ = 'a';
24470Sstevel@tonic-gate 				col += 2;
24480Sstevel@tonic-gate 				break;
24490Sstevel@tonic-gate 			case '\b' :
24500Sstevel@tonic-gate 				*lp++ = '\\';
24510Sstevel@tonic-gate 				*lp++ = 'b';
24520Sstevel@tonic-gate 				col += 2;
24530Sstevel@tonic-gate 				break;
24540Sstevel@tonic-gate 			case '\f' :
24550Sstevel@tonic-gate 				*lp++ = '\\';
24560Sstevel@tonic-gate 				*lp++ = 'f';
24570Sstevel@tonic-gate 				col += 2;
24580Sstevel@tonic-gate 				break;
24590Sstevel@tonic-gate 			case '\r' :
24600Sstevel@tonic-gate 				*lp++ = '\\';
24610Sstevel@tonic-gate 				*lp++ = 'r';
24620Sstevel@tonic-gate 				col += 2;
24630Sstevel@tonic-gate 				break;
24640Sstevel@tonic-gate 			case '\t' :
24650Sstevel@tonic-gate 				*lp++ = '\\';
24660Sstevel@tonic-gate 				*lp++ = 't';
24670Sstevel@tonic-gate 				col += 2;
24680Sstevel@tonic-gate 				break;
24690Sstevel@tonic-gate 			case '\v' :
24700Sstevel@tonic-gate 				*lp++ = '\\';
24710Sstevel@tonic-gate 				*lp++ = 'v';
24720Sstevel@tonic-gate 				col += 2;
24730Sstevel@tonic-gate 				break;
24740Sstevel@tonic-gate #ifdef XPG6
24750Sstevel@tonic-gate 		/* if $ characters are within the line preceed with \ */
24760Sstevel@tonic-gate 			case '$' :
24770Sstevel@tonic-gate 				*lp++ = '\\';
24780Sstevel@tonic-gate 				*lp++ = '$';
24790Sstevel@tonic-gate 				col += 2;
24800Sstevel@tonic-gate 				break;
24810Sstevel@tonic-gate #endif
24820Sstevel@tonic-gate 			default:
24830Sstevel@tonic-gate 				if (isprint(c)) {
24840Sstevel@tonic-gate 					*lp++ = c;
24850Sstevel@tonic-gate 					col += 1;
24860Sstevel@tonic-gate 				} else {
24870Sstevel@tonic-gate 					(void) sprintf(lp, "\\%03o", c);
24880Sstevel@tonic-gate 					col += 4;
24890Sstevel@tonic-gate 					lp += 4;
24900Sstevel@tonic-gate 				}
24910Sstevel@tonic-gate 				break;
24920Sstevel@tonic-gate 		}
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	/*
24950Sstevel@tonic-gate 	 * long lines are folded w/ pt of folding indicated by writing
24960Sstevel@tonic-gate 	 * backslash/newline character
24970Sstevel@tonic-gate 	 */
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 		if (col + 1 >= 72) {
25000Sstevel@tonic-gate 			col = 0;
25010Sstevel@tonic-gate 			*lp++ = '\\';
25020Sstevel@tonic-gate 			*lp++ = '\n';
25030Sstevel@tonic-gate 		}
25040Sstevel@tonic-gate 	} else
25050Sstevel@tonic-gate 		*lp++ = c;
25060Sstevel@tonic-gate 	if (c == '\n' || lp >= &line[64]) {
25070Sstevel@tonic-gate 		linp = line;
25080Sstevel@tonic-gate 		len = lp - line;
25090Sstevel@tonic-gate 		(void) write(1, line, len);
25100Sstevel@tonic-gate 		return;
25110Sstevel@tonic-gate 	}
25120Sstevel@tonic-gate 	linp = lp;
25130Sstevel@tonic-gate }
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate 
25160Sstevel@tonic-gate static char *
getkey(const char * prompt)25170Sstevel@tonic-gate getkey(const char *prompt)
25180Sstevel@tonic-gate {
25190Sstevel@tonic-gate 	struct termio b;
25200Sstevel@tonic-gate 	int save;
25210Sstevel@tonic-gate 	void (*sig)();
25220Sstevel@tonic-gate 	static char key[KSIZE+1];
25230Sstevel@tonic-gate 	char *p;
25240Sstevel@tonic-gate 	int c;
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 	sig = signal(SIGINT, SIG_IGN);
25270Sstevel@tonic-gate 	ioctl(0, TCGETA, &b);
25280Sstevel@tonic-gate 	save = b.c_lflag;
25290Sstevel@tonic-gate 	b.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
25300Sstevel@tonic-gate 	ioctl(0, TCSETAW, &b);
25310Sstevel@tonic-gate 	write(1, gettext(prompt), strlen(gettext(prompt)));
25320Sstevel@tonic-gate 	p = key;
25330Sstevel@tonic-gate 	while (((c = getchr()) != EOF) && (c != '\n')) {
25340Sstevel@tonic-gate 		if (p < &key[KSIZE])
25350Sstevel@tonic-gate 			*p++ = c;
25360Sstevel@tonic-gate 	}
25370Sstevel@tonic-gate 	*p = 0;
25380Sstevel@tonic-gate 	write(1, "\n", 1);
25390Sstevel@tonic-gate 	b.c_lflag = save;
25400Sstevel@tonic-gate 	ioctl(0, TCSETAW, &b);
25410Sstevel@tonic-gate 	signal(SIGINT, sig);
25420Sstevel@tonic-gate 	return (key);
25430Sstevel@tonic-gate }
25440Sstevel@tonic-gate 
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate static void
globaln(int k)25470Sstevel@tonic-gate globaln(int k)
25480Sstevel@tonic-gate {
25490Sstevel@tonic-gate 	char *gp;
25500Sstevel@tonic-gate 	int c;
25510Sstevel@tonic-gate 	int n;
25520Sstevel@tonic-gate 	wchar_t cl;
25530Sstevel@tonic-gate 	LINE a1;
25540Sstevel@tonic-gate 	int  nfirst;
25550Sstevel@tonic-gate 	char globuf[LBSIZE];
25560Sstevel@tonic-gate 	char multic[MB_LEN_MAX];
25570Sstevel@tonic-gate 	int	len;
25580Sstevel@tonic-gate 	int pflag_save = 0;
25590Sstevel@tonic-gate 	int listf_save = 0;
25600Sstevel@tonic-gate 	int listn_save = 0;
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	if (globp)
25630Sstevel@tonic-gate 		(void) error(33);
25640Sstevel@tonic-gate 	setall();
25650Sstevel@tonic-gate 	nonzero();
25660Sstevel@tonic-gate 	if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
25670Sstevel@tonic-gate 		(void) error(67);
25680Sstevel@tonic-gate 	if (cl == '\n')
25690Sstevel@tonic-gate 		(void) error(19);
25700Sstevel@tonic-gate 	save();
25710Sstevel@tonic-gate 	comple(cl);
25720Sstevel@tonic-gate 	for (a1 = zero; a1 <= dol; a1++) {
25730Sstevel@tonic-gate 		a1->cur &= ~01;
25740Sstevel@tonic-gate 		if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
25750Sstevel@tonic-gate 			a1->cur |= 01;
25760Sstevel@tonic-gate 	}
25770Sstevel@tonic-gate 	nfirst = 0;
25780Sstevel@tonic-gate 	newline();
25790Sstevel@tonic-gate 	/*
25800Sstevel@tonic-gate 	 * preserve the p, l, and n suffix commands of the G and V
25810Sstevel@tonic-gate 	 * commands during the interactive section and restore
25820Sstevel@tonic-gate 	 * on completion of the G and V command.
25830Sstevel@tonic-gate 	 */
25840Sstevel@tonic-gate 	pflag_save = pflag;
25850Sstevel@tonic-gate 	listf_save = listf;
25860Sstevel@tonic-gate 	listn_save = listn;
25870Sstevel@tonic-gate 	pflag = 0;
25880Sstevel@tonic-gate 	listf = 0;
25890Sstevel@tonic-gate 	listn = 0;
25900Sstevel@tonic-gate 	for (a1 = zero; a1 <= dol; a1++) {
25910Sstevel@tonic-gate 		if (a1->cur & 01) {
25920Sstevel@tonic-gate 			a1->cur &= ~01;
25930Sstevel@tonic-gate 			dot = a1;
2594*13093SRoger.Faulkner@Oracle.COM 			puts(getaline(a1->cur));
25950Sstevel@tonic-gate 			if ((c = get_wchr()) == EOF)
25960Sstevel@tonic-gate 				(void) error(52);
25970Sstevel@tonic-gate 			if (c == 'a' || c == 'i' || c == 'c')
25980Sstevel@tonic-gate 				(void) error(53);
25990Sstevel@tonic-gate 			if (c == '\n') {
26000Sstevel@tonic-gate 				a1 = zero;
26010Sstevel@tonic-gate 				continue;
26020Sstevel@tonic-gate 			}
26030Sstevel@tonic-gate 			if (c != '&') {
26040Sstevel@tonic-gate 				gp = globuf;
26050Sstevel@tonic-gate 				if ((len = wctomb(gp, c)) <= 0) {
26060Sstevel@tonic-gate 					*gp = (unsigned char)c;
26070Sstevel@tonic-gate 					len = 1;
26080Sstevel@tonic-gate 				}
26090Sstevel@tonic-gate 				gp += len;
26100Sstevel@tonic-gate 				while ((c = get_wchr()) != '\n') {
26110Sstevel@tonic-gate 
26120Sstevel@tonic-gate 			/* '\\' has special meaning only if preceding a '\n' */
26130Sstevel@tonic-gate 					if (c == '\\') {
26140Sstevel@tonic-gate 						c = get_wchr();
26150Sstevel@tonic-gate 						if (c != '\n')
26160Sstevel@tonic-gate 							*gp++ = '\\';
26170Sstevel@tonic-gate 					}
26180Sstevel@tonic-gate 					if ((gp + (unsigned int)MB_CUR_MAX) >=
26190Sstevel@tonic-gate 							&globuf[LBSIZE-1])
26200Sstevel@tonic-gate 						(void) error(34);
26210Sstevel@tonic-gate 
26220Sstevel@tonic-gate 					if ((len = wctomb(gp, c)) <= 0) {
26230Sstevel@tonic-gate 						*gp = (unsigned char)c;
26240Sstevel@tonic-gate 						len = 1;
26250Sstevel@tonic-gate 					}
26260Sstevel@tonic-gate 					gp += len;
26270Sstevel@tonic-gate 				}
26280Sstevel@tonic-gate 				*gp++ = '\n';
26290Sstevel@tonic-gate 				*gp++ = 0;
26300Sstevel@tonic-gate 				nfirst = 1;
26310Sstevel@tonic-gate 			} else if ((c = get_wchr()) != '\n')
26320Sstevel@tonic-gate 				(void) error(54);
26330Sstevel@tonic-gate 			globp = globuf;
26340Sstevel@tonic-gate 			if (nfirst) {
26350Sstevel@tonic-gate 				globflg = 1;
26360Sstevel@tonic-gate 				commands();
26370Sstevel@tonic-gate 				globflg = 0;
26380Sstevel@tonic-gate 			} else
26390Sstevel@tonic-gate 				(void) error(56);
26400Sstevel@tonic-gate 			globp = 0;
26410Sstevel@tonic-gate 			a1 = zero;
26420Sstevel@tonic-gate 		}
26430Sstevel@tonic-gate 	}
26440Sstevel@tonic-gate 	pflag = pflag_save;
26450Sstevel@tonic-gate 	listf = listf_save;
26460Sstevel@tonic-gate 	listn = listn_save;
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate 
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate static int
eopen(char * string,int rw)26510Sstevel@tonic-gate eopen(char *string, int rw)
26520Sstevel@tonic-gate {
26530Sstevel@tonic-gate #define	w_or_r(a, b) (rw ? a : b)
26540Sstevel@tonic-gate 	int pf[2];
26550Sstevel@tonic-gate 	pid_t i;
26560Sstevel@tonic-gate 	int io;
26570Sstevel@tonic-gate 	int chcount;	/* # of char read. */
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 	if (rflg) {	/* restricted shell */
26600Sstevel@tonic-gate 		if (Xqt) {
26610Sstevel@tonic-gate 			Xqt = 0;
26620Sstevel@tonic-gate 			(void) error(6);
26630Sstevel@tonic-gate 		}
26640Sstevel@tonic-gate 	}
26650Sstevel@tonic-gate 	if (!Xqt) {
26660Sstevel@tonic-gate 		if ((io = open(string, rw)) >= 0) {
26670Sstevel@tonic-gate 			if (fflg) {
26680Sstevel@tonic-gate 				chcount = read(io, crbuf, LBSIZE);
26690Sstevel@tonic-gate 				if (crflag == -1) {
26700Sstevel@tonic-gate 					if (isencrypt(crbuf, chcount))
26710Sstevel@tonic-gate 						crflag = 2;
26720Sstevel@tonic-gate 					else
26730Sstevel@tonic-gate 						crflag = -2;
26740Sstevel@tonic-gate 				}
26750Sstevel@tonic-gate 				if (crflag > 0)
26760Sstevel@tonic-gate 				if (run_crypt(0L, crbuf, chcount, perm) == -1)
26770Sstevel@tonic-gate 						(void) error(63);
26780Sstevel@tonic-gate 				if (fspec(crbuf, &fss, 0) < 0) {
26790Sstevel@tonic-gate 					fss.Ffill = 0;
26800Sstevel@tonic-gate 					fflg = 0;
26810Sstevel@tonic-gate 					(void) error(4);
26820Sstevel@tonic-gate 				}
26830Sstevel@tonic-gate 				lseek(io, 0L, 0);
26840Sstevel@tonic-gate 			}
26850Sstevel@tonic-gate 		}
26860Sstevel@tonic-gate 		fflg = 0;
26870Sstevel@tonic-gate 		return (io);
26880Sstevel@tonic-gate 	}
26890Sstevel@tonic-gate 	if (pipe(pf) < 0)
26900Sstevel@tonic-gate xerr:		(void) error(0);
26910Sstevel@tonic-gate 	if ((i = fork()) == 0) {
26920Sstevel@tonic-gate 		signal(SIGHUP, oldhup);
26930Sstevel@tonic-gate 		signal(SIGQUIT, oldquit);
26940Sstevel@tonic-gate 		signal(SIGPIPE, oldpipe);
26950Sstevel@tonic-gate 		signal(SIGINT, (void (*)()) 0);
26960Sstevel@tonic-gate 		close(w_or_r(pf[1], pf[0]));
26970Sstevel@tonic-gate 		close(w_or_r(0, 1));
26980Sstevel@tonic-gate 		dup(w_or_r(pf[0], pf[1]));
26990Sstevel@tonic-gate 		close(w_or_r(pf[0], pf[1]));
27000Sstevel@tonic-gate 		if (__xpg4 == 0) {	/* not XPG4 */
27010Sstevel@tonic-gate 			shpath = "/usr/bin/sh";
27020Sstevel@tonic-gate 		} else {
27030Sstevel@tonic-gate 			/* XPG4 */
27040Sstevel@tonic-gate 			shpath = "/usr/xpg4/bin/sh";
27050Sstevel@tonic-gate 		}
27060Sstevel@tonic-gate 		execlp((const char *)shpath, "sh", "-c", string, (char *)0);
27070Sstevel@tonic-gate 		exit(1);
27080Sstevel@tonic-gate 	}
27090Sstevel@tonic-gate 	if (i == (pid_t)-1)
27100Sstevel@tonic-gate 		goto xerr;
27110Sstevel@tonic-gate 	close(w_or_r(pf[0], pf[1]));
27120Sstevel@tonic-gate 	return (w_or_r(pf[1], pf[0]));
27130Sstevel@tonic-gate }
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate static void
eclose(int f)27170Sstevel@tonic-gate eclose(int f)
27180Sstevel@tonic-gate {
27190Sstevel@tonic-gate 	close(f);
27200Sstevel@tonic-gate 	if (Xqt)
27210Sstevel@tonic-gate 		Xqt = 0, wait((int *)0);
27220Sstevel@tonic-gate }
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate static void
mkfunny(void)27260Sstevel@tonic-gate mkfunny(void)
27270Sstevel@tonic-gate {
27280Sstevel@tonic-gate 	char *p, *p1, *p2;
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate 	p2 = p1 = funny;
27310Sstevel@tonic-gate 	p = file;
27320Sstevel@tonic-gate 	/*
27330Sstevel@tonic-gate 	 * Go to end of file name
27340Sstevel@tonic-gate 	 */
27350Sstevel@tonic-gate 	while (*p)
27360Sstevel@tonic-gate 		p++;
27370Sstevel@tonic-gate 	while (*--p  == '/')	/* delete trailing slashes */
27380Sstevel@tonic-gate 		*p = '\0';
27390Sstevel@tonic-gate 	/*
27400Sstevel@tonic-gate 	 * go back to beginning of file
27410Sstevel@tonic-gate 	 */
27420Sstevel@tonic-gate 	p = file;
27430Sstevel@tonic-gate 	/*
27440Sstevel@tonic-gate 	 * Copy file name to funny setting p2 at
27450Sstevel@tonic-gate 	 * basename of file.
27460Sstevel@tonic-gate 	 */
27470Sstevel@tonic-gate 	while (*p1++ = *p)
27480Sstevel@tonic-gate 		if (*p++ == '/') p2 = p1;
27490Sstevel@tonic-gate 	/*
27500Sstevel@tonic-gate 	 * Set p1 to point to basename of tfname.
27510Sstevel@tonic-gate 	 */
27520Sstevel@tonic-gate 	p1 = strrchr(tfname, '/');
27530Sstevel@tonic-gate 	if (strlen(tfname) > (size_t)6)
27540Sstevel@tonic-gate 		p1 = &tfname[strlen(tfname)-6];
27550Sstevel@tonic-gate 	p1++;
27560Sstevel@tonic-gate 	*p2 = '\007'; /* add unprintable char for funny  a unique name */
27570Sstevel@tonic-gate 	/*
27580Sstevel@tonic-gate 	 * Copy tfname to file.
27590Sstevel@tonic-gate 	 */
27600Sstevel@tonic-gate 	while (*++p2 = *p1++);
27610Sstevel@tonic-gate }
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate static void
getime(void)27650Sstevel@tonic-gate getime(void) /* get modified time of file and save */
27660Sstevel@tonic-gate {
27670Sstevel@tonic-gate 	if (stat(file, &Fl) < 0)
27680Sstevel@tonic-gate 		savtime = 0;
27690Sstevel@tonic-gate 	else
27700Sstevel@tonic-gate 		savtime = Fl.st_mtime;
27710Sstevel@tonic-gate }
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate static void
chktime(void)27750Sstevel@tonic-gate chktime(void) /* check saved mod time against current mod time */
27760Sstevel@tonic-gate {
27770Sstevel@tonic-gate 	if (savtime != 0 && Fl.st_mtime != 0) {
27780Sstevel@tonic-gate 		if (savtime != Fl.st_mtime)
27790Sstevel@tonic-gate 			(void) error(58);
27800Sstevel@tonic-gate 	}
27810Sstevel@tonic-gate }
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate static void
newtime(void)27850Sstevel@tonic-gate newtime(void) /* get new mod time and save */
27860Sstevel@tonic-gate {
27870Sstevel@tonic-gate 	stat(file, &Fl);
27880Sstevel@tonic-gate 	savtime = Fl.st_mtime;
27890Sstevel@tonic-gate }
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate static void
red(char * op)27930Sstevel@tonic-gate red(char *op)	/* restricted - check for '/' in name */
27940Sstevel@tonic-gate 		/* and delete trailing '/' */
27950Sstevel@tonic-gate {
27960Sstevel@tonic-gate 	char *p;
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	p = op;
27990Sstevel@tonic-gate 	while (*p)
28000Sstevel@tonic-gate 		if (*p++ == '/'&& rflg) {
28010Sstevel@tonic-gate 			*op = 0;
28020Sstevel@tonic-gate 			(void) error(6);
28030Sstevel@tonic-gate 		}
28040Sstevel@tonic-gate 	/* delete trailing '/' */
28050Sstevel@tonic-gate 	while (p > op) {
28060Sstevel@tonic-gate 		if (*--p == '/')
28070Sstevel@tonic-gate 			*p = '\0';
28080Sstevel@tonic-gate 		else break;
28090Sstevel@tonic-gate 	}
28100Sstevel@tonic-gate }
28110Sstevel@tonic-gate 
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate /*
28140Sstevel@tonic-gate  * Searches thru beginning of file looking for a string of the form
28150Sstevel@tonic-gate  *	<: values... :>
28160Sstevel@tonic-gate  *
28170Sstevel@tonic-gate  * where "values" are
28180Sstevel@tonic-gate  *
28190Sstevel@tonic-gate  *	\b      ignored
28200Sstevel@tonic-gate  *	s<num>  sets the Flim to <num>
28210Sstevel@tonic-gate  *	t???    sets tab stop stuff
28220Sstevel@tonic-gate  *	d       ignored
28230Sstevel@tonic-gate  *	m<num>  ignored
28240Sstevel@tonic-gate  *	e       ignored
28250Sstevel@tonic-gate  */
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate static int
fspec(char line[],struct Fspec * f,int up)28280Sstevel@tonic-gate fspec(char line[], struct Fspec *f, int up)
28290Sstevel@tonic-gate {
28300Sstevel@tonic-gate 	struct termio arg;
28310Sstevel@tonic-gate 	int havespec, n;
28320Sstevel@tonic-gate 	int	len;
28330Sstevel@tonic-gate 
28340Sstevel@tonic-gate 	if (!up) clear(f);
28350Sstevel@tonic-gate 
28360Sstevel@tonic-gate 	havespec = fsprtn = 0;
28370Sstevel@tonic-gate 	for (fsp = line; *fsp && *fsp != '\n'; fsp += len) {
28380Sstevel@tonic-gate 		if ((len = mblen(fsp, MB_CUR_MAX)) <= 0)
28390Sstevel@tonic-gate 			len = 1;
28400Sstevel@tonic-gate 		switch (*fsp) {
28410Sstevel@tonic-gate 
28420Sstevel@tonic-gate 			case '<':	if (havespec)
28430Sstevel@tonic-gate 						return (-1);
28440Sstevel@tonic-gate 					if (*(fsp+1) == ':') {
28450Sstevel@tonic-gate 						havespec = 1;
28460Sstevel@tonic-gate 						clear(f);
28470Sstevel@tonic-gate 						if (!ioctl(1, TCGETA, &arg) &&
28480Sstevel@tonic-gate 						((arg.c_oflag&TAB3) == TAB3))
28490Sstevel@tonic-gate 						    f->Ffill = 1;
28500Sstevel@tonic-gate 						fsp++;
28510Sstevel@tonic-gate 						continue;
28520Sstevel@tonic-gate 					}
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 			case ' ':	continue;
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 			case 's':	if (havespec && (n = numb()) >= 0)
28570Sstevel@tonic-gate 						f->Flim = n;
28580Sstevel@tonic-gate 					continue;
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate 			case 't':	if (havespec) targ(f);
28610Sstevel@tonic-gate 					continue;
28620Sstevel@tonic-gate 
28630Sstevel@tonic-gate 			case 'd':	continue;
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate 			case 'm':	if (havespec)  n = numb();
28660Sstevel@tonic-gate 					continue;
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 			case 'e':	continue;
28690Sstevel@tonic-gate 			case ':':	if (!havespec) continue;
28700Sstevel@tonic-gate 					if (*(fsp+1) != '>') fsprtn = -1;
28710Sstevel@tonic-gate 					return (fsprtn);
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 			default:	if (!havespec) continue;
28740Sstevel@tonic-gate 					return (-1);
28750Sstevel@tonic-gate 		}
28760Sstevel@tonic-gate 	}
28770Sstevel@tonic-gate 	return (1);
28780Sstevel@tonic-gate }
28790Sstevel@tonic-gate 
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate static int
numb(void)28820Sstevel@tonic-gate numb(void)
28830Sstevel@tonic-gate {
28840Sstevel@tonic-gate 	int n;
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	n = 0;
28870Sstevel@tonic-gate 	while (*++fsp >= '0' && *fsp <= '9')
28880Sstevel@tonic-gate 		n = 10*n + *fsp-'0';
28890Sstevel@tonic-gate 	fsp--;
28900Sstevel@tonic-gate 	return (n);
28910Sstevel@tonic-gate }
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate static void
targ(struct Fspec * f)28950Sstevel@tonic-gate targ(struct Fspec *f)
28960Sstevel@tonic-gate {
28970Sstevel@tonic-gate 
28980Sstevel@tonic-gate 	if (*++fsp == '-') {
28990Sstevel@tonic-gate 		if (*(fsp + 1) >= '0' && *(fsp+1) <= '9') tincr(numb(), f);
29000Sstevel@tonic-gate 		else tstd(f);
29010Sstevel@tonic-gate 		return;
29020Sstevel@tonic-gate 	}
29030Sstevel@tonic-gate 	if (*fsp >= '0' && *fsp <= '9') {
29040Sstevel@tonic-gate 		tlist(f);
29050Sstevel@tonic-gate 		return;
29060Sstevel@tonic-gate 	}
29070Sstevel@tonic-gate 	fsprtn = -1;
29080Sstevel@tonic-gate 	fsp--;
29090Sstevel@tonic-gate }
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 
29120Sstevel@tonic-gate static void
tincr(int n,struct Fspec * f)29130Sstevel@tonic-gate tincr(int n, struct Fspec *f)
29140Sstevel@tonic-gate {
29150Sstevel@tonic-gate 	int l, i;
29160Sstevel@tonic-gate 
29170Sstevel@tonic-gate 	l = 1;
29180Sstevel@tonic-gate 	for (i = 0; i < 20; i++)
29190Sstevel@tonic-gate 		f->Ftabs[i] = l += n;
29200Sstevel@tonic-gate 	f->Ftabs[i] = 0;
29210Sstevel@tonic-gate }
29220Sstevel@tonic-gate 
29230Sstevel@tonic-gate 
29240Sstevel@tonic-gate static void
tstd(struct Fspec * f)29250Sstevel@tonic-gate tstd(struct Fspec *f)
29260Sstevel@tonic-gate {
29270Sstevel@tonic-gate 	char std[3];
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	std[0] = *++fsp;
29300Sstevel@tonic-gate 	if (*(fsp+1) >= '0' && *(fsp+1) <= '9')  {
29310Sstevel@tonic-gate 						std[1] = *++fsp;
29320Sstevel@tonic-gate 						std[2] = '\0';
29330Sstevel@tonic-gate 	} else std[1] = '\0';
29340Sstevel@tonic-gate 	fsprtn = stdtab(std, f->Ftabs);
29350Sstevel@tonic-gate }
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate 
29380Sstevel@tonic-gate static void
tlist(struct Fspec * f)29390Sstevel@tonic-gate tlist(struct Fspec *f)
29400Sstevel@tonic-gate {
29410Sstevel@tonic-gate 	int n, last, i;
29420Sstevel@tonic-gate 
29430Sstevel@tonic-gate 	fsp--;
29440Sstevel@tonic-gate 	last = i = 0;
29450Sstevel@tonic-gate 
29460Sstevel@tonic-gate 	do {
29470Sstevel@tonic-gate 		if ((n = numb()) <= last || i >= 20) {
29480Sstevel@tonic-gate 			fsprtn = -1;
29490Sstevel@tonic-gate 			return;
29500Sstevel@tonic-gate 		}
29510Sstevel@tonic-gate 		f->Ftabs[i++] = last = n;
29520Sstevel@tonic-gate 	} while (*++fsp == ',');
29530Sstevel@tonic-gate 
29540Sstevel@tonic-gate 	f->Ftabs[i] = 0;
29550Sstevel@tonic-gate 	fsp--;
29560Sstevel@tonic-gate }
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 
29590Sstevel@tonic-gate static int
expnd(char line[],char buf[],int * sz,struct Fspec * f)29600Sstevel@tonic-gate expnd(char line[], char buf[], int *sz, struct Fspec *f)
29610Sstevel@tonic-gate {
29620Sstevel@tonic-gate 	char *l, *t;
29630Sstevel@tonic-gate 	int b;
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	l = line - 1;
29660Sstevel@tonic-gate 	b = 1;
29670Sstevel@tonic-gate 	t = f->Ftabs;
29680Sstevel@tonic-gate 	fsprtn = 0;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	while (*++l && *l != '\n' && b < 511) {
29710Sstevel@tonic-gate 		if (*l == '\t') {
29720Sstevel@tonic-gate 			while (*t && b >= *t) t++;
29730Sstevel@tonic-gate 			if (*t == 0) fsprtn = -2;
29740Sstevel@tonic-gate 			do buf[b-1] = ' '; while (++b < *t);
29750Sstevel@tonic-gate 		} else buf[b++ - 1] = *l;
29760Sstevel@tonic-gate 	}
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 	buf[b] = '\0';
29790Sstevel@tonic-gate 	*sz = b;
29800Sstevel@tonic-gate 	if (*l != '\0' && *l != '\n') {
29810Sstevel@tonic-gate 		buf[b-1] = '\n';
29820Sstevel@tonic-gate 		return (-1);
29830Sstevel@tonic-gate 	}
29840Sstevel@tonic-gate 	buf[b-1] = *l;
29850Sstevel@tonic-gate 	if (f->Flim && (b-1 > (int)f->Flim))
29860Sstevel@tonic-gate 		return (-1);
29870Sstevel@tonic-gate 	return (fsprtn);
29880Sstevel@tonic-gate }
29890Sstevel@tonic-gate 
29900Sstevel@tonic-gate 
29910Sstevel@tonic-gate static void
clear(struct Fspec * f)29920Sstevel@tonic-gate clear(struct Fspec *f)
29930Sstevel@tonic-gate {
29940Sstevel@tonic-gate 	f->Ftabs[0] = f->Fdel = f->Fmov = f->Ffill = 0;
29950Sstevel@tonic-gate 	f->Flim = 0;
29960Sstevel@tonic-gate }
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate static int
lenchk(char line[],struct Fspec * f)30000Sstevel@tonic-gate lenchk(char line[], struct Fspec *f)
30010Sstevel@tonic-gate {
30020Sstevel@tonic-gate 	char *l, *t;
30030Sstevel@tonic-gate 	int b;
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate 	l = line - 1;
30060Sstevel@tonic-gate 	b = 1;
30070Sstevel@tonic-gate 	t = f->Ftabs;
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate 	while (*++l && *l != '\n' && b < 511) {
30100Sstevel@tonic-gate 		if (*l == '\t') {
30110Sstevel@tonic-gate 			while (*t && b >= *t) t++;
30120Sstevel@tonic-gate 			while (++b < *t);
30130Sstevel@tonic-gate 		} else b++;
30140Sstevel@tonic-gate 	}
30150Sstevel@tonic-gate 
30160Sstevel@tonic-gate 	if ((*l != '\0' && *l != '\n') || (f->Flim && (b-1 > (int)f->Flim)))
30170Sstevel@tonic-gate 		return (-1);
30180Sstevel@tonic-gate 	return (0);
30190Sstevel@tonic-gate }
30200Sstevel@tonic-gate #define	NTABS 21
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 
30230Sstevel@tonic-gate /*
30240Sstevel@tonic-gate  *	stdtabs: standard tabs table
30250Sstevel@tonic-gate  *	format: option code letter(s), null, tabs, null
30260Sstevel@tonic-gate  */
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate static char stdtabs[] = {
30290Sstevel@tonic-gate 'a', 0, 1, 10, 16, 36, 72, 0,			/* IBM 370 Assembler */
30300Sstevel@tonic-gate 'a', '2', 0, 1, 10, 16, 40, 72, 0,		/* IBM Assembler alternative */
30310Sstevel@tonic-gate 'c', 0, 1, 8, 12, 16, 20, 55, 0,		/* COBOL, normal */
30320Sstevel@tonic-gate 'c', '2', 0, 1, 6, 10, 14, 49, 0,		/* COBOL, crunched */
30330Sstevel@tonic-gate 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50,
30340Sstevel@tonic-gate 	54, 58, 62, 67, 0,
30350Sstevel@tonic-gate 'f', 0, 1, 7, 11, 15, 19, 23, 0,		/* FORTRAN */
30360Sstevel@tonic-gate 'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
30370Sstevel@tonic-gate 						/* PL/I */
30380Sstevel@tonic-gate 's', 0, 1, 10, 55, 0,    			/* SNOBOL */
30390Sstevel@tonic-gate 'u', 0, 1, 12, 20, 44, 0, 			/* UNIVAC ASM */
30400Sstevel@tonic-gate 0 };
30410Sstevel@tonic-gate 
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate /*
30440Sstevel@tonic-gate  *	stdtab: return tab list for any "canned" tab option.
30450Sstevel@tonic-gate  *		entry: option points to null-terminated option string
30460Sstevel@tonic-gate  *		tabvect points to vector to be filled in
30470Sstevel@tonic-gate  *	exit: return (0) if legal, tabvect filled, ending with zero
30480Sstevel@tonic-gate  *		return (-1) if unknown option
30490Sstevel@tonic-gate  */
30500Sstevel@tonic-gate 
30510Sstevel@tonic-gate 
30520Sstevel@tonic-gate static int
stdtab(char option[],char tabvect[NTABS])30530Sstevel@tonic-gate stdtab(char option[], char tabvect[NTABS])
30540Sstevel@tonic-gate {
30550Sstevel@tonic-gate 	char *scan;
30560Sstevel@tonic-gate 	tabvect[0] = 0;
30570Sstevel@tonic-gate 	scan = stdtabs;
30580Sstevel@tonic-gate 	while (*scan) {
30590Sstevel@tonic-gate 		if (strequal(&scan, option)) {
30600Sstevel@tonic-gate 			strcopy(scan, tabvect);
30610Sstevel@tonic-gate 			break;
30620Sstevel@tonic-gate 		} else
30630Sstevel@tonic-gate 			while (*scan++);    /* skip over tab specs */
30640Sstevel@tonic-gate 	}
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate /*	later: look up code in /etc/something */
30670Sstevel@tonic-gate 	return (tabvect[0] ? 0 : -1);
30680Sstevel@tonic-gate }
30690Sstevel@tonic-gate 
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate /*
30720Sstevel@tonic-gate  *	strequal: checks strings for equality
30730Sstevel@tonic-gate  *		entry: scan1 points to scan pointer, str points to string
30740Sstevel@tonic-gate  *	exit: return (1) if equal, return (0) if not
30750Sstevel@tonic-gate  *		*scan1 is advanced to next nonzero byte after null
30760Sstevel@tonic-gate  */
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate static int
strequal(char ** scan1,char * str)30800Sstevel@tonic-gate strequal(char **scan1, char *str)
30810Sstevel@tonic-gate {
30820Sstevel@tonic-gate 	char c, *scan;
30830Sstevel@tonic-gate 	scan = *scan1;
30840Sstevel@tonic-gate 	while ((c = *scan++) == *str && c) str++;
30850Sstevel@tonic-gate 	*scan1 = scan;
30860Sstevel@tonic-gate 	if (c == 0 && *str == 0)
30870Sstevel@tonic-gate 		return (1);
30880Sstevel@tonic-gate 	if (c)
30890Sstevel@tonic-gate 		while (*scan++);
30900Sstevel@tonic-gate 			*scan1 = scan;
30910Sstevel@tonic-gate 	return (0);
30920Sstevel@tonic-gate }
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 
30950Sstevel@tonic-gate /*	strcopy: copy source to destination */
30960Sstevel@tonic-gate 
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate static void
strcopy(char * source,char * dest)30990Sstevel@tonic-gate strcopy(char *source, char *dest)
31000Sstevel@tonic-gate {
31010Sstevel@tonic-gate 	while (*dest++ = *source++);
31020Sstevel@tonic-gate }
31030Sstevel@tonic-gate 
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate /* This is called before a buffer modifying command so that the */
31060Sstevel@tonic-gate /* current array of line ptrs is saved in sav and dot and dol are saved */
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate static void
save(void)31100Sstevel@tonic-gate save(void) {
31110Sstevel@tonic-gate 	LINE i;
31120Sstevel@tonic-gate 	int	j;
31130Sstevel@tonic-gate 
31140Sstevel@tonic-gate 	savdot = dot;
31150Sstevel@tonic-gate 	savdol = dol;
31160Sstevel@tonic-gate 	for (j = 0; j <= 25; j++)
31170Sstevel@tonic-gate 		savnames[j] = names[j];
31180Sstevel@tonic-gate 
31190Sstevel@tonic-gate 	for (i = zero + 1; i <= dol; i++)
31200Sstevel@tonic-gate 		i->sav = i->cur;
31210Sstevel@tonic-gate 	initflg = 0;
31220Sstevel@tonic-gate }
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate 
31250Sstevel@tonic-gate /* The undo command calls this to restore the previous ptr array sav */
31260Sstevel@tonic-gate /* and swap with cur - dot and dol are swapped also. This allows user to */
31270Sstevel@tonic-gate /* undo an undo */
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate static void
undo(void)31310Sstevel@tonic-gate undo(void) {
31320Sstevel@tonic-gate 	int j;
31330Sstevel@tonic-gate 	long tmp;
31340Sstevel@tonic-gate 	LINE i, tmpdot, tmpdol;
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate 	tmpdot = dot; dot = savdot; savdot = tmpdot;
31370Sstevel@tonic-gate 	tmpdol = dol; dol = savdol; savdol = tmpdol;
31380Sstevel@tonic-gate 	/* swap arrays using the greater of dol or savdol as upper limit */
31390Sstevel@tonic-gate 	for (i = zero + 1; i <= ((dol > savdol) ? dol : savdol); i++) {
31400Sstevel@tonic-gate 		tmp = i->cur;
31410Sstevel@tonic-gate 		i->cur = i->sav;
31420Sstevel@tonic-gate 		i->sav = tmp;
31430Sstevel@tonic-gate 	}
31440Sstevel@tonic-gate 		/*
31450Sstevel@tonic-gate 		 * If the current text lines are swapped with the
31460Sstevel@tonic-gate 		 * text lines in the save buffer, then swap the current
31470Sstevel@tonic-gate 		 * marks with those in the save area.
31480Sstevel@tonic-gate 		 */
31490Sstevel@tonic-gate 
31500Sstevel@tonic-gate 		for (j = 0; j <= 25; j++) {
31510Sstevel@tonic-gate 			tmp = names[j];
31520Sstevel@tonic-gate 			names[j] = savnames[j];
31530Sstevel@tonic-gate 			savnames[j] = tmp;
31540Sstevel@tonic-gate 		}
31550Sstevel@tonic-gate }
31560Sstevel@tonic-gate 
31570Sstevel@tonic-gate static wchar_t
get_wchr()31580Sstevel@tonic-gate get_wchr()
31590Sstevel@tonic-gate {
31600Sstevel@tonic-gate 	wchar_t	wc;
31610Sstevel@tonic-gate 	char	multi[MB_LEN_MAX];
31620Sstevel@tonic-gate 
31630Sstevel@tonic-gate 	if (_mbftowc(multi, &wc, getchr, &peekc) <= 0)
31640Sstevel@tonic-gate 		wc = getchr();
31650Sstevel@tonic-gate 	return (wc);
31660Sstevel@tonic-gate }
3167