heirloom-ed

diff ed.c @ 0:1493bea5ac22

Initial version of the standalone heirloom-ed
author markus schnalke <meillo@marmaro.de>
date Mon, 05 Sep 2011 16:31:35 +0200
parents
children a09d0630f05b
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ed.c	Mon Sep 05 16:31:35 2011 +0200
     1.3 @@ -0,0 +1,2822 @@
     1.4 +/*
     1.5 + * Editor
     1.6 + */
     1.7 +
     1.8 +/*
     1.9 + * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003.
    1.10 + */
    1.11 +/*	from Unix 32V /usr/src/cmd/ed.c	*/
    1.12 +/*
    1.13 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
    1.14 + *
    1.15 + * Redistribution and use in source and binary forms, with or without
    1.16 + * modification, are permitted provided that the following conditions
    1.17 + * are met:
    1.18 + *   Redistributions of source code and documentation must retain the
    1.19 + *    above copyright notice, this list of conditions and the following
    1.20 + *    disclaimer.
    1.21 + *   Redistributions in binary form must reproduce the above copyright
    1.22 + *    notice, this list of conditions and the following disclaimer in the
    1.23 + *    documentation and/or other materials provided with the distribution.
    1.24 + *   All advertising materials mentioning features or use of this software
    1.25 + *    must display the following acknowledgement:
    1.26 + *      This product includes software developed or owned by Caldera
    1.27 + *      International, Inc.
    1.28 + *   Neither the name of Caldera International, Inc. nor the names of
    1.29 + *    other contributors may be used to endorse or promote products
    1.30 + *    derived from this software without specific prior written permission.
    1.31 + *
    1.32 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
    1.33 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
    1.34 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    1.35 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.36 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
    1.37 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.38 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.39 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    1.40 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    1.41 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    1.42 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    1.43 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.44 + */
    1.45 +
    1.46 +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
    1.47 +#define	USED	__attribute__ ((used))
    1.48 +#elif defined __GNUC__
    1.49 +#define	USED	__attribute__ ((unused))
    1.50 +#else
    1.51 +#define	USED
    1.52 +#endif
    1.53 +#if defined (SU3)
    1.54 +static const char sccsid[] USED = "@(#)ed_su3.sl	1.99 (gritter) 7/27/06";
    1.55 +#elif defined (SUS)
    1.56 +static const char sccsid[] USED = "@(#)ed_sus.sl	1.99 (gritter) 7/27/06";
    1.57 +#elif defined (S42)
    1.58 +static const char sccsid[] USED = "@(#)ed_s42.sl	1.99 (gritter) 7/27/06";
    1.59 +#else	/* !SU3, !SUS, !S42 */
    1.60 +static const char sccsid[] USED = "@(#)ed.sl	1.99 (gritter) 7/27/06";
    1.61 +#endif	/* !SU3, !SUS, !S42 */
    1.62 +
    1.63 +#include <sys/types.h>
    1.64 +#include <sys/stat.h>
    1.65 +#include <sys/wait.h>
    1.66 +#include <sys/stat.h>
    1.67 +#include <fcntl.h>
    1.68 +#include <unistd.h>
    1.69 +#include <time.h>
    1.70 +#include <string.h>
    1.71 +#include <stdlib.h>
    1.72 +#include <signal.h>
    1.73 +#include "sigset.h"
    1.74 +#include <termios.h>
    1.75 +#include <setjmp.h>
    1.76 +#include <libgen.h>
    1.77 +#include <inttypes.h>
    1.78 +#include <locale.h>
    1.79 +#include <wchar.h>
    1.80 +#include <ctype.h>
    1.81 +#include <wctype.h>
    1.82 +#include <limits.h>
    1.83 +#include <termios.h>
    1.84 +static int	FNSIZE;
    1.85 +static int	LBSIZE;
    1.86 +static int	RHSIZE;
    1.87 +#define	ESIZE	2048
    1.88 +static int	GBSIZE;
    1.89 +#undef	EOF
    1.90 +#define	EOF	-1
    1.91 +#define	puts(s)		xxputs(s)
    1.92 +#define	getline(t, n)	xxgetline(t, n)
    1.93 +
    1.94 +#if (LONG_MAX > 017777777777L)
    1.95 +#define	MAXCNT	0777777777777777777777L		/* 2^63-1 */
    1.96 +#else
    1.97 +#define	MAXCNT	017777777777L			/* 2^31-1 */
    1.98 +#endif
    1.99 +#define	BLKMSK	(MAXCNT>>8)			/* was 0377 */
   1.100 +
   1.101 +#define	READ	0
   1.102 +#define	WRITE	1
   1.103 +#define	EXIST	2
   1.104 +
   1.105 +struct	tabulator {
   1.106 +	struct tabulator	*t_nxt;	/* next list element */
   1.107 +	const char	*t_str;		/* tabulator string */
   1.108 +	int	t_tab;			/* tab stop position */
   1.109 +	int	t_rep;			/* repetitive tab count */
   1.110 +};
   1.111 +
   1.112 +static int	peekc;
   1.113 +static int	lastc;
   1.114 +static char	*savedfile;
   1.115 +static char	*file;
   1.116 +static struct stat	fstbuf;
   1.117 +static char	*linebuf;
   1.118 +static char	*rhsbuf;
   1.119 +static char	expbuf[ESIZE + 4];
   1.120 +static long	*zero;
   1.121 +static long	*undzero;
   1.122 +static long	*dot;
   1.123 +static long	*unddot;
   1.124 +static long	*dol;
   1.125 +static long	*unddol;
   1.126 +static long	*addr1;
   1.127 +static long	*addr2;
   1.128 +static char	*genbuf;
   1.129 +static long	count;
   1.130 +static char	*linebp;
   1.131 +static int	ninbuf;
   1.132 +static int	io;
   1.133 +static int	ioeof;
   1.134 +static int	pflag;
   1.135 +static char	*wrtemp;
   1.136 +static uid_t	myuid;
   1.137 +static void	(*oldhup)(int);
   1.138 +static void	(*oldquit)(int);
   1.139 +static void	(*oldpipe)(int);
   1.140 +static int	vflag	= 1;
   1.141 +static int	listf;
   1.142 +static int	numbf;
   1.143 +static char	*globp;
   1.144 +static int	tfile	= -1;
   1.145 +static long	tline;
   1.146 +static char	tfname[64];
   1.147 +static char	ibuff[512];
   1.148 +static int	iblock	= -1;
   1.149 +static char	obuff[512];
   1.150 +static int	oblock	= -1;
   1.151 +static int	ichanged;
   1.152 +static int	nleft;
   1.153 +static long	*names;
   1.154 +static long	*undnames;
   1.155 +static int	anymarks;
   1.156 +static int	subnewa;
   1.157 +static int	fchange;
   1.158 +static int	wrapp;
   1.159 +static unsigned nlall = 128;
   1.160 +static const char	*progname;
   1.161 +static const char	*prompt = "*";
   1.162 +static int	Pflag;
   1.163 +static int	prhelp;
   1.164 +static const char	*prvmsg;
   1.165 +static int	lastsig;
   1.166 +static int	pipid = -1;
   1.167 +static int	readop;
   1.168 +static int	status;
   1.169 +static int	mb_cur_max;
   1.170 +static int	needsub;
   1.171 +static int	insub;
   1.172 +static struct tabulator	*tabstops;
   1.173 +static int	maxlength;
   1.174 +static int	rspec;
   1.175 +static int	Nflag;
   1.176 +static int	bcount = 22;
   1.177 +static int	ocount = 11;
   1.178 +
   1.179 +static jmp_buf	savej;
   1.180 +
   1.181 +static void	usage(char, int);
   1.182 +static void	commands(void);
   1.183 +static long	*address(void);
   1.184 +static void	setdot(void);
   1.185 +static void	setall(void);
   1.186 +static void	setnoaddr(void);
   1.187 +static void	nonzero(void);
   1.188 +static void	newline(void);
   1.189 +static void	filename(int);
   1.190 +static void	exfile(void);
   1.191 +static void	onintr(int);
   1.192 +static void	onhup(int);
   1.193 +static void	onpipe(int);
   1.194 +static void	error(const char *);
   1.195 +static void	error2(const char *, const char *);
   1.196 +static void	errput(const char *, const char *);
   1.197 +static int	getchr(void);
   1.198 +static int	gettty(void);
   1.199 +static long	getnum(void);
   1.200 +static int	getfile(void);
   1.201 +static void	putfile(void);
   1.202 +static int	append(int (*)(void), long *);
   1.203 +static void	callunix(void);
   1.204 +static char	*readcmd(void);
   1.205 +static void	quit(int);
   1.206 +static void	delete(void);
   1.207 +static void	rdelete(long *, long *);
   1.208 +static void	gdelete(void);
   1.209 +static char	*getline(long, int);
   1.210 +static int	putline(void);
   1.211 +static char	*getblock(long, long);
   1.212 +static void	blkio(long, char *, int);
   1.213 +static void	init(void);
   1.214 +static void	global(int, int);
   1.215 +static void	globrd(char **, int);
   1.216 +static void	join(void);
   1.217 +static void	substitute(int);
   1.218 +static int	compsub(void);
   1.219 +static int	getsub(void);
   1.220 +static int	dosub(int);
   1.221 +static int	place(int, const char *, const char *);
   1.222 +static void	move(int);
   1.223 +static void	reverse(long *, long *);
   1.224 +static int	getcopy(void);
   1.225 +static int	execute(int, long *, int);
   1.226 +static void	cmplerr(int);
   1.227 +static void	doprnt(long *, long *);
   1.228 +static void	putd(long);
   1.229 +static void	puts(const char *);
   1.230 +static void	nlputs(const char *);
   1.231 +static void	list(const char *);
   1.232 +static int	lstchr(int);
   1.233 +static void	putstr(const char *);
   1.234 +static void	putchr(int);
   1.235 +static void	checkpoint(void);
   1.236 +static void	undo(void);
   1.237 +static int	maketf(int);
   1.238 +static int	creatf(const char *);
   1.239 +static int	sopen(const char *, int);
   1.240 +static void	sclose(int);
   1.241 +static void	fspec(const char *);
   1.242 +static const char	*ftok(const char **);
   1.243 +static struct tabulator	*tabstring(const char *);
   1.244 +static void	freetabs(void);
   1.245 +static void	expand(const char *);
   1.246 +static void	growlb(const char *);
   1.247 +static void	growrhs(const char *);
   1.248 +static void	growfn(const char *);
   1.249 +static void	help(void);
   1.250 +
   1.251 +#define	INIT
   1.252 +#define	GETC()		getchr()
   1.253 +#define	UNGETC(c)	(peekc = c)
   1.254 +#define	PEEKC()		(peekc = getchr())
   1.255 +#define	RETURN(c)	return c
   1.256 +#define	ERROR(c)	cmplerr(c)
   1.257 +static wint_t	GETWC(char *);
   1.258 +
   1.259 +#if defined (SUS) || defined (S42) || defined (SU3)
   1.260 +
   1.261 +#include <regex.h>
   1.262 +
   1.263 +#define	NBRA	9
   1.264 +
   1.265 +static char	*braslist[NBRA];
   1.266 +static char	*braelist[NBRA];
   1.267 +static char	*loc1, *loc2, *locs;
   1.268 +static int	nbra;
   1.269 +static int	circf;
   1.270 +static int	nodelim;
   1.271 +
   1.272 +static char	*compile(char *, char *, const char *, int);
   1.273 +static int	step(const char *, const char *);
   1.274 +
   1.275 +#else	/* !SUS, !S42, !SU3 */
   1.276 +
   1.277 +#include <regexp.h>
   1.278 +
   1.279 +#endif	/* !SUS, !S42, !SU3 */
   1.280 +
   1.281 +int
   1.282 +main(int argc, char **argv)
   1.283 +{
   1.284 +	register int i;
   1.285 +	void (*oldintr)(int);
   1.286 +
   1.287 +	progname = basename(argv[0]);
   1.288 +#if defined (SUS) || defined (S42) || defined (SU3)
   1.289 +	setlocale(LC_COLLATE, "");
   1.290 +#endif
   1.291 +	setlocale(LC_CTYPE, "");
   1.292 +	mb_cur_max = MB_CUR_MAX;
   1.293 +	myuid = getuid();
   1.294 +	oldquit = sigset(SIGQUIT, SIG_IGN);
   1.295 +	oldhup = sigset(SIGHUP, SIG_IGN);
   1.296 +	oldintr = sigset(SIGINT, SIG_IGN);
   1.297 +	if (sigset(SIGTERM, SIG_IGN) != SIG_IGN)
   1.298 +		sigset(SIGTERM, quit);
   1.299 +	oldpipe = sigset(SIGPIPE, onpipe);
   1.300 +	argv++;
   1.301 +	while (argc > 1 && **argv=='-') {
   1.302 +		if ((*argv)[1] == '\0') {
   1.303 +			vflag = 0;
   1.304 +			goto next;
   1.305 +		} else if ((*argv)[1] == '-' && (*argv)[2] == '\0') {
   1.306 +			argv++;
   1.307 +			argc--;
   1.308 +			break;
   1.309 +		}
   1.310 +	letter:	switch((*argv)[1]) {
   1.311 +
   1.312 +		case 's':
   1.313 +			vflag = 0;
   1.314 +			break;
   1.315 +
   1.316 +		case 'q':
   1.317 +			sigset(SIGQUIT, SIG_DFL);
   1.318 +			vflag = 1;
   1.319 +			break;
   1.320 +
   1.321 +		case 'p':
   1.322 +			if ((*argv)[2])
   1.323 +				prompt = &(*argv)[2];
   1.324 +			else if (argv[1]) {
   1.325 +				prompt = argv[1];
   1.326 +				argv++;
   1.327 +				argc--;
   1.328 +			} else
   1.329 +				usage((*argv)[1], 1);
   1.330 +			Pflag = 1;
   1.331 +			goto next;
   1.332 +
   1.333 +		default:
   1.334 +			usage((*argv)[1], 0);
   1.335 +		}
   1.336 +		if ((*argv)[2]) {
   1.337 +			(*argv)++;
   1.338 +			goto letter;
   1.339 +		}
   1.340 +	next:	argv++;
   1.341 +		argc--;
   1.342 +	}
   1.343 +
   1.344 +	growfn("no space");
   1.345 +	if (argc>1) {
   1.346 +		i = -1;
   1.347 +		do
   1.348 +			if (++i >= FNSIZE)
   1.349 +				growfn("maximum of characters in "
   1.350 +						"file names reached");
   1.351 +		while (savedfile[i] = (*argv)[i]);
   1.352 +		globp = "e";
   1.353 +	}
   1.354 +	names = malloc(26*sizeof *names);
   1.355 +	undnames = malloc(26*sizeof *undnames);
   1.356 +	zero = malloc(nlall*sizeof *zero);
   1.357 +	if ((undzero = malloc(nlall*sizeof *undzero)) == NULL)
   1.358 +		puts("no memory for undo");
   1.359 +	growlb("no space");
   1.360 +	growrhs("no space");
   1.361 +	init();
   1.362 +	if (oldintr != SIG_IGN)
   1.363 +		sigset(SIGINT, onintr);
   1.364 +	if (oldhup != SIG_IGN)
   1.365 +		sigset(SIGHUP, onhup);
   1.366 +	setjmp(savej);
   1.367 +	if (lastsig) {
   1.368 +		sigrelse(lastsig);
   1.369 +		lastsig = 0;
   1.370 +	}
   1.371 +	commands();
   1.372 +	quit(0);
   1.373 +	/*NOTREACHED*/
   1.374 +	return 0;
   1.375 +}
   1.376 +
   1.377 +static void
   1.378 +usage(char c, int misarg)
   1.379 +{
   1.380 +	if (c) {
   1.381 +		write(2, progname, strlen(progname));
   1.382 +		if (misarg)
   1.383 +			write(2, ": option requires an argument -- ", 33);
   1.384 +		else
   1.385 +			write(2, ": illegal option -- ", 20);
   1.386 +		write(2, &c, 1);
   1.387 +		write(2, "\n", 1);
   1.388 +	}
   1.389 +	write(2, "usage: ", 7);
   1.390 +	write(2, progname, strlen(progname));
   1.391 +	write(2, " [- | -s] [-p string] [file]\n", 29);
   1.392 +	exit(2);
   1.393 +}
   1.394 +
   1.395 +static void
   1.396 +commands(void)
   1.397 +{
   1.398 +	register long *a1;
   1.399 +	register int c;
   1.400 +	int	n;
   1.401 +
   1.402 +	for (;;) {
   1.403 +	if (pflag) {
   1.404 +		pflag = 0;
   1.405 +		addr1 = addr2 = dot;
   1.406 +		goto print;
   1.407 +	}
   1.408 +	if (Pflag && globp == NULL)
   1.409 +		write(1, prompt, strlen(prompt));
   1.410 +	addr1 = 0;
   1.411 +	addr2 = 0;
   1.412 +	switch (c = getchr()) {
   1.413 +	case ',':
   1.414 +	case ';':
   1.415 +		addr2 = c == ',' ? zero+1 : dot;
   1.416 +		if (((peekc = getchr()) < '0' || peekc > '9') &&
   1.417 +				peekc != ' ' && peekc != '\t' &&
   1.418 +				peekc != '+' && peekc != '-' &&
   1.419 +				peekc != '^' && peekc != '?' &&
   1.420 +				peekc != '/' && peekc != '$' &&
   1.421 +				peekc != '.' && peekc != '\'') {
   1.422 +			addr1 = addr2;
   1.423 +			a1 = dol;
   1.424 +			goto loop;
   1.425 +		}
   1.426 +		break;
   1.427 +	default:
   1.428 +		peekc = c;
   1.429 +	}
   1.430 +	do {
   1.431 +		addr1 = addr2;
   1.432 +		if ((a1 = address())==0) {
   1.433 +			c = getchr();
   1.434 +			break;
   1.435 +		}
   1.436 +	loop:	addr2 = a1;
   1.437 +		if ((c=getchr()) == ';') {
   1.438 +			c = ',';
   1.439 +			dot = a1;
   1.440 +		}
   1.441 +	} while (c==',');
   1.442 +	if (addr1==0)
   1.443 +		addr1 = addr2;
   1.444 +	switch(c) {
   1.445 +
   1.446 +	case 'a':
   1.447 +		setdot();
   1.448 +		newline();
   1.449 +		checkpoint();
   1.450 +		append(gettty, addr2);
   1.451 +		continue;
   1.452 +
   1.453 +	case 'c':
   1.454 +#if defined (SU3)
   1.455 +		if (addr1 == zero && addr1+1 <= dol) {
   1.456 +			if (addr1 == addr2)
   1.457 +				addr2++;
   1.458 +			addr1++;
   1.459 +		}
   1.460 +#endif	/* SU3 */
   1.461 +		delete();
   1.462 +		append(gettty, addr1-1);
   1.463 +#if defined (SUS) || defined (SU3)
   1.464 +		if (dot == addr1-1 && addr1 <= dol)
   1.465 +			dot = addr1;
   1.466 +#endif	/* SUS || SU3 */
   1.467 +		continue;
   1.468 +
   1.469 +	case 'd':
   1.470 +		delete();
   1.471 +		continue;
   1.472 +
   1.473 +	case 'E':
   1.474 +		fchange = 0;
   1.475 +		c = 'e';
   1.476 +	case 'e':
   1.477 +		setnoaddr();
   1.478 +		if (vflag && fchange) {
   1.479 +			fchange = 0;
   1.480 +			error("warning: expecting `w'");
   1.481 +		}
   1.482 +		filename(c);
   1.483 +		init();
   1.484 +		addr2 = zero;
   1.485 +		goto caseread;
   1.486 +
   1.487 +	case 'f':
   1.488 +		setnoaddr();
   1.489 +		filename(c);
   1.490 +		puts(savedfile);
   1.491 +		continue;
   1.492 +
   1.493 +	case 'g':
   1.494 +		global(1, 0);
   1.495 +		continue;
   1.496 +
   1.497 +	case 'G':
   1.498 +		global(1, 1);
   1.499 +		continue;
   1.500 +
   1.501 +	case 'H':
   1.502 +		prhelp = !prhelp;
   1.503 +		/*FALLTHRU*/
   1.504 +
   1.505 +	case 'h':
   1.506 +		if ((peekc = getchr()) == 'e') {
   1.507 +			peekc = 0;
   1.508 +			if (getchr() != 'l' || getchr() != 'p' ||
   1.509 +					getchr() != '\n')
   1.510 +				error("illegal suffix");
   1.511 +			setnoaddr();
   1.512 +			help();
   1.513 +			continue;
   1.514 +		}
   1.515 +		newline();
   1.516 +		setnoaddr();
   1.517 +		if (prvmsg)
   1.518 +			puts(prvmsg);
   1.519 +		continue;
   1.520 +
   1.521 +	case 'i':
   1.522 +		setdot();
   1.523 +#if defined (SU3)
   1.524 +		if (addr1 == zero) {
   1.525 +			if (addr1 == addr2)
   1.526 +				addr2++;
   1.527 +			addr1++;
   1.528 +			if (dol != zero)
   1.529 +				nonzero();
   1.530 +		} else
   1.531 +#endif	/* SU3 */
   1.532 +			nonzero();
   1.533 +		newline();
   1.534 +		checkpoint();
   1.535 +		append(gettty, addr2-1);
   1.536 +		if (dot == addr2-1)
   1.537 +			dot++;
   1.538 +		continue;
   1.539 +
   1.540 +
   1.541 +	case 'j':
   1.542 +		if (addr2==0) {
   1.543 +			addr1 = dot;
   1.544 +			addr2 = dot+1;
   1.545 +		}
   1.546 +		setdot();
   1.547 +		newline();
   1.548 +		nonzero();
   1.549 +		checkpoint();
   1.550 +		if (addr1 != addr2)
   1.551 +			join();
   1.552 +		continue;
   1.553 +
   1.554 +	case 'k':
   1.555 +		if ((c = getchr()) < 'a' || c > 'z')
   1.556 +			error("mark not lower case");
   1.557 +		newline();
   1.558 +		setdot();
   1.559 +		nonzero();
   1.560 +		names[c-'a'] = *addr2 & ~01;
   1.561 +		anymarks |= 01;
   1.562 +		continue;
   1.563 +
   1.564 +	case 'm':
   1.565 +		move(0);
   1.566 +		continue;
   1.567 +
   1.568 +	case '\n':
   1.569 +		if (addr2==0)
   1.570 +			addr2 = dot+1;
   1.571 +		addr1 = addr2;
   1.572 +		goto print;
   1.573 +
   1.574 +	case 'n':
   1.575 +		numbf = 1;
   1.576 +		newline();
   1.577 +		goto print;
   1.578 +
   1.579 +	case 'N':
   1.580 +		newline();
   1.581 +		setnoaddr();
   1.582 +		Nflag = !Nflag;
   1.583 +		continue;
   1.584 +
   1.585 +	case 'b':
   1.586 +	case 'o':
   1.587 +		n = getnum();
   1.588 +		newline();
   1.589 +		setdot();
   1.590 +		nonzero();
   1.591 +		if (n >= 0) {
   1.592 +			if (c == 'b')
   1.593 +				bcount = n;
   1.594 +			else
   1.595 +				ocount = n;
   1.596 +		}
   1.597 +		if (c == 'b') {
   1.598 +			a1 = addr2+bcount > dol ? dol : addr2 + bcount;
   1.599 +			doprnt(addr1, a1);
   1.600 +			dot = a1;
   1.601 +		} else {
   1.602 +			a1 = addr2+ocount > dol ? dol : addr2 + ocount;
   1.603 +			doprnt(addr2-ocount<zero+1?zero+1:addr2-ocount, a1);
   1.604 +			dot = addr2;
   1.605 +		}
   1.606 +		continue;
   1.607 +
   1.608 +	case 'l':
   1.609 +		listf++;
   1.610 +	case 'p':
   1.611 +		newline();
   1.612 +	print:
   1.613 +		setdot();
   1.614 +		nonzero();
   1.615 +		doprnt(addr1, addr2);
   1.616 +		dot = addr2;
   1.617 +		continue;
   1.618 +
   1.619 +	case 'P':
   1.620 +		setnoaddr();
   1.621 +		newline();
   1.622 +		Pflag = !Pflag;
   1.623 +		continue;
   1.624 +
   1.625 +	case 'Q':
   1.626 +		fchange = 0;
   1.627 +	case 'q':
   1.628 +		setnoaddr();
   1.629 +		newline();
   1.630 +		quit(0);
   1.631 +
   1.632 +	case 'r':
   1.633 +		filename(c);
   1.634 +	caseread:
   1.635 +		if ((io = sopen(file, READ)) < 0) {
   1.636 +			lastc = '\n';
   1.637 +			error2("cannot open input file", file);
   1.638 +		}
   1.639 +		ioeof = 0;
   1.640 +		setall();
   1.641 +		ninbuf = 0;
   1.642 +		if (c == 'r')
   1.643 +			checkpoint();
   1.644 +		n = zero != dol;
   1.645 +		rspec = (c == 'e' || !n) && file[0] != '!';
   1.646 +		append(getfile, addr2);
   1.647 +		rspec = 0;
   1.648 +		exfile();
   1.649 +		fchange = n;
   1.650 +		continue;
   1.651 +
   1.652 +	case 's':
   1.653 +		setdot();
   1.654 +		nonzero();
   1.655 +		substitute(globp!=0);
   1.656 +		continue;
   1.657 +
   1.658 +	case 't':
   1.659 +		move(1);
   1.660 +		continue;
   1.661 +
   1.662 +	case 'u':
   1.663 +		setdot();
   1.664 +		newline();
   1.665 +		if (unddot == NULL)
   1.666 +			error("nothing to undo");
   1.667 +		undo();
   1.668 +		continue;
   1.669 +
   1.670 +	case 'v':
   1.671 +		global(0, 0);
   1.672 +		continue;
   1.673 +
   1.674 +	case 'V':
   1.675 +		global(0, 1);
   1.676 +		continue;
   1.677 +
   1.678 +	case 'W':
   1.679 +		wrapp++;
   1.680 +	case 'w':
   1.681 +	write:
   1.682 +		setall();
   1.683 +		if (zero != dol)
   1.684 +			nonzero();
   1.685 +		filename(c);
   1.686 +		if(!wrapp ||
   1.687 +		  ((io = open(file,O_WRONLY|O_APPEND)) == -1) ||
   1.688 +		  ((lseek(io, 0, SEEK_END)) == -1)) {
   1.689 +			struct stat	st;
   1.690 +			if (lstat(file, &st) == 0 &&
   1.691 +					(st.st_mode&S_IFMT) == S_IFREG &&
   1.692 +					st.st_nlink == 1 &&
   1.693 +					(myuid==0 || myuid==st.st_uid)) {
   1.694 +				char	*cp, *tp;
   1.695 +				int	nio;
   1.696 +				if ((io = sopen(file, EXIST)) < 0)
   1.697 +					error("cannot create output file");
   1.698 +				if ((wrtemp = malloc(strlen(file)+8)) == NULL)
   1.699 +					error("out of memory");
   1.700 +				for (cp = file, tp = wrtemp; *cp; cp++)
   1.701 +					*tp++ = *cp;
   1.702 +				while (tp > wrtemp && tp[-1] != '/')
   1.703 +					tp--;
   1.704 +				for (cp = "\7XXXXXX"; *cp; cp++)
   1.705 +					*tp++ = *cp;
   1.706 +				*tp = '\0';
   1.707 +				if ((nio = mkstemp(wrtemp)) < 0) {
   1.708 +					free(wrtemp);
   1.709 +					wrtemp = NULL;
   1.710 +					ftruncate(io, 0);
   1.711 +				} else {
   1.712 +					close(io);
   1.713 +					io = nio;
   1.714 +				}
   1.715 +			} else {
   1.716 +				if ((io = sopen(file, WRITE)) < 0)
   1.717 +					error("cannot create output file");
   1.718 +			}
   1.719 +		}
   1.720 +		if (zero != dol) {
   1.721 +			ioeof = 0;
   1.722 +			wrapp = 0;
   1.723 +			putfile();
   1.724 +		}
   1.725 +		exfile();
   1.726 +		if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero)
   1.727 +			fchange = 0;
   1.728 +		if (c == 'z')
   1.729 +			quit(0);
   1.730 +		continue;
   1.731 +
   1.732 +	case 'z':
   1.733 +		if ((peekc=getchr()) != '\n')
   1.734 +			error("illegal suffix");
   1.735 +		setnoaddr();
   1.736 +		goto write;
   1.737 +
   1.738 +	case '=':
   1.739 +		setall();
   1.740 +		newline();
   1.741 +		putd((addr2-zero)&MAXCNT);
   1.742 +		putchr('\n');
   1.743 +		continue;
   1.744 +
   1.745 +	case '!':
   1.746 +		callunix();
   1.747 +		continue;
   1.748 +
   1.749 +	case EOF:
   1.750 +		return;
   1.751 +
   1.752 +	}
   1.753 +	error("unknown command");
   1.754 +	}
   1.755 +}
   1.756 +
   1.757 +static long *
   1.758 +address(void)
   1.759 +{
   1.760 +	register long *a1;
   1.761 +	register int minus, c;
   1.762 +	int n, relerr;
   1.763 +
   1.764 +	minus = 0;
   1.765 +	a1 = 0;
   1.766 +	for (;;) {
   1.767 +		c = getchr();
   1.768 +		if ('0'<=c && c<='9') {
   1.769 +			n = 0;
   1.770 +			do {
   1.771 +				n *= 10;
   1.772 +				n += c - '0';
   1.773 +			} while ((c = getchr())>='0' && c<='9');
   1.774 +			peekc = c;
   1.775 +			if (a1==0)
   1.776 +				a1 = zero;
   1.777 +			if (minus<0)
   1.778 +				n = -n;
   1.779 +			a1 += n;
   1.780 +			minus = 0;
   1.781 +			continue;
   1.782 +		}
   1.783 +		relerr = 0;
   1.784 +		if (a1 || minus)
   1.785 +			relerr++;
   1.786 +		switch(c) {
   1.787 +		case ' ':
   1.788 +		case '\t':
   1.789 +			continue;
   1.790 +	
   1.791 +		case '+':
   1.792 +			minus++;
   1.793 +			if (a1==0)
   1.794 +				a1 = dot;
   1.795 +			continue;
   1.796 +
   1.797 +		case '-':
   1.798 +		case '^':
   1.799 +			minus--;
   1.800 +			if (a1==0)
   1.801 +				a1 = dot;
   1.802 +			continue;
   1.803 +	
   1.804 +		case '?':
   1.805 +		case '/':
   1.806 +			compile(NULL, expbuf, &expbuf[ESIZE], c);
   1.807 +			a1 = dot;
   1.808 +			for (;;) {
   1.809 +				if (c=='/') {
   1.810 +					a1++;
   1.811 +					if (a1 > dol)
   1.812 +						a1 = zero;
   1.813 +				} else {
   1.814 +					a1--;
   1.815 +					if (a1 < zero)
   1.816 +						a1 = dol;
   1.817 +				}
   1.818 +				if (execute(0, a1, 0))
   1.819 +					break;
   1.820 +				if (a1==dot)
   1.821 +					error("search string not found");
   1.822 +			}
   1.823 +			break;
   1.824 +	
   1.825 +		case '$':
   1.826 +			a1 = dol;
   1.827 +			break;
   1.828 +	
   1.829 +		case '.':
   1.830 +			a1 = dot;
   1.831 +			break;
   1.832 +
   1.833 +		case '\'':
   1.834 +			if ((c = getchr()) < 'a' || c > 'z')
   1.835 +				error("mark not lower case");
   1.836 +			for (a1=zero; a1<=dol; a1++)
   1.837 +				if (names[c-'a'] == (*a1 & ~01))
   1.838 +					break;
   1.839 +			break;
   1.840 +	
   1.841 +		default:
   1.842 +			peekc = c;
   1.843 +			if (a1==0)
   1.844 +				return(0);
   1.845 +			a1 += minus;
   1.846 +			if (a1<zero || a1>dol)
   1.847 +				error("line out of range");
   1.848 +			return(a1);
   1.849 +		}
   1.850 +		if (relerr)
   1.851 +			error("bad number");
   1.852 +	}
   1.853 +}
   1.854 +
   1.855 +static void
   1.856 +setdot(void)
   1.857 +{
   1.858 +	if (addr2 == 0)
   1.859 +		addr1 = addr2 = dot;
   1.860 +	if (addr1 > addr2)
   1.861 +		error("bad range");
   1.862 +}
   1.863 +
   1.864 +static void
   1.865 +setall(void)
   1.866 +{
   1.867 +	if (addr2==0) {
   1.868 +		addr1 = zero+1;
   1.869 +		addr2 = dol;
   1.870 +		if (dol==zero)
   1.871 +			addr1 = zero;
   1.872 +	}
   1.873 +	setdot();
   1.874 +}
   1.875 +
   1.876 +static void
   1.877 +setnoaddr(void)
   1.878 +{
   1.879 +	if (addr2)
   1.880 +		error("Illegal address count");
   1.881 +}
   1.882 +
   1.883 +static void
   1.884 +nonzero(void)
   1.885 +{
   1.886 +	if (addr1<=zero || addr2>dol)
   1.887 +		error("line out of range");
   1.888 +}
   1.889 +
   1.890 +static void
   1.891 +newline(void)
   1.892 +{
   1.893 +	register int c;
   1.894 +
   1.895 +	if ((c = getchr()) == '\n')
   1.896 +		return;
   1.897 +	if (c=='p' || c=='l' || c=='n') {
   1.898 +		pflag++;
   1.899 +		if (c=='l')
   1.900 +			listf++;
   1.901 +		else if (c=='n')
   1.902 +			numbf = 1;
   1.903 +		if (getchr() == '\n')
   1.904 +			return;
   1.905 +	}
   1.906 +	error("illegal suffix");
   1.907 +}
   1.908 +
   1.909 +static void
   1.910 +filename(int comm)
   1.911 +{
   1.912 +	register char *p1, *p2;
   1.913 +	register int c, i;
   1.914 +
   1.915 +	count = 0;
   1.916 +	c = getchr();
   1.917 +	if (c=='\n' || c==EOF) {
   1.918 +		p1 = savedfile;
   1.919 +		if (*p1==0 && comm!='f')
   1.920 +			error("illegal or missing filename");
   1.921 +		p2 = file;
   1.922 +		while (*p2++ = *p1++)
   1.923 +			;
   1.924 +		return;
   1.925 +	}
   1.926 +	if (c!=' ')
   1.927 +		error("no space after command");
   1.928 +	while ((c = getchr()) == ' ')
   1.929 +		;
   1.930 +	if (c=='\n')
   1.931 +		error("illegal or missing filename");
   1.932 +	i = 0;
   1.933 +	do {
   1.934 +		if (i >= FNSIZE)
   1.935 +			growfn("maximum of characters in file names reached");
   1.936 +		file[i++] = c;
   1.937 +		if (c==' ' && file[0] != '!' || c==EOF)
   1.938 +			error("illegal or missing filename");
   1.939 +	} while ((c = getchr()) != '\n');
   1.940 +	file[i++] = 0;
   1.941 +	if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') {
   1.942 +		p1 = savedfile;
   1.943 +		p2 = file;
   1.944 +		while (*p1++ = *p2++)
   1.945 +			;
   1.946 +	}
   1.947 +}
   1.948 +
   1.949 +static void
   1.950 +exfile(void)
   1.951 +{
   1.952 +	sclose(io);
   1.953 +	io = -1;
   1.954 +	if (wrtemp) {
   1.955 +		extern int	rename(const char *, const char *);
   1.956 +		if (rename(wrtemp, file) < 0)
   1.957 +			error("cannot create output file");
   1.958 +		if (myuid == 0)
   1.959 +			chown(file, fstbuf.st_uid, fstbuf.st_gid);
   1.960 +		chmod(file, fstbuf.st_mode & 07777);
   1.961 +		free(wrtemp);
   1.962 +		wrtemp = NULL;
   1.963 +	}
   1.964 +	if (vflag) {
   1.965 +		putd(count);
   1.966 +		putchr('\n');
   1.967 +	}
   1.968 +}
   1.969 +
   1.970 +static void
   1.971 +onintr(int signo)
   1.972 +{
   1.973 +	lastsig = signo;
   1.974 +	putchr('\n');
   1.975 +	lastc = '\n';
   1.976 +	if (readop) {
   1.977 +		puts("\007read may be incomplete - beware!\007");
   1.978 +		fchange = 0;
   1.979 +	}
   1.980 +	error("interrupt");
   1.981 +}
   1.982 +
   1.983 +static void
   1.984 +onhup(int signo)
   1.985 +{
   1.986 +	if (dol > zero && fchange) {
   1.987 +		addr1 = zero+1;
   1.988 +		addr2 = dol;
   1.989 +		io = creat("ed.hup", 0666);
   1.990 +		if (io < 0) {
   1.991 +			char	*home = getenv("HOME");
   1.992 +			if (home) {
   1.993 +				char	*fn = malloc(strlen(home) + 10);
   1.994 +				if (fn) {
   1.995 +					strcpy(fn, home);
   1.996 +					strcat(fn, "/ed.hup");
   1.997 +					io = creat(fn, 0666);
   1.998 +				}
   1.999 +			}
  1.1000 +		}
  1.1001 +		if (io >= 0)
  1.1002 +			putfile();
  1.1003 +	}
  1.1004 +	fchange = 0;
  1.1005 +	status = 0200 | signo;
  1.1006 +	quit(0);
  1.1007 +}
  1.1008 +
  1.1009 +static void
  1.1010 +onpipe(int signo)
  1.1011 +{
  1.1012 +	lastsig = signo;
  1.1013 +	error("write or open on pipe failed");
  1.1014 +}
  1.1015 +
  1.1016 +static void
  1.1017 +error(const char *s)
  1.1018 +{
  1.1019 +	error2(s, NULL);
  1.1020 +}
  1.1021 +
  1.1022 +static void
  1.1023 +error2(const char *s, const char *fn)
  1.1024 +{
  1.1025 +	register int c;
  1.1026 +
  1.1027 +	wrapp = 0;
  1.1028 +	listf = 0;
  1.1029 +	numbf = 0;
  1.1030 +	errput(s, fn);
  1.1031 +	count = 0;
  1.1032 +	if (lseek(0, 0, SEEK_END) > 0)
  1.1033 +		status = 2;
  1.1034 +	pflag = 0;
  1.1035 +	if (globp)
  1.1036 +		lastc = '\n';
  1.1037 +	globp = 0;
  1.1038 +	peekc = lastc;
  1.1039 +	if(lastc)
  1.1040 +		while ((c = getchr()) != '\n' && c != EOF)
  1.1041 +			;
  1.1042 +	if (io > 0) {
  1.1043 +		sclose(io);
  1.1044 +		io = -1;
  1.1045 +	}
  1.1046 +	if (wrtemp) {
  1.1047 +		unlink(wrtemp);
  1.1048 +		free(wrtemp);
  1.1049 +		wrtemp = NULL;
  1.1050 +	}
  1.1051 +	longjmp(savej, 1);
  1.1052 +}
  1.1053 +
  1.1054 +static void
  1.1055 +errput(const char *s, const char *fn)
  1.1056 +{
  1.1057 +	prvmsg = s;
  1.1058 +	if (fn) {
  1.1059 +		putchr('?');
  1.1060 +		puts(fn);
  1.1061 +	} else
  1.1062 +		puts("?");
  1.1063 +	if (prhelp)
  1.1064 +		puts(s);
  1.1065 +}
  1.1066 +
  1.1067 +static int
  1.1068 +getchr(void)
  1.1069 +{
  1.1070 +	char c;
  1.1071 +	if (lastc=peekc) {
  1.1072 +		peekc = 0;
  1.1073 +		return(lastc);
  1.1074 +	}
  1.1075 +	if (globp) {
  1.1076 +		if ((lastc = *globp++) != 0)
  1.1077 +			return(lastc);
  1.1078 +		globp = 0;
  1.1079 +		return(EOF);
  1.1080 +	}
  1.1081 +	if (read(0, &c, 1) <= 0)
  1.1082 +		return(lastc = EOF);
  1.1083 +	lastc = c;
  1.1084 +	return(lastc);
  1.1085 +}
  1.1086 +
  1.1087 +static int
  1.1088 +gettty(void)
  1.1089 +{
  1.1090 +	register int c, i;
  1.1091 +	register char *gf;
  1.1092 +
  1.1093 +	i = 0;
  1.1094 +	gf = globp;
  1.1095 +	while ((c = getchr()) != '\n') {
  1.1096 +		if (c==EOF) {
  1.1097 +			if (gf)
  1.1098 +				peekc = c;
  1.1099 +			return(c);
  1.1100 +		}
  1.1101 +		if (c == 0)
  1.1102 +			continue;
  1.1103 +		if (i >= LBSIZE)
  1.1104 +			growlb("line too long");
  1.1105 +		linebuf[i++] = c;
  1.1106 +	}
  1.1107 +	if (i >= LBSIZE-2)
  1.1108 +		growlb("line too long");
  1.1109 +	linebuf[i++] = 0;
  1.1110 +	if (linebuf[0]=='.' && linebuf[1]==0)
  1.1111 +		return(EOF);
  1.1112 +#if !defined (SUS) && !defined (SU3)
  1.1113 +	if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0)
  1.1114 +		linebuf[0]='.', linebuf[1]=0;
  1.1115 +#endif
  1.1116 +	return(0);
  1.1117 +}
  1.1118 +
  1.1119 +static long
  1.1120 +getnum(void)
  1.1121 +{
  1.1122 +	char	scount[20];
  1.1123 +	int	i;
  1.1124 +
  1.1125 +	i = 0;
  1.1126 +	while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) {
  1.1127 +		scount[i++] = peekc;
  1.1128 +		peekc = 0;
  1.1129 +	}
  1.1130 +	scount[i] = '\0';
  1.1131 +	return i ? atol(scount) : -1;
  1.1132 +}
  1.1133 +
  1.1134 +static int
  1.1135 +getfile(void)
  1.1136 +{
  1.1137 +	register int c, i, j;
  1.1138 +	static int	nextj;
  1.1139 +
  1.1140 +	i = 0;
  1.1141 +	j = nextj;
  1.1142 +	do {
  1.1143 +		if (--ninbuf < 0) {
  1.1144 +			if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) {
  1.1145 +				if (ioeof == 0 && ninbuf < -1) {
  1.1146 +					puts("input error");
  1.1147 +					status = 1;
  1.1148 +				}
  1.1149 +				if (i > 0) {
  1.1150 +					puts("'\\n' appended");
  1.1151 +					c = '\n';
  1.1152 +					ioeof = 1;
  1.1153 +					goto wrc;
  1.1154 +				}
  1.1155 +				return(EOF);
  1.1156 +			}
  1.1157 +			j = 0;
  1.1158 +		}
  1.1159 +		c = genbuf[j++]&0377;
  1.1160 +	wrc:	if (i >= LBSIZE) {
  1.1161 +			lastc = '\n';
  1.1162 +			growlb("line too long");
  1.1163 +		}
  1.1164 +		linebuf[i++] = c ? c : '\n';
  1.1165 +		count++;
  1.1166 +	} while (c != '\n');
  1.1167 +	linebuf[--i] = 0;
  1.1168 +	nextj = j;
  1.1169 +	if (rspec && dot == zero)
  1.1170 +		fspec(linebuf);
  1.1171 +	if (maxlength && i > maxlength) {
  1.1172 +		putstr("line too long: lno = ");
  1.1173 +		putd((dot - zero+1)&MAXCNT);
  1.1174 +		putchr('\n');
  1.1175 +	}
  1.1176 +	return(0);
  1.1177 +}
  1.1178 +
  1.1179 +static void
  1.1180 +putfile(void)
  1.1181 +{
  1.1182 +	long *a1;
  1.1183 +	int n;
  1.1184 +	register char *fp, *lp;
  1.1185 +	register int nib;
  1.1186 +
  1.1187 +	nib = 512;
  1.1188 +	fp = genbuf;
  1.1189 +	a1 = addr1;
  1.1190 +	do {
  1.1191 +		lp = getline(*a1++, 0);
  1.1192 +		if (maxlength) {
  1.1193 +			for (n = 0; lp[n]; n++);
  1.1194 +			if (n > maxlength) {
  1.1195 +				putstr("line too long: lno = ");
  1.1196 +				putd((a1-1 - zero)&MAXCNT);
  1.1197 +				putchr('\n');
  1.1198 +			}
  1.1199 +		}
  1.1200 +		for (;;) {
  1.1201 +			if (--nib < 0) {
  1.1202 +				n = fp-genbuf;
  1.1203 +				if(write(io, genbuf, n) != n)
  1.1204 +					error("write error");
  1.1205 +				nib = 511;
  1.1206 +				fp = genbuf;
  1.1207 +			}
  1.1208 +			count++;
  1.1209 +			if ((*fp++ = *lp++) == 0) {
  1.1210 +				fp[-1] = '\n';
  1.1211 +				break;
  1.1212 +			} else if (fp[-1] == '\n')
  1.1213 +				fp[-1] = '\0';
  1.1214 +		}
  1.1215 +	} while (a1 <= addr2);
  1.1216 +	n = fp-genbuf;
  1.1217 +	if(write(io, genbuf, n) != n)
  1.1218 +		error("write error");
  1.1219 +}
  1.1220 +
  1.1221 +static int
  1.1222 +append(int (*f)(void), long *a)
  1.1223 +{
  1.1224 +	register long *a1, *a2, *rdot;
  1.1225 +	int nline, tl;
  1.1226 +
  1.1227 +	nline = 0;
  1.1228 +	dot = a;
  1.1229 +	while ((*f)() == 0) {
  1.1230 +		if ((dol-zero)+1 >= nlall) {
  1.1231 +			long *ozero = zero;
  1.1232 +			nlall += 512;
  1.1233 +			if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) {
  1.1234 +				lastc = '\n';
  1.1235 +				zero = ozero;
  1.1236 +				error("out of memory for append");
  1.1237 +			}
  1.1238 +			dot += zero - ozero;
  1.1239 +			dol += zero - ozero;
  1.1240 +			addr1 += zero - ozero;
  1.1241 +			addr2 += zero - ozero;
  1.1242 +			if (unddot) {
  1.1243 +				unddot += zero - ozero;
  1.1244 +				unddol += zero - ozero;
  1.1245 +			}
  1.1246 +			if (undzero) {
  1.1247 +				ozero = undzero;
  1.1248 +				if ((undzero = realloc(undzero,
  1.1249 +						nlall*sizeof *undzero)) == 0) {
  1.1250 +					puts("no memory for undo");
  1.1251 +					free(ozero);
  1.1252 +				}
  1.1253 +			}
  1.1254 +		}
  1.1255 +		tl = putline();
  1.1256 +		nline++;
  1.1257 +		a1 = ++dol;
  1.1258 +		a2 = a1+1;
  1.1259 +		rdot = ++dot;
  1.1260 +		while (a1 > rdot)
  1.1261 +			*--a2 = *--a1;
  1.1262 +		*rdot = tl;
  1.1263 +	}
  1.1264 +	return(nline);
  1.1265 +}
  1.1266 +
  1.1267 +static void
  1.1268 +callunix(void)
  1.1269 +{
  1.1270 +	char	*line;
  1.1271 +	void (*savint)(int);
  1.1272 +	pid_t pid, rpid;
  1.1273 +	int retcode;
  1.1274 +
  1.1275 +	setnoaddr();
  1.1276 +	line = readcmd();
  1.1277 +	if ((pid = fork()) == 0) {
  1.1278 +		sigset(SIGHUP, oldhup);
  1.1279 +		sigset(SIGQUIT, oldquit);
  1.1280 +		sigset(SIGPIPE, oldpipe);
  1.1281 +		execl(SHELL, "sh", "-c", line, NULL);
  1.1282 +		_exit(0100);
  1.1283 +	} else if (pid < 0)
  1.1284 +		error("fork failed - try again");
  1.1285 +	savint = sigset(SIGINT, SIG_IGN);
  1.1286 +	while ((rpid = wait(&retcode)) != pid && rpid != -1)
  1.1287 +		;
  1.1288 +	sigset(SIGINT, savint);
  1.1289 +	if (vflag)
  1.1290 +		puts("!");
  1.1291 +}
  1.1292 +
  1.1293 +#define	cmadd(c)	((i>=cmsize ? \
  1.1294 +		((line=realloc(line,cmsize+=128)) == 0 ? \
  1.1295 +			(error("line too long"),0) : 0, 0) \
  1.1296 +		: 0), line[i++]=(c))
  1.1297 +
  1.1298 +static char *
  1.1299 +readcmd(void)
  1.1300 +{
  1.1301 +	static char	*line, *prev;
  1.1302 +	static int	cmsize, pvsize;
  1.1303 +	char	*pp;
  1.1304 +	int	c, mod = 0, i;
  1.1305 +
  1.1306 +	i = 0;
  1.1307 +	if ((c = getchr()) == '!') {
  1.1308 +		for (pp = prev; *pp; pp++)
  1.1309 +			line[i++] = *pp;
  1.1310 +		mod = 1;
  1.1311 +		c = getchr();
  1.1312 +	}
  1.1313 +	while (c != '\n' && c != EOF) {
  1.1314 +		if (c == '\\') {
  1.1315 +			c = getchr();
  1.1316 +			if (c != '%')
  1.1317 +				cmadd('\\');
  1.1318 +			cmadd(c);
  1.1319 +		} else if (c == '%') {
  1.1320 +			for (pp = savedfile; *pp; pp++)
  1.1321 +				cmadd(*pp);
  1.1322 +			mod = 1;
  1.1323 +		} else
  1.1324 +			cmadd(c);
  1.1325 +		c = getchr();
  1.1326 +	}
  1.1327 +	cmadd('\0');
  1.1328 +	if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0)
  1.1329 +		error("line too long");
  1.1330 +	strcpy(prev, line);
  1.1331 +	if (mod)
  1.1332 +		nlputs(line);
  1.1333 +	return line;
  1.1334 +}
  1.1335 +
  1.1336 +static void
  1.1337 +quit(int signo)
  1.1338 +{
  1.1339 +	lastsig = signo;
  1.1340 +	if (vflag && fchange) {
  1.1341 +		fchange = 0;
  1.1342 +		error("warning: expecting `w'");
  1.1343 +	}
  1.1344 +	if (wrtemp)
  1.1345 +		unlink(wrtemp);
  1.1346 +	unlink(tfname);
  1.1347 +	exit(status);
  1.1348 +}
  1.1349 +
  1.1350 +static void
  1.1351 +delete(void)
  1.1352 +{
  1.1353 +	setdot();
  1.1354 +	newline();
  1.1355 +	nonzero();
  1.1356 +	checkpoint();
  1.1357 +	rdelete(addr1, addr2);
  1.1358 +}
  1.1359 +
  1.1360 +static void
  1.1361 +rdelete(long *ad1, long *ad2)
  1.1362 +{
  1.1363 +	register long *a1, *a2, *a3;
  1.1364 +
  1.1365 +	a1 = ad1;
  1.1366 +	a2 = ad2+1;
  1.1367 +	a3 = dol;
  1.1368 +	dol -= a2 - a1;
  1.1369 +	do {
  1.1370 +		*a1++ = *a2++;
  1.1371 +	} while (a2 <= a3);
  1.1372 +	a1 = ad1;
  1.1373 +	if (a1 > dol)
  1.1374 +		a1 = dol;
  1.1375 +	dot = a1;
  1.1376 +	fchange = 1;
  1.1377 +}
  1.1378 +
  1.1379 +static void
  1.1380 +gdelete(void)
  1.1381 +{
  1.1382 +	register long *a1, *a2, *a3;
  1.1383 +
  1.1384 +	a3 = dol;
  1.1385 +	for (a1=zero+1; (*a1&01)==0; a1++)
  1.1386 +		if (a1>=a3)
  1.1387 +			return;
  1.1388 +	for (a2=a1+1; a2<=a3;) {
  1.1389 +		if (*a2&01) {
  1.1390 +			a2++;
  1.1391 +			dot = a1;
  1.1392 +		} else
  1.1393 +			*a1++ = *a2++;
  1.1394 +	}
  1.1395 +	dol = a1-1;
  1.1396 +	if (dot>dol)
  1.1397 +		dot = dol;
  1.1398 +	fchange = 1;
  1.1399 +}
  1.1400 +
  1.1401 +static char *
  1.1402 +getline(long tl, int nulterm)
  1.1403 +{
  1.1404 +	register char *bp, *lp;
  1.1405 +	register long nl;
  1.1406 +
  1.1407 +	lp = linebuf;
  1.1408 +	bp = getblock(tl, READ);
  1.1409 +	nl = nleft;
  1.1410 +	tl &= ~0377;
  1.1411 +	while (*lp++ = *bp++) {
  1.1412 +		if (lp[-1] == '\n' && nulterm) {
  1.1413 +			lp[-1] = '\0';
  1.1414 +			break;
  1.1415 +		}
  1.1416 +		if (--nl == 0) {
  1.1417 +			bp = getblock(tl+=0400, READ);
  1.1418 +			nl = nleft;
  1.1419 +		}
  1.1420 +	}
  1.1421 +	return(linebuf);
  1.1422 +}
  1.1423 +
  1.1424 +static int
  1.1425 +putline(void)
  1.1426 +{
  1.1427 +	register char *bp, *lp;
  1.1428 +	register long nl;
  1.1429 +	long tl;
  1.1430 +
  1.1431 +	fchange = 1;
  1.1432 +	lp = linebuf;
  1.1433 +	tl = tline;
  1.1434 +	bp = getblock(tl, WRITE);
  1.1435 +	nl = nleft;
  1.1436 +	tl &= ~0377;
  1.1437 +	while (*bp = *lp++) {
  1.1438 +		if (*bp++ == '\n' && insub) {
  1.1439 +			*--bp = 0;
  1.1440 +			linebp = lp;
  1.1441 +			break;
  1.1442 +		}
  1.1443 +		if (--nl == 0) {
  1.1444 +			bp = getblock(tl+=0400, WRITE);
  1.1445 +			nl = nleft;
  1.1446 +		}
  1.1447 +	}
  1.1448 +	nl = tline;
  1.1449 +	tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1);
  1.1450 +	return(nl);
  1.1451 +}
  1.1452 +
  1.1453 +static char *
  1.1454 +getblock(long atl, long iof)
  1.1455 +{
  1.1456 +	register long bno, off;
  1.1457 +	
  1.1458 +	bno = (atl>>8)&BLKMSK;
  1.1459 +	off = (atl<<1)&0774;
  1.1460 +	if (bno >= BLKMSK) {
  1.1461 +		lastc = '\n';
  1.1462 +		error("temp file too big");
  1.1463 +	}
  1.1464 +	nleft = 512 - off;
  1.1465 +	if (bno==iblock) {
  1.1466 +		ichanged |= iof;
  1.1467 +		return(ibuff+off);
  1.1468 +	}
  1.1469 +	if (bno==oblock)
  1.1470 +		return(obuff+off);
  1.1471 +	if (iof==READ) {
  1.1472 +		if (ichanged)
  1.1473 +			blkio(iblock, ibuff, 1);
  1.1474 +		ichanged = 0;
  1.1475 +		iblock = bno;
  1.1476 +		blkio(bno, ibuff, 0);
  1.1477 +		return(ibuff+off);
  1.1478 +	}
  1.1479 +	if (oblock>=0)
  1.1480 +		blkio(oblock, obuff, 1);
  1.1481 +	oblock = bno;
  1.1482 +	return(obuff+off);
  1.1483 +}
  1.1484 +
  1.1485 +static void
  1.1486 +blkio(long b, char *buf, int wr)
  1.1487 +{
  1.1488 +	lseek(tfile, b<<9, SEEK_SET);
  1.1489 +	if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) {
  1.1490 +		status = 1;
  1.1491 +		error("I/O error on temp file");
  1.1492 +	}
  1.1493 +}
  1.1494 +
  1.1495 +static void
  1.1496 +init(void)
  1.1497 +{
  1.1498 +	register long *markp;
  1.1499 +
  1.1500 +	tline = 2;
  1.1501 +	for (markp = names; markp < &names[26]; markp++)
  1.1502 +		*markp = 0;
  1.1503 +	for (markp = undnames; markp < &undnames[26]; markp++)
  1.1504 +		*markp = 0;
  1.1505 +	subnewa = 0;
  1.1506 +	anymarks = 0;
  1.1507 +	iblock = -1;
  1.1508 +	oblock = -1;
  1.1509 +	ichanged = 0;
  1.1510 +	tfile = maketf(tfile);
  1.1511 +	dot = dol = zero;
  1.1512 +	unddot = NULL;
  1.1513 +}
  1.1514 +
  1.1515 +static void
  1.1516 +global(int k, int ia)
  1.1517 +{
  1.1518 +	register int c;
  1.1519 +	register long *a1;
  1.1520 +	static char *globuf;
  1.1521 +	char	mb[MB_LEN_MAX+1];
  1.1522 +	int	spflag = 0;
  1.1523 +
  1.1524 +	if (globp)
  1.1525 +		error("multiple globals not allowed");
  1.1526 +	setall();
  1.1527 +	nonzero();
  1.1528 +	if ((c=GETWC(mb))=='\n')
  1.1529 +		error("incomplete global expression");
  1.1530 +	compile(NULL, expbuf, &expbuf[ESIZE], c);
  1.1531 +	if (!ia) {
  1.1532 +		globrd(&globuf, EOF);
  1.1533 +		if (globuf[0] == '\n')
  1.1534 +			globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0';
  1.1535 +	} else {
  1.1536 +		newline();
  1.1537 +		spflag = pflag;
  1.1538 +		pflag = 0;
  1.1539 +	}
  1.1540 +	checkpoint();
  1.1541 +	for (a1=zero; a1<=dol; a1++) {
  1.1542 +		*a1 &= ~01;
  1.1543 +		if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k)
  1.1544 +			*a1 |= 01;
  1.1545 +	}
  1.1546 +	/*
  1.1547 +	 * Special case: g/.../d (avoid n^2 algorithm)
  1.1548 +	 */
  1.1549 +	if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
  1.1550 +		gdelete();
  1.1551 +		return;
  1.1552 +	}
  1.1553 +	for (a1=zero; a1<=dol; a1++) {
  1.1554 +		if (*a1 & 01) {
  1.1555 +			*a1 &= ~01;
  1.1556 +			dot = a1;
  1.1557 +			if (ia) {
  1.1558 +				puts(getline(*a1, 0));
  1.1559 +				if ((c = getchr()) == EOF)
  1.1560 +					error("command expected");
  1.1561 +				if (c == 'a' || c == 'c' || c == 'i')
  1.1562 +					error("a, i, or c not allowed in G");
  1.1563 +				else if (c == '&') {
  1.1564 +					if ((c = getchr()) != '\n')
  1.1565 +						error("end of line expected");
  1.1566 +					if (globuf == 0 || *globuf == 0)
  1.1567 +						error("no remembered command");
  1.1568 +				} else if (c == '\n') {
  1.1569 +					a1 = zero;
  1.1570 +					continue;
  1.1571 +				} else
  1.1572 +					globrd(&globuf, c);
  1.1573 +			}
  1.1574 +			globp = globuf;
  1.1575 +			commands();
  1.1576 +			globp = NULL;
  1.1577 +			a1 = zero;
  1.1578 +		}
  1.1579 +	}
  1.1580 +	if (ia)
  1.1581 +		pflag = spflag;
  1.1582 +}
  1.1583 +
  1.1584 +static void
  1.1585 +globrd(char **globuf, register int c)
  1.1586 +{
  1.1587 +	register int i;
  1.1588 +
  1.1589 +	if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0)
  1.1590 +		error("global too long");
  1.1591 +	i = 0;
  1.1592 +	if (c != EOF)
  1.1593 +		(*globuf)[i++] = c;
  1.1594 +	while ((c = getchr()) != '\n') {
  1.1595 +		if (c==EOF)
  1.1596 +			error("incomplete global expression");
  1.1597 +		if (c=='\\') {
  1.1598 +			c = getchr();
  1.1599 +			if (c!='\n')
  1.1600 +				(*globuf)[i++] = '\\';
  1.1601 +		}
  1.1602 +		(*globuf)[i++] = c;
  1.1603 +		if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0)
  1.1604 +			error("global too long");
  1.1605 +	}
  1.1606 +	(*globuf)[i++] = '\n';
  1.1607 +	(*globuf)[i++] = 0;
  1.1608 +}
  1.1609 +
  1.1610 +static void
  1.1611 +join(void)
  1.1612 +{
  1.1613 +	register int i, j;
  1.1614 +	register long *a1;
  1.1615 +
  1.1616 +	j = 0;
  1.1617 +	for (a1=addr1; a1<=addr2; a1++) {
  1.1618 +		i = getline(*a1, 0) - linebuf;
  1.1619 +		while (genbuf[j] = linebuf[i++])
  1.1620 +			if (j++ >= LBSIZE-2)
  1.1621 +				growlb("line too long");
  1.1622 +	}
  1.1623 +	i = 0;
  1.1624 +	j = 0;
  1.1625 +	while (linebuf[i++] = genbuf[j++])
  1.1626 +		;
  1.1627 +	*addr1 = putline();
  1.1628 +	if (addr1<addr2)
  1.1629 +		rdelete(addr1+1, addr2);
  1.1630 +	dot = addr1;
  1.1631 +}
  1.1632 +
  1.1633 +static void
  1.1634 +substitute(int inglob)
  1.1635 +{
  1.1636 +	register long *markp;
  1.1637 +	register long *a1;
  1.1638 +	intptr_t nl;
  1.1639 +	int gsubf;
  1.1640 +
  1.1641 +	checkpoint();
  1.1642 +	gsubf = compsub();
  1.1643 +	insub = 1;
  1.1644 +	for (a1 = addr1; a1 <= addr2; a1++) {
  1.1645 +		long *ozero;
  1.1646 +		if (execute(0, a1, 1)==0)
  1.1647 +			continue;
  1.1648 +		inglob |= dosub(gsubf < 2);
  1.1649 +		if (gsubf) {
  1.1650 +			int	i = 1;
  1.1651 +
  1.1652 +			while (*loc2) {
  1.1653 +				if (execute(1, NULL, 1)==0)
  1.1654 +					break;
  1.1655 +				inglob |= dosub(gsubf == -1 || ++i == gsubf);
  1.1656 +			}
  1.1657 +		}
  1.1658 +		subnewa = putline();
  1.1659 +		*a1 &= ~01;
  1.1660 +		if (anymarks) {
  1.1661 +			for (markp = names; markp < &names[26]; markp++)
  1.1662 +				if (*markp == *a1)
  1.1663 +					*markp = subnewa;
  1.1664 +		}
  1.1665 +		*a1 = subnewa;
  1.1666 +		ozero = zero;
  1.1667 +		nl = append(getsub, a1);
  1.1668 +		nl += zero-ozero;
  1.1669 +		a1 += nl;
  1.1670 +		addr2 += nl;
  1.1671 +	}
  1.1672 +	insub = 0;
  1.1673 +	if (inglob==0)
  1.1674 +		error("no match");
  1.1675 +}
  1.1676 +
  1.1677 +static int
  1.1678 +compsub(void)
  1.1679 +{
  1.1680 +	register int seof, c, i;
  1.1681 +	static char	*oldrhs;
  1.1682 +	static int	orhssz;
  1.1683 +	char	mb[MB_LEN_MAX+1];
  1.1684 +
  1.1685 +	if ((seof = GETWC(mb)) == '\n' || seof == ' ')
  1.1686 +		error("illegal or missing delimiter");
  1.1687 +	nodelim = 0;
  1.1688 +	compile(NULL, expbuf, &expbuf[ESIZE], seof);
  1.1689 +	i = 0;
  1.1690 +	for (;;) {
  1.1691 +		c = GETWC(mb);
  1.1692 +		if (c=='\\') {
  1.1693 +			if (i >= RHSIZE-2)
  1.1694 +				growrhs("replacement string too long");
  1.1695 +			rhsbuf[i++] = c;
  1.1696 +			c = GETWC(mb);
  1.1697 +		} else if (c=='\n') {
  1.1698 +			if (globp && *globp) {
  1.1699 +				if (i >= RHSIZE-2)
  1.1700 +					growrhs("replacement string too long");
  1.1701 +				rhsbuf[i++] = '\\';
  1.1702 +			}
  1.1703 +			else if (nodelim)
  1.1704 +				error("illegal or missing delimiter");
  1.1705 +			else {
  1.1706 +				peekc = c;
  1.1707 +				pflag++;
  1.1708 +				break;
  1.1709 +			}
  1.1710 +		} else if (c==seof)
  1.1711 +			break;
  1.1712 +		for (c = 0; c==0 || mb[c]; c++) {
  1.1713 +			if (i >= RHSIZE-2)
  1.1714 +				growrhs("replacement string too long");
  1.1715 +			rhsbuf[i++] = mb[c];
  1.1716 +		}
  1.1717 +	}
  1.1718 +	rhsbuf[i++] = 0;
  1.1719 +	if (rhsbuf[0] == '%' && rhsbuf[1] == 0) {
  1.1720 +		if (orhssz == 0)
  1.1721 +			error("no remembered replacement string");
  1.1722 +		strcpy(rhsbuf, oldrhs);
  1.1723 +	} else {
  1.1724 +		if (orhssz < RHSIZE &&
  1.1725 +				(oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0)
  1.1726 +			error("replacement string too long");
  1.1727 +		strcpy(oldrhs, rhsbuf);
  1.1728 +	}
  1.1729 +	if ((peekc = getchr()) == 'g') {
  1.1730 +		peekc = 0;
  1.1731 +		newline();
  1.1732 +		return(-1);
  1.1733 +	} else if (peekc >= '0' && peekc <= '9') {
  1.1734 +		c = getnum();
  1.1735 +		if (c < 1 || c > LBSIZE)
  1.1736 +			error("invalid count");
  1.1737 +		newline();
  1.1738 +		return c;
  1.1739 +	}
  1.1740 +	newline();
  1.1741 +	return(0);
  1.1742 +}
  1.1743 +
  1.1744 +static int
  1.1745 +getsub(void)
  1.1746 +{
  1.1747 +	register char *p1, *p2;
  1.1748 +
  1.1749 +	p1 = linebuf;
  1.1750 +	if ((p2 = linebp) == 0)
  1.1751 +		return(EOF);
  1.1752 +	while (*p1++ = *p2++)
  1.1753 +		;
  1.1754 +	linebp = 0;
  1.1755 +	return(0);
  1.1756 +}
  1.1757 +
  1.1758 +static int
  1.1759 +dosub(int really)
  1.1760 +{
  1.1761 +	register char *lp, *sp;
  1.1762 +	register int i, j, k;
  1.1763 +	int c;
  1.1764 +
  1.1765 +	if (!really)
  1.1766 +		goto copy;
  1.1767 +	i = 0;
  1.1768 +	j = 0;
  1.1769 +	k = 0;
  1.1770 +	while (&linebuf[i] < loc1)
  1.1771 +		genbuf[j++] = linebuf[i++];
  1.1772 +	while (c = rhsbuf[k++]&0377) {
  1.1773 +		if (c=='&') {
  1.1774 +			j = place(j, loc1, loc2);
  1.1775 +			continue;
  1.1776 +		} else if (c == '\\') {
  1.1777 +			c = rhsbuf[k++]&0377;
  1.1778 +			if (c >='1' && c < nbra+'1') {
  1.1779 +				j = place(j, braslist[c-'1'], braelist[c-'1']);
  1.1780 +				continue;
  1.1781 +			}
  1.1782 +		}
  1.1783 +		if (j >= LBSIZE)
  1.1784 +			growlb("line too long");
  1.1785 +		genbuf[j++] = c;
  1.1786 +	}
  1.1787 +	i = loc2 - linebuf;
  1.1788 +	loc2 = j + linebuf;
  1.1789 +#if defined (SUS) || defined (SU3) || defined (S42)
  1.1790 +	if (loc1 == &linebuf[i]) {
  1.1791 +		int	n;
  1.1792 +		wchar_t	wc;
  1.1793 +		if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0)
  1.1794 +			loc2 += n;
  1.1795 +		else
  1.1796 +			loc2++;
  1.1797 +	}
  1.1798 +#endif	/* SUS || SU3 || S42 */
  1.1799 +	while (genbuf[j++] = linebuf[i++])
  1.1800 +		if (j >= LBSIZE)
  1.1801 +			growlb("line too long");
  1.1802 +	if (really) {
  1.1803 +		lp = linebuf;
  1.1804 +		sp = genbuf;
  1.1805 +	} else {
  1.1806 +	copy:	sp = linebuf;
  1.1807 +		lp = genbuf;
  1.1808 +	}
  1.1809 +	while (*lp++ = *sp++)
  1.1810 +		;
  1.1811 +	return really;
  1.1812 +}
  1.1813 +
  1.1814 +static int
  1.1815 +place(register int j, register const char *l1, register const char *l2)
  1.1816 +{
  1.1817 +
  1.1818 +	while (l1 < l2) {
  1.1819 +		genbuf[j++] = *l1++;
  1.1820 +		if (j >= LBSIZE)
  1.1821 +			growlb("line too long");
  1.1822 +	}
  1.1823 +	return(j);
  1.1824 +}
  1.1825 +
  1.1826 +static void
  1.1827 +move(int cflag)
  1.1828 +{
  1.1829 +	register long *adt, *ad1, *ad2;
  1.1830 +
  1.1831 +	setdot();
  1.1832 +	nonzero();
  1.1833 +	if ((adt = address())==0)
  1.1834 +		error("illegal move destination");
  1.1835 +	newline();
  1.1836 +	checkpoint();
  1.1837 +	if (cflag) {
  1.1838 +		long *ozero;
  1.1839 +		intptr_t delta;
  1.1840 +		ad1 = dol;
  1.1841 +		ozero = zero;
  1.1842 +		append(getcopy, ad1++);
  1.1843 +		ad2 = dol;
  1.1844 +		delta = zero - ozero;
  1.1845 +		ad1 += delta;
  1.1846 +		adt += delta;
  1.1847 +	} else {
  1.1848 +		ad2 = addr2;
  1.1849 +		for (ad1 = addr1; ad1 <= ad2;)
  1.1850 +			*ad1++ &= ~01;
  1.1851 +		ad1 = addr1;
  1.1852 +	}
  1.1853 +	ad2++;
  1.1854 +	if (adt<ad1) {
  1.1855 +		dot = adt + (ad2-ad1);
  1.1856 +		if ((++adt)==ad1)
  1.1857 +			return;
  1.1858 +		reverse(adt, ad1);
  1.1859 +		reverse(ad1, ad2);
  1.1860 +		reverse(adt, ad2);
  1.1861 +	} else if (adt >= ad2) {
  1.1862 +		dot = adt++;
  1.1863 +		reverse(ad1, ad2);
  1.1864 +		reverse(ad2, adt);
  1.1865 +		reverse(ad1, adt);
  1.1866 +	} else
  1.1867 +		error("illegal move destination");
  1.1868 +	fchange = 1;
  1.1869 +}
  1.1870 +
  1.1871 +static void
  1.1872 +reverse(register long *a1, register long *a2)
  1.1873 +{
  1.1874 +	register int t;
  1.1875 +
  1.1876 +	for (;;) {
  1.1877 +		t = *--a2;
  1.1878 +		if (a2 <= a1)
  1.1879 +			return;
  1.1880 +		*a2 = *a1;
  1.1881 +		*a1++ = t;
  1.1882 +	}
  1.1883 +}
  1.1884 +
  1.1885 +static int
  1.1886 +getcopy(void)
  1.1887 +{
  1.1888 +	if (addr1 > addr2)
  1.1889 +		return(EOF);
  1.1890 +	getline(*addr1++, 0);
  1.1891 +	return(0);
  1.1892 +}
  1.1893 +
  1.1894 +static int
  1.1895 +execute(int gf, long *addr, int subst)
  1.1896 +{
  1.1897 +	register char *p1, *p2, c;
  1.1898 +
  1.1899 +	for (c=0; c<NBRA; c++) {
  1.1900 +		braslist[c&0377] = 0;
  1.1901 +		braelist[c&0377] = 0;
  1.1902 +	}
  1.1903 +	if (gf) {
  1.1904 +		if (circf)
  1.1905 +			return(0);
  1.1906 +		p1 = linebuf;
  1.1907 +		p2 = genbuf;
  1.1908 +		while (*p1++ = *p2++)
  1.1909 +			;
  1.1910 +		locs = p1 = loc2;
  1.1911 +	} else {
  1.1912 +		if (addr==zero)
  1.1913 +			return(0);
  1.1914 +		p1 = getline(*addr, 1);
  1.1915 +		locs = 0;
  1.1916 +	}
  1.1917 +	needsub = subst;
  1.1918 +	return step(p1, expbuf);
  1.1919 +}
  1.1920 +
  1.1921 +static void
  1.1922 +cmplerr(int c)
  1.1923 +{
  1.1924 +	const char	*msg;
  1.1925 +
  1.1926 +#if !defined (SUS) && !defined (S42) && !defined (SU3)
  1.1927 +	expbuf[0] = 0;
  1.1928 +#endif
  1.1929 +	switch (c) {
  1.1930 +	case 11:
  1.1931 +		msg = "Range endpoint too large";
  1.1932 +		break;
  1.1933 +	case 16:
  1.1934 +		msg = "bad number";
  1.1935 +		break;
  1.1936 +	case 25:
  1.1937 +		msg = "`\\digit' out of range";
  1.1938 +		break;
  1.1939 +	case 36:
  1.1940 +		msg = "illegal or missing delimiter";
  1.1941 +		break;
  1.1942 +	case 41:
  1.1943 +		msg = "no remembered search string";
  1.1944 +		break;
  1.1945 +	case 42:
  1.1946 +		msg = "'\\( \\)' imbalance";
  1.1947 +		break;
  1.1948 +	case 43:
  1.1949 +		msg = "Too many `\\(' s";
  1.1950 +		break;
  1.1951 +	case 44:
  1.1952 +		msg = "more than 2 numbers given";
  1.1953 +		break;
  1.1954 +	case 45:
  1.1955 +		msg = "'\\}' expected";
  1.1956 +		break;
  1.1957 +	case 46:
  1.1958 +		msg = "first number exceeds second";
  1.1959 +		break;
  1.1960 +	case 49:
  1.1961 +		msg = "'[ ]' imbalance";
  1.1962 +		break;
  1.1963 +	case 50:
  1.1964 +		msg = "regular expression overflow";
  1.1965 +		break;
  1.1966 +	case 67:
  1.1967 +		msg = "illegal byte sequence";
  1.1968 +		break;
  1.1969 +	default:
  1.1970 +		msg = "regular expression error";
  1.1971 +		break;
  1.1972 +	}
  1.1973 +	error(msg);
  1.1974 +}
  1.1975 +
  1.1976 +static void
  1.1977 +doprnt(long *bot, long *top)
  1.1978 +{
  1.1979 +	long	*a1;
  1.1980 +
  1.1981 +	a1 = bot;
  1.1982 +	do {
  1.1983 +		if (numbf ^ Nflag) {
  1.1984 +			putd(a1-zero);
  1.1985 +			putchr('\t');
  1.1986 +		}
  1.1987 +		nlputs(getline(*a1++, 0));
  1.1988 +	} while (a1 <= top);
  1.1989 +	pflag = 0;
  1.1990 +	listf = 0;
  1.1991 +	numbf = 0;
  1.1992 +}
  1.1993 +
  1.1994 +static void
  1.1995 +putd(long c)
  1.1996 +{
  1.1997 +	register int r;
  1.1998 +
  1.1999 +	r = c%10;
  1.2000 +	c /= 10;
  1.2001 +	if (c)
  1.2002 +		putd(c);
  1.2003 +	putchr(r + '0');
  1.2004 +}
  1.2005 +
  1.2006 +static void
  1.2007 +nlputs(register const char *sp)
  1.2008 +{
  1.2009 +	if (listf)
  1.2010 +		list(sp);
  1.2011 +	else if (tabstops)
  1.2012 +		expand(sp);
  1.2013 +	else
  1.2014 +		puts(sp);
  1.2015 +}
  1.2016 +
  1.2017 +static void
  1.2018 +puts(register const char *sp)
  1.2019 +{
  1.2020 +	while (*sp) {
  1.2021 +		if (*sp != '\n')
  1.2022 +			putchr(*sp++ & 0377);
  1.2023 +		else
  1.2024 +			sp++, putchr('\0');
  1.2025 +	}
  1.2026 +	putchr('\n');
  1.2027 +}
  1.2028 +
  1.2029 +static void
  1.2030 +list(const char *lp)
  1.2031 +{
  1.2032 +	int col, n;
  1.2033 +	wchar_t c;
  1.2034 +
  1.2035 +	col = numbf ^ Nflag ? 8 : 0;
  1.2036 +	while (*lp) {
  1.2037 +		if (mb_cur_max > 1 && *lp&0200)
  1.2038 +			n = mbtowc(&c, lp, mb_cur_max);
  1.2039 +		else {
  1.2040 +			n = 1;
  1.2041 +			c = *lp&0377;
  1.2042 +		}
  1.2043 +		if (col+1 >= 72) {
  1.2044 +			col = 0;
  1.2045 +			putchr('\\');
  1.2046 +			putchr('\n');
  1.2047 +		}
  1.2048 +		if (n<0 ||
  1.2049 +#if defined (SUS) || defined (S42) || defined (SU3)
  1.2050 +				c == '\\' ||
  1.2051 +#endif	/* SUS || S42 || SU3 */
  1.2052 +				!(mb_cur_max>1 ? iswprint(c) : isprint(c))) {
  1.2053 +			if (n<0)
  1.2054 +				n = 1;
  1.2055 +			while (n--)
  1.2056 +				col += lstchr(*lp++&0377);
  1.2057 +		} else if (mb_cur_max>1) {
  1.2058 +			col += wcwidth(c);
  1.2059 +			while (n--)
  1.2060 +				putchr(*lp++&0377);
  1.2061 +		} else {
  1.2062 +			putchr(*lp++&0377);
  1.2063 +			col++;
  1.2064 +		}
  1.2065 +	}
  1.2066 +#if defined (SUS) || defined (S42) || defined (SU3)
  1.2067 +	putchr('$');
  1.2068 +#endif
  1.2069 +	putchr('\n');
  1.2070 +}
  1.2071 +
  1.2072 +static int
  1.2073 +lstchr(int c)
  1.2074 +{
  1.2075 +	int	cad = 1, d;
  1.2076 +
  1.2077 +#if !defined (SUS) && !defined (S42) && !defined (SU3)
  1.2078 +	if (c=='\t') {
  1.2079 +		c = '>';
  1.2080 +		goto esc;
  1.2081 +	}
  1.2082 +	if (c=='\b') {
  1.2083 +		c = '<';
  1.2084 +	esc:
  1.2085 +		putchr('-');
  1.2086 +		putchr('\b');
  1.2087 +		putchr(c);
  1.2088 +	} else if (c == '\n') {
  1.2089 +		putchr('\\');
  1.2090 +		putchr('0');
  1.2091 +		putchr('0');
  1.2092 +		putchr('0');
  1.2093 +		cad = 4;
  1.2094 +#else	/* !SUS, !S42, !SU3 */
  1.2095 +	if (c == '\n')
  1.2096 +		c = '\0';
  1.2097 +	if (c == '\\') {
  1.2098 +		putchr('\\');
  1.2099 +		putchr('\\');
  1.2100 +		cad = 2;
  1.2101 +	} else if (c == '\a') {
  1.2102 +		putchr('\\');
  1.2103 +		putchr('a');
  1.2104 +		cad = 2;
  1.2105 +	} else if (c == '\b') {
  1.2106 +		putchr('\\');
  1.2107 +		putchr('b');
  1.2108 +		cad = 2;
  1.2109 +	} else if (c == '\f') {
  1.2110 +		putchr('\\');
  1.2111 +		putchr('f');
  1.2112 +		cad = 2;
  1.2113 +	} else if (c == '\r') {
  1.2114 +		putchr('\\');
  1.2115 +		putchr('r');
  1.2116 +		cad = 2;
  1.2117 +	} else if (c == '\t') {
  1.2118 +		putchr('\\');
  1.2119 +		putchr('t');
  1.2120 +		cad = 2;
  1.2121 +	} else if (c == '\v') {
  1.2122 +		putchr('\\');
  1.2123 +		putchr('v');
  1.2124 +		cad = 2;
  1.2125 +#endif	/* !SUS, !S42, !SU3 */
  1.2126 +	} else {
  1.2127 +		putchr('\\');
  1.2128 +		putchr(((c&~077)>>6)+'0');
  1.2129 +		c &= 077;
  1.2130 +		d = c & 07;
  1.2131 +		putchr(c > d ? ((c-d)>>3)+'0' : '0');
  1.2132 +		putchr(d+'0');
  1.2133 +		cad = 4;
  1.2134 +	}
  1.2135 +	return cad;
  1.2136 +}
  1.2137 +
  1.2138 +static void
  1.2139 +putstr(const char *s)
  1.2140 +{
  1.2141 +	while (*s)
  1.2142 +		putchr(*s++);
  1.2143 +}
  1.2144 +
  1.2145 +static char	line[70];
  1.2146 +static char	*linp	= line;
  1.2147 +
  1.2148 +static void
  1.2149 +putchr(int ac)
  1.2150 +{
  1.2151 +	register char *lp;
  1.2152 +	register int c;
  1.2153 +
  1.2154 +	lp = linp;
  1.2155 +	c = ac;
  1.2156 +	*lp++ = c;
  1.2157 +	if(c == '\n' || lp >= &line[64]) {
  1.2158 +		linp = line;
  1.2159 +		write(1, line, lp-line);
  1.2160 +		return;
  1.2161 +	}
  1.2162 +	linp = lp;
  1.2163 +}
  1.2164 +
  1.2165 +static void
  1.2166 +checkpoint(void)
  1.2167 +{
  1.2168 +	long	*a1, *a2;
  1.2169 +
  1.2170 +	if (undzero && globp == NULL) {
  1.2171 +		for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++)
  1.2172 +			*a2 = *a1;
  1.2173 +		unddot = &undzero[dot-zero];
  1.2174 +		unddol = &undzero[dol-zero];
  1.2175 +		for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++)
  1.2176 +			*a2 = *a1;
  1.2177 +	}
  1.2178 +}
  1.2179 +
  1.2180 +#define	swap(a, b)	(t = a, a = b, b = t)
  1.2181 +
  1.2182 +static void
  1.2183 +undo(void)
  1.2184 +{
  1.2185 +	long	*t;
  1.2186 +
  1.2187 +	if (undzero == NULL)
  1.2188 +		error("no undo information saved");
  1.2189 +	swap(zero, undzero);
  1.2190 +	swap(dot, unddot);
  1.2191 +	swap(dol, unddol);
  1.2192 +	swap(names, undnames);
  1.2193 +}
  1.2194 +
  1.2195 +static int
  1.2196 +maketf(int fd)
  1.2197 +{
  1.2198 +	char	*tmpdir;
  1.2199 +
  1.2200 +	if (fd == -1) {
  1.2201 +		if ((tmpdir = getenv("TMPDIR")) == NULL ||
  1.2202 +				(fd = creatf(tmpdir)) < 0)
  1.2203 +			if ((fd = creatf("/var/tmp")) < 0 &&
  1.2204 +					(fd = creatf("/tmp")) < 0)
  1.2205 +				error("cannot create temporary file");
  1.2206 +	} else
  1.2207 +		ftruncate(fd, 0);	/* blkio() will seek to 0 anyway */
  1.2208 +	return fd;
  1.2209 +}
  1.2210 +
  1.2211 +static int
  1.2212 +creatf(const char *tmpdir)
  1.2213 +{
  1.2214 +	if (strlen(tmpdir) >= sizeof tfname - 9)
  1.2215 +		return -1;
  1.2216 +	strcpy(tfname, tmpdir);
  1.2217 +	strcat(tfname, "/eXXXXXX");
  1.2218 +	return mkstemp(tfname);
  1.2219 +}
  1.2220 +
  1.2221 +static int
  1.2222 +sopen(const char *fn, int rdwr)
  1.2223 +{
  1.2224 +	int	pf[2], fd = -1;
  1.2225 +
  1.2226 +	if (fn[0] == '!') {
  1.2227 +		fn++;
  1.2228 +		if (pipe(pf) < 0)
  1.2229 +			error("write or open on pipe failed");
  1.2230 +		switch (pipid = fork()) {
  1.2231 +		case 0:
  1.2232 +			if (rdwr == READ)
  1.2233 +				dup2(pf[1], 1);
  1.2234 +			else
  1.2235 +				dup2(pf[0], 0);
  1.2236 +			close(pf[0]);
  1.2237 +			close(pf[1]);
  1.2238 +			sigset(SIGHUP, oldhup);
  1.2239 +			sigset(SIGQUIT, oldquit);
  1.2240 +			sigset(SIGPIPE, oldpipe);
  1.2241 +			execl(SHELL, "sh", "-c", fn, NULL);
  1.2242 +			_exit(0100);
  1.2243 +		default:
  1.2244 +			close(pf[rdwr == READ ? 1 : 0]);
  1.2245 +			fd = pf[rdwr == READ ? 0 : 1];
  1.2246 +			break;
  1.2247 +		case -1:
  1.2248 +			error("fork failed - try again");
  1.2249 +		}
  1.2250 +	} else if (rdwr == READ)
  1.2251 +		fd = open(fn, O_RDONLY);
  1.2252 +	else if (rdwr == EXIST)
  1.2253 +		fd = open(fn, O_WRONLY);
  1.2254 +	else /*if (rdwr == WRITE)*/
  1.2255 +		fd = creat(fn, 0666);
  1.2256 +	if (fd >= 0 && rdwr == READ)
  1.2257 +		readop = 1;
  1.2258 +	if (fd >= 0)
  1.2259 +		fstat(fd, &fstbuf);
  1.2260 +	return fd;
  1.2261 +}
  1.2262 +
  1.2263 +static void
  1.2264 +sclose(int fd)
  1.2265 +{
  1.2266 +	int	status;
  1.2267 +
  1.2268 +	close(fd);
  1.2269 +	if (pipid >= 0) {
  1.2270 +		while (wait(&status) != pipid);
  1.2271 +		pipid = -1;
  1.2272 +	}
  1.2273 +	readop = 0;
  1.2274 +}
  1.2275 +
  1.2276 +static void
  1.2277 +fspec(const char *lp)
  1.2278 +{
  1.2279 +	struct termios	ts;
  1.2280 +	const char	*cp;
  1.2281 +
  1.2282 +	freetabs();
  1.2283 +	maxlength = 0;
  1.2284 +	if (tcgetattr(1, &ts) < 0
  1.2285 +#ifdef	TAB3
  1.2286 +			|| (ts.c_oflag&TAB3) == 0
  1.2287 +#endif
  1.2288 +			)
  1.2289 +		return;
  1.2290 +	while (lp[0]) {
  1.2291 +		if (lp[0] == '<' && lp[1] == ':')
  1.2292 +			break;
  1.2293 +		lp++;
  1.2294 +	}
  1.2295 +	if (lp[0]) {
  1.2296 +		lp += 2;
  1.2297 +		while ((cp = ftok(&lp)) != NULL) {
  1.2298 +			switch (*cp) {
  1.2299 +			case 't':
  1.2300 +				freetabs();
  1.2301 +				if ((tabstops = tabstring(&cp[1])) == NULL)
  1.2302 +					goto err;
  1.2303 +				break;
  1.2304 +			case 's':
  1.2305 +				maxlength = atoi(&cp[1]);
  1.2306 +				break;
  1.2307 +			case 'm':
  1.2308 +			case 'd':
  1.2309 +			case 'e':
  1.2310 +				break;
  1.2311 +			case ':':
  1.2312 +				if (cp[1] == '>') {
  1.2313 +					if (tabstops == NULL)
  1.2314 +						if ((tabstops = tabstring("0"))
  1.2315 +								== NULL)
  1.2316 +							goto err;
  1.2317 +					return;
  1.2318 +				}
  1.2319 +				/*FALLTHRU*/
  1.2320 +			default:
  1.2321 +			err:	freetabs();
  1.2322 +				maxlength = 0;
  1.2323 +				errput("PWB spec problem", NULL);
  1.2324 +				return;
  1.2325 +			}
  1.2326 +		}
  1.2327 +	}
  1.2328 +}
  1.2329 +
  1.2330 +static const char *
  1.2331 +ftok(const char **lp)
  1.2332 +{
  1.2333 +	const char	*cp;
  1.2334 +
  1.2335 +	while (**lp && **lp != ':' && (**lp == ' ' || **lp == '\t'))
  1.2336 +		(*lp)++;
  1.2337 +	cp = *lp;
  1.2338 +	while (**lp && **lp != ':' && **lp != ' ' && **lp != '\t')
  1.2339 +		(*lp)++;
  1.2340 +	return cp;
  1.2341 +}
  1.2342 +
  1.2343 +static struct tabulator *
  1.2344 +repetitive(int repetition)
  1.2345 +{
  1.2346 +	struct tabulator	*tp, *tabspec;
  1.2347 +	int	col, i;
  1.2348 +
  1.2349 +	if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL)
  1.2350 +		return NULL;
  1.2351 +	tp->t_rep = repetition;
  1.2352 +	if (repetition > 0) {
  1.2353 +		 for (col = 1+repetition, i = 0; i < 22; col += repetition) {
  1.2354 +			if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL)
  1.2355 +				return NULL;
  1.2356 +			tp = tp->t_nxt;
  1.2357 +			tp->t_tab = col;
  1.2358 +		}
  1.2359 +	}
  1.2360 +	return tabspec;
  1.2361 +}
  1.2362 +
  1.2363 +#define	blank(c)	((c) == ' ' || (c) == '\t')
  1.2364 +
  1.2365 +static struct tabulator *
  1.2366 +tablist(const char *s)
  1.2367 +{
  1.2368 +	struct tabulator	*tp, *tabspec;
  1.2369 +	char	*x;
  1.2370 +	int	prev = 0, val;
  1.2371 +
  1.2372 +	if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL)
  1.2373 +		return NULL;
  1.2374 +	for (;;) {
  1.2375 +		while (*s == ',')
  1.2376 +			s++;
  1.2377 +		if (*s == '\0' || blank(*s) || *s == ':')
  1.2378 +			break;
  1.2379 +		val = strtol(s, &x, 10);
  1.2380 +		if (*s == '+')
  1.2381 +			val += prev;
  1.2382 +		prev = val;
  1.2383 +		if (*s == '-' || (*x != ',' && !blank(*x) && *x != ':' &&
  1.2384 +					*x != '\0'))
  1.2385 +			return NULL;
  1.2386 +		s = x;
  1.2387 +		if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL)
  1.2388 +			return NULL;
  1.2389 +		tp = tp->t_nxt;
  1.2390 +		tp->t_tab = val;
  1.2391 +	}
  1.2392 +	return tabspec;
  1.2393 +}
  1.2394 +
  1.2395 +static struct tabulator *
  1.2396 +tabstring(const char *s)
  1.2397 +{
  1.2398 +	const struct {
  1.2399 +		const char	*c_nam;
  1.2400 +		const char	*c_str;
  1.2401 +	} canned[] = {
  1.2402 +		{ "a",	"1,10,16,36,72" },
  1.2403 +		{ "a2",	"1,10,16,40,72" },
  1.2404 +		{ "c",	"1,8,12,16,20,55" },
  1.2405 +		{ "c2",	"1,6,10,14,49" },
  1.2406 +		{ "c3",	"1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67" },
  1.2407 +		{ "f",	"1,7,11,15,19,23" },
  1.2408 +		{ "p",	"1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61" },
  1.2409 +		{ "s",	"1,10,55" },
  1.2410 +		{ "u",	"1,12,20,44" },
  1.2411 +		{ 0,	0 }
  1.2412 +	};
  1.2413 +
  1.2414 +	int	i, j;
  1.2415 +
  1.2416 +	if (s[0] == '-') {
  1.2417 +		if (s[1] >= '0' && s[1] <= '9' && ((i = atoi(&s[1])) != 0))
  1.2418 +			return repetitive(i);
  1.2419 +		for (i = 0; canned[i].c_nam; i++) {
  1.2420 +			for (j = 0; canned[i].c_nam[j]; j++)
  1.2421 +				if (s[j+1] != canned[i].c_nam[j])
  1.2422 +					break;
  1.2423 +			if ((s[j+1]=='\0' || s[j+1]==':' || blank(s[j+1])) &&
  1.2424 +					canned[i].c_nam[j] == '\0')
  1.2425 +				return tablist(canned[i].c_str);
  1.2426 +		}
  1.2427 +		return NULL;
  1.2428 +	} else
  1.2429 +		return tablist(s);
  1.2430 +}
  1.2431 +
  1.2432 +static void
  1.2433 +freetabs(void)
  1.2434 +{
  1.2435 +	struct tabulator	*tp;
  1.2436 +
  1.2437 +	tp = tabstops;
  1.2438 +	while (tp) {
  1.2439 +		tabstops = tp->t_nxt;
  1.2440 +		free(tp);
  1.2441 +		tp = tabstops;
  1.2442 +	}
  1.2443 +}
  1.2444 +
  1.2445 +static void
  1.2446 +expand(const char *s)
  1.2447 +{
  1.2448 +	struct tabulator	*tp = tabstops;
  1.2449 +	int	col = 0, n = 1, m, tabcnt = 0, nspc;
  1.2450 +	wchar_t	wc;
  1.2451 +
  1.2452 +	while (*s) {
  1.2453 +		nspc = 0;
  1.2454 +		switch (*s) {
  1.2455 +		case '\n':
  1.2456 +			putchr('\0');
  1.2457 +			s++;
  1.2458 +			continue;
  1.2459 +		case '\t':
  1.2460 +			if (tp) {
  1.2461 +				if (tp->t_rep) {
  1.2462 +					if (col % tp->t_rep == 0) {
  1.2463 +						nspc++;
  1.2464 +						col++;
  1.2465 +					}
  1.2466 +					while (col % tp->t_rep) {
  1.2467 +						nspc++;
  1.2468 +						col++;
  1.2469 +					}
  1.2470 +					break;
  1.2471 +				}
  1.2472 +				while (tp && (col>tp->t_tab || tp->t_tab == 0))
  1.2473 +					tp = tp->t_nxt;
  1.2474 +				if (tp && col == tp->t_tab) {
  1.2475 +					nspc++;
  1.2476 +					col++;
  1.2477 +					tp = tp->t_nxt;
  1.2478 +				}
  1.2479 +				if (tp) {
  1.2480 +					while (col < tp->t_tab) {
  1.2481 +						nspc++;
  1.2482 +						col++;
  1.2483 +					}
  1.2484 +					tp = tp->t_nxt;
  1.2485 +					break;
  1.2486 +				}
  1.2487 +			}
  1.2488 +			tabcnt = 1;
  1.2489 +			nspc++;
  1.2490 +			break;
  1.2491 +		default:
  1.2492 +			if (mb_cur_max>1 && (n=mbtowc(&wc, s, mb_cur_max))>0) {
  1.2493 +				if ((m = wcwidth(wc)) > 0)
  1.2494 +					col += m;
  1.2495 +			} else {
  1.2496 +				col++;
  1.2497 +				n = 1;
  1.2498 +			}
  1.2499 +		}
  1.2500 +		if (maxlength && col > maxlength) {
  1.2501 +			putstr("\ntoo long");
  1.2502 +			break;
  1.2503 +		}
  1.2504 +		if (nspc) {
  1.2505 +			while (nspc--)
  1.2506 +				putchr(' ');
  1.2507 +			s++;
  1.2508 +		} else
  1.2509 +			while (n--)
  1.2510 +				putchr(*s++);
  1.2511 +	}
  1.2512 +	if (tabcnt)
  1.2513 +		putstr("\ntab count");
  1.2514 +	putchr('\n');
  1.2515 +}
  1.2516 +
  1.2517 +static wint_t
  1.2518 +GETWC(char *mb)
  1.2519 +{
  1.2520 +	int	c, n;
  1.2521 +
  1.2522 +	n = 1;
  1.2523 +	mb[0] = c = GETC();
  1.2524 +	mb[1] = '\0';
  1.2525 +	if (mb_cur_max > 1 && c&0200 && c != EOF) {
  1.2526 +		int	m;
  1.2527 +		wchar_t	wc;
  1.2528 +
  1.2529 +		while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n<mb_cur_max) {
  1.2530 +			mb[n++] = c = GETC();
  1.2531 +			mb[n] = '\0';
  1.2532 +			if (c == '\n' || c == EOF)
  1.2533 +				break;
  1.2534 +		}
  1.2535 +		if (m != n)
  1.2536 +			ERROR(67);
  1.2537 +		return wc;
  1.2538 +	} else
  1.2539 +		return c;
  1.2540 +}
  1.2541 +
  1.2542 +static void
  1.2543 +growlb(const char *msg)
  1.2544 +{
  1.2545 +	char	*olb = linebuf;
  1.2546 +	int	i;
  1.2547 +
  1.2548 +	LBSIZE += 512;
  1.2549 +	if ((linebuf = realloc(linebuf, LBSIZE)) == NULL ||
  1.2550 +			(genbuf = realloc(genbuf, LBSIZE)) == NULL)
  1.2551 +		error(msg);
  1.2552 +	if (linebuf != olb) {
  1.2553 +		loc1 += linebuf - olb;
  1.2554 +		loc2 += linebuf - olb;
  1.2555 +		for (i = 0; i < NBRA; i++) {
  1.2556 +			if (braslist[i])
  1.2557 +				braslist[i] += linebuf - olb;
  1.2558 +			if (braelist[i])
  1.2559 +				braelist[i] += linebuf - olb;
  1.2560 +		}
  1.2561 +	}
  1.2562 +}
  1.2563 +
  1.2564 +static void
  1.2565 +growrhs(const char *msg)
  1.2566 +{
  1.2567 +	RHSIZE += 256;
  1.2568 +	if ((rhsbuf = realloc(rhsbuf, RHSIZE)) == NULL)
  1.2569 +		error(msg);
  1.2570 +}
  1.2571 +
  1.2572 +static void
  1.2573 +growfn(const char *msg)
  1.2574 +{
  1.2575 +	FNSIZE += 64;
  1.2576 +	if ((savedfile = realloc(savedfile, FNSIZE)) == NULL ||
  1.2577 +			(file = realloc(file, FNSIZE)) == NULL)
  1.2578 +		error(msg);
  1.2579 +	if (FNSIZE == 64)
  1.2580 +		file[0] = savedfile[0] = 0;
  1.2581 +}
  1.2582 +
  1.2583 +#if defined (SUS) || defined (S42) || defined (SU3)
  1.2584 +union	ptrstore {
  1.2585 +	void	*vp;
  1.2586 +	char	bp[sizeof (void *)];
  1.2587 +};
  1.2588 +
  1.2589 +static void *
  1.2590 +fetchptr(const char *bp)
  1.2591 +{
  1.2592 +	union ptrstore	u;
  1.2593 +	int	i;
  1.2594 +
  1.2595 +	for (i = 0; i < sizeof (void *); i++)
  1.2596 +		u.bp[i] = bp[i];
  1.2597 +	return u.vp;
  1.2598 +}
  1.2599 +
  1.2600 +static void
  1.2601 +storeptr(void *vp, char *bp)
  1.2602 +{
  1.2603 +	union ptrstore	u;
  1.2604 +	int	i;
  1.2605 +
  1.2606 +	u.vp = vp;
  1.2607 +	for (i = 0; i < sizeof (void *); i++)
  1.2608 +		bp[i] = u.bp[i];
  1.2609 +}
  1.2610 +
  1.2611 +#define	add(c)	((i>=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \
  1.2612 +		genbuf[i++] = (c))
  1.2613 +
  1.2614 +#define	copy(s)	{ \
  1.2615 +	int	m; \
  1.2616 +	for (m = 0; m==0 || s[m]; m++) \
  1.2617 +		add(s[m]); \
  1.2618 +}
  1.2619 +
  1.2620 +static char *
  1.2621 +compile(char *unused, char *ep, const char *endbuf, int seof)
  1.2622 +{
  1.2623 +	INIT
  1.2624 +	int	c, d, i;
  1.2625 +	regex_t	*rp;
  1.2626 +	char	*op;
  1.2627 +	char	mb[MB_LEN_MAX+1];
  1.2628 +
  1.2629 +	op = ep;
  1.2630 +	ep += 2;
  1.2631 +	if ((rp = fetchptr(ep)) == NULL) {
  1.2632 +		if ((rp = calloc(1, sizeof *rp)) == NULL)
  1.2633 +			ERROR(50);
  1.2634 +		storeptr(rp, ep);
  1.2635 +	}
  1.2636 +	ep += sizeof (void *);
  1.2637 +	i = 0;
  1.2638 +	nbra = 0;
  1.2639 +	do {
  1.2640 +		if ((c = GETWC(mb)) == seof)
  1.2641 +			add('\0');
  1.2642 +		else if (c == '\\') {
  1.2643 +			copy(mb);
  1.2644 +			c = GETWC(mb);
  1.2645 +			if (c == '(')
  1.2646 +				nbra++;
  1.2647 +			goto normchar;
  1.2648 +		} else if (c == '[') {
  1.2649 +			add(c);
  1.2650 +			d = EOF;
  1.2651 +			do {
  1.2652 +				c = GETWC(mb);
  1.2653 +				if (c == EOF || c == '\n')
  1.2654 +					ERROR(49);
  1.2655 +				copy(mb);
  1.2656 +				if (d=='[' && (c==':' || c=='.' || c=='=')) {
  1.2657 +					d = c;
  1.2658 +					do {
  1.2659 +						c = GETWC(mb);
  1.2660 +						if (c == EOF || c == '\n')
  1.2661 +							ERROR(49);
  1.2662 +						copy(mb);
  1.2663 +					} while (c != d || PEEKC() != ']');
  1.2664 +					c = GETWC(mb);
  1.2665 +					copy(mb);
  1.2666 +					c = EOF;
  1.2667 +				}
  1.2668 +				d = c;
  1.2669 +			} while (c != ']');
  1.2670 +		} else {
  1.2671 +			if (c == EOF || c == '\n') {
  1.2672 +				if (c == '\n')
  1.2673 +					UNGETC(c);
  1.2674 +				mb[0] = c = '\0';
  1.2675 +			}
  1.2676 +			if (c == '\0')
  1.2677 +				nodelim = 1;
  1.2678 +	normchar:	copy(mb);
  1.2679 +		}
  1.2680 +	} while (genbuf[i-1] != '\0');
  1.2681 +	if (genbuf[0]) {
  1.2682 +		int	reflags = 0;
  1.2683 +
  1.2684 +#ifdef	REG_ANGLES
  1.2685 +		reflags |= REG_ANGLES;
  1.2686 +#endif
  1.2687 +#if defined (SU3) && defined (REG_AVOIDNULL)
  1.2688 +		reflags |= REG_AVOIDNULL;
  1.2689 +#endif
  1.2690 +		if (op[0])
  1.2691 +			regfree(rp);
  1.2692 +		op[0] = 0;
  1.2693 +		switch (regcomp(rp, genbuf, reflags)) {
  1.2694 +		case 0:
  1.2695 +			break;
  1.2696 +		case REG_ESUBREG:
  1.2697 +			ERROR(25);
  1.2698 +			/*NOTREACHED*/
  1.2699 +		case REG_EBRACK:
  1.2700 +			ERROR(49);
  1.2701 +			/*NOTREACHED*/
  1.2702 +		case REG_EPAREN:
  1.2703 +			ERROR(42);
  1.2704 +			/*NOTREACHED*/
  1.2705 +		case REG_BADBR:
  1.2706 +		case REG_EBRACE:
  1.2707 +			ERROR(45);
  1.2708 +			/*NOTREACHED*/
  1.2709 +		case REG_ERANGE:
  1.2710 +			ERROR(11);
  1.2711 +			/*NOTREACHED*/
  1.2712 +		case REG_ESPACE:
  1.2713 +			ERROR(50);
  1.2714 +			/*NOTREACHED*/
  1.2715 +		default:
  1.2716 +			ERROR(-1);
  1.2717 +		}
  1.2718 +		op[0] = 1;
  1.2719 +		circf = op[1] = genbuf[0] == '^';
  1.2720 +	} else if (op[0]) {
  1.2721 +		circf = op[1];
  1.2722 +	} else
  1.2723 +		ERROR(41);
  1.2724 +	return ep + sizeof (void *);
  1.2725 +}
  1.2726 +
  1.2727 +static int
  1.2728 +step(const char *lp, const char *ep)
  1.2729 +{
  1.2730 +	regex_t	*rp;
  1.2731 +	regmatch_t	bralist[NBRA+1];
  1.2732 +	int	eflag = 0;
  1.2733 +	int	res;
  1.2734 +	int	i;
  1.2735 +
  1.2736 +	rp = fetchptr(&ep[2]);
  1.2737 +	if (ep[0] == 0)
  1.2738 +		return 0;
  1.2739 +	if (locs)
  1.2740 +		eflag |= REG_NOTBOL;
  1.2741 +	if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 &&
  1.2742 +			needsub) {
  1.2743 +		loc1 = (char *)lp + bralist[0].rm_so;
  1.2744 +		loc2 = (char *)lp + bralist[0].rm_eo;
  1.2745 +		for (i = 1; i <= NBRA; i++) {
  1.2746 +			if (bralist[i].rm_so != -1) {
  1.2747 +				braslist[i-1] = (char *)lp + bralist[i].rm_so;
  1.2748 +				braelist[i-1] = (char *)lp + bralist[i].rm_eo;
  1.2749 +			} else
  1.2750 +				braslist[i-1] = braelist[i-1] = NULL;
  1.2751 +		}
  1.2752 +	}
  1.2753 +	return res == 0;
  1.2754 +}
  1.2755 +#endif	/* SUS || S42 || SU3 */
  1.2756 +
  1.2757 +static void
  1.2758 +help(void)
  1.2759 +{
  1.2760 +	const char	*desc[] = {
  1.2761 +		"(.)a            append up to .",
  1.2762 +		"(.)b[n]         browse n lines",
  1.2763 +		"(.,.)c          change up to .",
  1.2764 +		"(.,.)d          delete lines",
  1.2765 +		"e [file]        edit file",
  1.2766 +		"E [file]        force edit",
  1.2767 +		"f [file]        print or set file",
  1.2768 +		"(1,$)g/RE/cmd   global cmd",
  1.2769 +		"(1,$)G/RE/      interactive global",
  1.2770 +		"h               print last error",
  1.2771 +		"H               toggle error messages",
  1.2772 +		"help            print this screen",
  1.2773 +		"(.)i            insert up to .",
  1.2774 +		"(.,.+1)j        join lines",
  1.2775 +		"(.)kx           mark line with x",
  1.2776 +		"(.,.)l          list lines",
  1.2777 +		"(.,.)ma         move lines to a",
  1.2778 +		"(.,.)n          number lines",
  1.2779 +		"N               revert n and p",
  1.2780 +		"(.)o[n]         show n lines of context",
  1.2781 +		"(.,.)p          print lines",
  1.2782 +		"P               toggle prompt",
  1.2783 +		"q               quit",
  1.2784 +		"Q               force quit",
  1.2785 +		"($)r            read file",
  1.2786 +		"(.,.)s/RE/repl/ search and replace",
  1.2787 +		"(.,.)s/RE/rp/g  replace all occurrences",
  1.2788 +		"(.,.)s/RE/rp/n  replace n-th occurrence",
  1.2789 +		"(.,.)ta         transfer lines to a",
  1.2790 +		"u               undo last change",
  1.2791 +		"(1,$)v/RE/cmd   reverse global",
  1.2792 +		"(1,$)V/RE/      reverse i/a global",
  1.2793 +		"(1,$)w [file]   write file",
  1.2794 +		"(1,$)W [file]   append to file",
  1.2795 +		"z               write buffer and quit",
  1.2796 +		"($)=            print line number",
  1.2797 +		"!command        execute shell command",
  1.2798 +		"(.+1)<newline>  print one line",
  1.2799 +		"/RE             find RE forwards",
  1.2800 +		"?RE             find RE backwards",
  1.2801 +		"1               first line",
  1.2802 +		".               current line",
  1.2803 +		"$               last line",
  1.2804 +		",               1,$",
  1.2805 +		";               .,$",
  1.2806 +		NULL
  1.2807 +	};
  1.2808 +	char	line[100];
  1.2809 +	int	c, half, i, k;
  1.2810 +
  1.2811 +	half = (sizeof desc / sizeof *desc) / 2;
  1.2812 +	for (i = 0; i < half && desc[i]; i++) {
  1.2813 +		c = 0;
  1.2814 +		for (k = 0; desc[i][k]; k++)
  1.2815 +			line[c++] = desc[i][k];
  1.2816 +		if (desc[i+half]) {
  1.2817 +			while (c < 40)
  1.2818 +				line[c++] = ' ';
  1.2819 +			for (k = 0; desc[i+half][k]; k++)
  1.2820 +				line[c++] = desc[i+half][k];
  1.2821 +		}
  1.2822 +		line[c] = 0;
  1.2823 +		puts(line);
  1.2824 +	}
  1.2825 +}