new utilities.
the .C files compile but are renamed to avoid building automatically.
diff --git a/src/cmd/ed.c b/src/cmd/ed.c
new file mode 100644
index 0000000..42fa3e0
--- /dev/null
+++ b/src/cmd/ed.c
@@ -0,0 +1,1608 @@
+/*
+ * Editor
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <regexp.h>
+
+enum
+{
+	FNSIZE	= 128,		/* file name */
+	LBSIZE	= 4096,		/* max line size */
+	BLKSIZE	= 4096,		/* block size in temp file */
+	NBLK	= 8191,		/* max size of temp file */
+	ESIZE	= 256,		/* max size of reg exp */
+	GBSIZE	= 256,		/* max size of global command */
+	MAXSUB	= 9,		/* max number of sub reg exp */
+	ESCFLG	= 0xFFFF,	/* escape Rune - user defined code */
+	EOF	= -1,
+};
+
+void	(*oldhup)(int);
+void	(*oldquit)(int);
+int*	addr1;
+int*	addr2;
+int	anymarks;
+int	col;
+long	count;
+int*	dol;
+int*	dot;
+int	fchange;
+char	file[FNSIZE];
+Rune	genbuf[LBSIZE];
+int	given;
+Rune*	globp;
+int	iblock;
+int	ichanged;
+int	io;
+Biobuf	iobuf;
+int	lastc;
+char	line[70];
+Rune*	linebp;
+Rune	linebuf[LBSIZE];
+int	listf;
+int	listn;
+Rune*	loc1;
+Rune*	loc2;
+int	names[26];
+int	nleft;
+int	oblock;
+int	oflag;
+Reprog	*pattern;
+int	peekc;
+int	pflag;
+int	rescuing;
+Rune	rhsbuf[LBSIZE/2];
+char	savedfile[FNSIZE];
+jmp_buf	savej;
+int	subnewa;
+int	subolda;
+Resub	subexp[MAXSUB];
+char*	tfname;
+int	tline;
+int	waiting;
+int	wrapp;
+int*	zero;
+
+char	Q[]	= "";
+char	T[]	= "TMP";
+char	WRERR[]	= "WRITE ERROR";
+int	bpagesize = 20;
+char	hex[]	= "0123456789abcdef";
+char*	linp	= line;
+ulong	nlall = 128;
+int	tfile	= -1;
+int	vflag	= 1;
+
+void	add(int);
+int*	address(void);
+int	append(int(*)(void), int*);
+void	browse(void);
+void	callunix(void);
+void	commands(void);
+void	compile(int);
+int	compsub(void);
+void	dosub(void);
+void	error(char*);
+int	match(int*);
+void	exfile(int);
+void	filename(int);
+Rune*	getblock(int, int);
+int	getchr(void);
+int	getcopy(void);
+int	getfile(void);
+Rune*	getline(int);
+int	getnum(void);
+int	getsub(void);
+int	gettty(void);
+void	global(int);
+void	init(void);
+void	join(void);
+void	move(int);
+void	newline(void);
+void	nonzero(void);
+void	notifyf(void*, char*);
+Rune*	place(Rune*, Rune*, Rune*);
+void	printcom(void);
+void	putchr(int);
+void	putd(void);
+void	putfile(void);
+int	putline(void);
+void	putshst(Rune*);
+void	putst(char*);
+void	quit(void);
+void	rdelete(int*, int*);
+void	regerror(char *);
+void	reverse(int*, int*);
+void	setnoaddr(void);
+void	setwide(void);
+void	squeeze(int);
+void	substitute(int);
+
+Rune La[] = { 'a', 0 };
+Rune Lr[] = { 'r', 0 };
+
+char tmp[] = "/tmp/eXXXXX";
+
+void
+main(int argc, char *argv[])
+{
+	char *p1, *p2;
+
+	notify(notifyf);
+	ARGBEGIN {
+	case 'o':
+		oflag = 1;
+		vflag = 0;
+		break;
+	} ARGEND
+
+	USED(argc);
+	if(*argv && (strcmp(*argv, "-") == 0)) {
+		argv++;
+		vflag = 0;
+	}
+	if(oflag) {
+		p1 = "/fd/1";
+		p2 = savedfile;
+		while(*p2++ = *p1++)
+			;
+		globp = La;
+	} else
+	if(*argv) {
+		p1 = *argv;
+		p2 = savedfile;
+		while(*p2++ = *p1++)
+			if(p2 >= &savedfile[sizeof(savedfile)])
+				p2--;
+		globp = Lr;
+	}
+	zero = malloc((nlall+5)*sizeof(int*));
+	tfname = mktemp(tmp);
+	init();
+	setjmp(savej);
+	commands();
+	quit();
+}
+
+void
+commands(void)
+{
+	int *a1, c, temp;
+	char lastsep;
+	Dir *d;
+
+	for(;;) {
+		if(pflag) {
+			pflag = 0;
+			addr1 = addr2 = dot;
+			printcom();
+		}
+		c = '\n';
+		for(addr1 = 0;;) {
+			lastsep = c;
+			a1 = address();
+			c = getchr();
+			if(c != ',' && c != ';')
+				break;
+			if(lastsep == ',')
+				error(Q);
+			if(a1 == 0) {
+				a1 = zero+1;
+				if(a1 > dol)
+					a1--;
+			}
+			addr1 = a1;
+			if(c == ';')
+				dot = a1;
+		}
+		if(lastsep != '\n' && a1 == 0)
+			a1 = dol;
+		if((addr2=a1) == 0) {
+			given = 0;
+			addr2 = dot;	
+		} else
+			given = 1;
+		if(addr1 == 0)
+			addr1 = addr2;
+		switch(c) {
+
+		case 'a':
+			add(0);
+			continue;
+
+		case 'b':
+			nonzero();
+			browse();
+			continue;
+
+		case 'c':
+			nonzero();
+			newline();
+			rdelete(addr1, addr2);
+			append(gettty, addr1-1);
+			continue;
+
+		case 'd':
+			nonzero();
+			newline();
+			rdelete(addr1, addr2);
+			continue;
+
+		case 'E':
+			fchange = 0;
+			c = 'e';
+		case 'e':
+			setnoaddr();
+			if(vflag && fchange) {
+				fchange = 0;
+				error(Q);
+			}
+			filename(c);
+			init();
+			addr2 = zero;
+			goto caseread;
+
+		case 'f':
+			setnoaddr();
+			filename(c);
+			putst(savedfile);
+			continue;
+
+		case 'g':
+			global(1);
+			continue;
+
+		case 'i':
+			add(-1);
+			continue;
+
+
+		case 'j':
+			if(!given)
+				addr2++;
+			newline();
+			join();
+			continue;
+
+		case 'k':
+			nonzero();
+			c = getchr();
+			if(c < 'a' || c > 'z')
+				error(Q);
+			newline();
+			names[c-'a'] = *addr2 & ~01;
+			anymarks |= 01;
+			continue;
+
+		case 'm':
+			move(0);
+			continue;
+
+		case 'n':
+			listn++;
+			newline();
+			printcom();
+			continue;
+
+		case '\n':
+			if(a1==0) {
+				a1 = dot+1;
+				addr2 = a1;
+				addr1 = a1;
+			}
+			if(lastsep==';')
+				addr1 = a1;
+			printcom();
+			continue;
+
+		case 'l':
+			listf++;
+		case 'p':
+		case 'P':
+			newline();
+			printcom();
+			continue;
+
+		case 'Q':
+			fchange = 0;
+		case 'q':
+			setnoaddr();
+			newline();
+			quit();
+
+		case 'r':
+			filename(c);
+		caseread:
+			if((io=open(file, OREAD)) < 0) {
+				lastc = '\n';
+				error(file);
+			}
+			if((d = dirfstat(io)) != nil){
+				if(d->mode & DMAPPEND)
+					print("warning: %s is append only\n", file);
+				free(d);
+			}
+			Binit(&iobuf, io, OREAD);
+			setwide();
+			squeeze(0);
+			c = zero != dol;
+			append(getfile, addr2);
+			exfile(OREAD);
+
+			fchange = c;
+			continue;
+
+		case 's':
+			nonzero();
+			substitute(globp != 0);
+			continue;
+
+		case 't':
+			move(1);
+			continue;
+
+		case 'u':
+			nonzero();
+			newline();
+			if((*addr2&~01) != subnewa)
+				error(Q);
+			*addr2 = subolda;
+			dot = addr2;
+			continue;
+
+		case 'v':
+			global(0);
+			continue;
+
+		case 'W':
+			wrapp++;
+		case 'w':
+			setwide();
+			squeeze(dol>zero);
+			temp = getchr();
+			if(temp != 'q' && temp != 'Q') {
+				peekc = temp;
+				temp = 0;
+			}
+			filename(c);
+			if(!wrapp ||
+			  ((io = open(file, OWRITE)) == -1) ||
+			  ((seek(io, 0L, 2)) == -1))
+				if((io = create(file, OWRITE, 0666)) < 0)
+					error(file);
+			Binit(&iobuf, io, OWRITE);
+			wrapp = 0;
+			if(dol > zero)
+				putfile();
+			exfile(OWRITE);
+			if(addr1<=zero+1 && addr2==dol)
+				fchange = 0;
+			if(temp == 'Q')
+				fchange = 0;
+			if(temp)
+				quit();
+			continue;
+
+		case '=':
+			setwide();
+			squeeze(0);
+			newline();
+			count = addr2 - zero;
+			putd();
+			putchr(L'\n');
+			continue;
+
+		case '!':
+			callunix();
+			continue;
+
+		case EOF:
+			return;
+
+		}
+		error(Q);
+	}
+}
+
+void
+printcom(void)
+{
+	int *a1;
+
+	nonzero();
+	a1 = addr1;
+	do {
+		if(listn) {
+			count = a1-zero;
+			putd();
+			putchr(L'\t');
+		}
+		putshst(getline(*a1++));
+	} while(a1 <= addr2);
+	dot = addr2;
+	listf = 0;
+	listn = 0;
+	pflag = 0;
+}
+
+int*
+address(void)
+{
+	int sign, *a, opcnt, nextopand, *b, c;
+
+	nextopand = -1;
+	sign = 1;
+	opcnt = 0;
+	a = dot;
+	do {
+		do {
+			c = getchr();
+		} while(c == ' ' || c == '\t');
+		if(c >= '0' && c <= '9') {
+			peekc = c;
+			if(!opcnt)
+				a = zero;
+			a += sign*getnum();
+		} else
+		switch(c) {
+		case '$':
+			a = dol;
+		case '.':
+			if(opcnt)
+				error(Q);
+			break;
+		case '\'':
+			c = getchr();
+			if(opcnt || c < 'a' || c > 'z')
+				error(Q);
+			a = zero;
+			do {
+				a++;
+			} while(a <= dol && names[c-'a'] != (*a & ~01));
+			break;
+		case '?':
+			sign = -sign;
+		case '/':
+			compile(c);
+			b = a;
+			for(;;) {
+				a += sign;
+				if(a <= zero)
+					a = dol;
+				if(a > dol)
+					a = zero;
+				if(match(a))
+					break;
+				if(a == b)
+					error(Q);
+			}
+			break;
+		default:
+			if(nextopand == opcnt) {
+				a += sign;
+				if(a < zero || dol < a)
+					continue;       /* error(Q); */
+			}
+			if(c != '+' && c != '-' && c != '^') {
+				peekc = c;
+				if(opcnt == 0)
+					a = 0;
+				return a;
+			}
+			sign = 1;
+			if(c != '+')
+				sign = -sign;
+			nextopand = ++opcnt;
+			continue;
+		}
+		sign = 1;
+		opcnt++;
+	} while(zero <= a && a <= dol);
+	error(Q);
+	return 0;
+}
+
+int
+getnum(void)
+{
+	int r, c;
+
+	r = 0;
+	for(;;) {
+		c = getchr();
+		if(c < '0' || c > '9')
+			break;
+		r = r*10 + (c-'0');
+	}
+	peekc = c;
+	return r;
+}
+
+void
+setwide(void)
+{
+	if(!given) {
+		addr1 = zero + (dol>zero);
+		addr2 = dol;
+	}
+}
+
+void
+setnoaddr(void)
+{
+	if(given)
+		error(Q);
+}
+
+void
+nonzero(void)
+{
+	squeeze(1);
+}
+
+void
+squeeze(int i)
+{
+	if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
+		error(Q);
+}
+
+void
+newline(void)
+{
+	int c;
+
+	c = getchr();
+	if(c == '\n' || c == EOF)
+		return;
+	if(c == 'p' || c == 'l' || c == 'n') {
+		pflag++;
+		if(c == 'l')
+			listf++;
+		else
+		if(c == 'n')
+			listn++;
+		c = getchr();
+		if(c == '\n')
+			return;
+	}
+	error(Q);
+}
+
+void
+filename(int comm)
+{
+	char *p1, *p2;
+	Rune rune;
+	int c;
+
+	count = 0;
+	c = getchr();
+	if(c == '\n' || c == EOF) {
+		p1 = savedfile;
+		if(*p1 == 0 && comm != 'f')
+			error(Q);
+		p2 = file;
+		while(*p2++ = *p1++)
+			;
+		return;
+	}
+	if(c != ' ')
+		error(Q);
+	while((c=getchr()) == ' ')
+		;
+	if(c == '\n')
+		error(Q);
+	p1 = file;
+	do {
+		if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
+			error(Q);
+		rune = c;
+		p1 += runetochar(p1, &rune);
+	} while((c=getchr()) != '\n');
+	*p1 = 0;
+	if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
+		p1 = savedfile;
+		p2 = file;
+		while(*p1++ = *p2++)
+			;
+	}
+}
+
+void
+exfile(int om)
+{
+
+	if(om == OWRITE)
+		if(Bflush(&iobuf) < 0)
+			error(Q);
+	close(io);
+	io = -1;
+	if(vflag) {
+		putd();
+		putchr(L'\n');
+	}
+}
+
+void
+error1(char *s)
+{
+	int c;
+
+	wrapp = 0;
+	listf = 0;
+	listn = 0;
+	count = 0;
+	seek(0, 0, 2);
+	pflag = 0;
+	if(globp)
+		lastc = '\n';
+	globp = 0;
+	peekc = lastc;
+	if(lastc)
+		for(;;) {
+			c = getchr();
+			if(c == '\n' || c == EOF)
+				break;
+		}
+	if(io > 0) {
+		close(io);
+		io = -1;
+	}
+	putchr(L'?');
+	putst(s);
+}
+
+void
+error(char *s)
+{
+	error1(s);
+	longjmp(savej, 1);
+}
+
+void
+rescue(void)
+{
+	rescuing = 1;
+	if(dol > zero) {
+		addr1 = zero+1;
+		addr2 = dol;
+		io = create("ed.hup", OWRITE, 0666);
+		if(io > 0){
+			Binit(&iobuf, io, OWRITE);
+			putfile();
+		}
+	}
+	fchange = 0;
+	quit();
+}
+
+void
+notifyf(void *a, char *s)
+{
+	if(strcmp(s, "interrupt") == 0){
+		if(rescuing || waiting)
+			noted(NCONT);
+		putchr(L'\n');
+		lastc = '\n';
+		error1(Q);
+		notejmp(a, savej, 0);
+	}
+	if(strcmp(s, "hangup") == 0){
+		if(rescuing)
+			noted(NDFLT);
+		rescue();
+	}
+	fprint(2, "ed: note: %s\n", s);
+	abort();
+}
+
+int
+getchr(void)
+{
+	char s[UTFmax];
+	int i;
+	Rune r;
+
+	if(lastc = peekc) {
+		peekc = 0;
+		return lastc;
+	}
+	if(globp) {
+		if((lastc=*globp++) != 0)
+			return lastc;
+		globp = 0;
+		return EOF;
+	}
+	for(i=0;;) {
+		if(read(0, s+i, 1) <= 0)
+			return lastc = EOF;
+		i++;
+		if(fullrune(s, i))
+			break;
+		
+	}
+	chartorune(&r, s);
+	lastc = r;
+	return lastc;
+}
+
+int
+gety(void)
+{
+	int c;
+	Rune *gf, *p;
+
+	p = linebuf;
+	gf = globp;
+	for(;;) {
+		c = getchr();
+		if(c == '\n') {
+			*p = 0;
+			return 0;
+		}
+		if(c == EOF) {
+			if(gf)
+				peekc = c;
+			return c;
+		}
+		if(c == 0)
+			continue;
+		*p++ = c;
+		if(p >= &linebuf[LBSIZE-2])
+			error(Q);
+	}
+	return 0;
+}
+
+int
+gettty(void)
+{
+	int rc;
+
+	rc = gety();
+	if(rc)
+		return rc;
+	if(linebuf[0] == '.' && linebuf[1] == 0)
+		return EOF;
+	return 0;
+}
+
+int
+getfile(void)
+{
+	int c;
+	Rune *lp;
+
+	lp = linebuf;
+	do {
+		c = Bgetrune(&iobuf);
+		if(c < 0) {
+			if(lp > linebuf) {
+				putst("'\\n' appended");
+				c = '\n';
+			} else
+				return EOF;
+		}
+		if(lp >= &linebuf[LBSIZE]) {
+			lastc = '\n';
+			error(Q);
+		}
+		*lp++ = c;
+		count++;
+	} while(c != '\n');
+	lp[-1] = 0;
+	return 0;
+}
+
+void
+putfile(void)
+{
+	int *a1;
+	Rune *lp;
+	long c;
+
+	a1 = addr1;
+	do {
+		lp = getline(*a1++);
+		for(;;) {
+			count++;
+			c = *lp++;
+			if(c == 0) {
+				if(Bputrune(&iobuf, '\n') < 0)
+					error(Q);
+				break;
+			}
+			if(Bputrune(&iobuf, c) < 0)
+				error(Q);
+		}
+	} while(a1 <= addr2);
+	if(Bflush(&iobuf) < 0)
+		error(Q);
+}
+
+int
+append(int (*f)(void), int *a)
+{
+	int *a1, *a2, *rdot, nline, tl;
+
+	nline = 0;
+	dot = a;
+	while((*f)() == 0) {
+		if((dol-zero) >= nlall) {
+			nlall += 512;
+			a1 = realloc(zero, (nlall+5)*sizeof(int*));
+			if(a1 == 0) {
+				error("MEM?");
+				rescue();
+			}
+			tl = a1 - zero;	/* relocate pointers */
+			zero += tl;
+			addr1 += tl;
+			addr2 += tl;
+			dol += tl;
+			dot += tl;
+		}
+		tl = putline();
+		nline++;
+		a1 = ++dol;
+		a2 = a1+1;
+		rdot = ++dot;
+		while(a1 > rdot)
+			*--a2 = *--a1;
+		*rdot = tl;
+	}
+	return nline;
+}
+
+void
+add(int i)
+{
+	if(i && (given || dol > zero)) {
+		addr1--;
+		addr2--;
+	}
+	squeeze(0);
+	newline();
+	append(gettty, addr2);
+}
+
+void
+browse(void)
+{
+	int forward, n;
+	static int bformat, bnum; /* 0 */
+
+	forward = 1;
+	peekc = getchr();
+	if(peekc != '\n'){
+		if(peekc == '-' || peekc == '+') {
+			if(peekc == '-')
+				forward = 0;
+			getchr();
+		}
+		n = getnum();
+		if(n > 0)
+			bpagesize = n;
+	}
+	newline();
+	if(pflag) {
+		bformat = listf;
+		bnum = listn;
+	} else {
+		listf = bformat;
+		listn = bnum;
+	}
+	if(forward) {
+		addr1 = addr2;
+		addr2 += bpagesize;
+		if(addr2 > dol)
+			addr2 = dol;
+	} else {
+		addr1 = addr2-bpagesize;
+		if(addr1 <= zero)
+			addr1 = zero+1;
+	}
+	printcom();
+}
+
+void
+callunix(void)
+{
+	int c, pid;
+	Rune rune;
+	char buf[512];
+	char *p;
+
+	setnoaddr();
+	p = buf;
+	while((c=getchr()) != EOF && c != '\n')
+		if(p < &buf[sizeof(buf) - 6]) {
+			rune = c;
+			p += runetochar(p, &rune);
+		}
+	*p = 0;
+	pid = fork();
+	if(pid == 0) {
+		execl("/bin/rc", "rc", "-c", buf, 0);
+		exits("execl failed");
+	}
+	waiting = 1;
+	while(waitpid() != pid)
+		;
+	waiting = 0;
+	if(vflag)
+		putst("!");
+}
+
+void
+quit(void)
+{
+	if(vflag && fchange && dol!=zero) {
+		fchange = 0;
+		error(Q);
+	}
+	remove(tfname);
+	exits(0);
+}
+
+void
+onquit(int sig)
+{
+	USED(sig);
+	quit();
+}
+
+void
+rdelete(int *ad1, int *ad2)
+{
+	int *a1, *a2, *a3;
+
+	a1 = ad1;
+	a2 = ad2+1;
+	a3 = dol;
+	dol -= a2 - a1;
+	do {
+		*a1++ = *a2++;
+	} while(a2 <= a3);
+	a1 = ad1;
+	if(a1 > dol)
+		a1 = dol;
+	dot = a1;
+	fchange = 1;
+}
+
+void
+gdelete(void)
+{
+	int *a1, *a2, *a3;
+
+	a3 = dol;
+	for(a1=zero; (*a1&01)==0; a1++)
+		if(a1>=a3)
+			return;
+	for(a2=a1+1; a2<=a3;) {
+		if(*a2 & 01) {
+			a2++;
+			dot = a1;
+		} else
+			*a1++ = *a2++;
+	}
+	dol = a1-1;
+	if(dot > dol)
+		dot = dol;
+	fchange = 1;
+}
+
+Rune*
+getline(int tl)
+{
+	Rune *lp, *bp;
+	int nl;
+
+	lp = linebuf;
+	bp = getblock(tl, OREAD);
+	nl = nleft;
+	tl &= ~((BLKSIZE/2) - 1);
+	while(*lp++ = *bp++) {
+		nl -= sizeof(Rune);
+		if(nl == 0) {
+			bp = getblock(tl += BLKSIZE/2, OREAD);
+			nl = nleft;
+		}
+	}
+	return linebuf;
+}
+
+int
+putline(void)
+{
+	Rune *lp, *bp;
+	int nl, tl;
+
+	fchange = 1;
+	lp = linebuf;
+	tl = tline;
+	bp = getblock(tl, OWRITE);
+	nl = nleft;
+	tl &= ~((BLKSIZE/2)-1);
+	while(*bp = *lp++) {
+		if(*bp++ == '\n') {
+			bp[-1] = 0;
+			linebp = lp;
+			break;
+		}
+		nl -= sizeof(Rune);
+		if(nl == 0) {
+			tl += BLKSIZE/2;
+			bp = getblock(tl, OWRITE);
+			nl = nleft;
+		}
+	}
+	nl = tline;
+	tline += ((lp-linebuf) + 03) & 077776;
+	return nl;
+}
+
+void
+blkio(int b, uchar *buf, int isread)
+{
+	int n;
+
+	seek(tfile, b*BLKSIZE, 0);
+	if(isread)
+		n = read(tfile, buf, BLKSIZE);
+	else
+		n = write(tfile, buf, BLKSIZE);
+	if(n != BLKSIZE)
+		error(T);
+}
+
+Rune*
+getblock(int atl, int iof)
+{
+	int bno, off;
+	
+	static uchar ibuff[BLKSIZE];
+	static uchar obuff[BLKSIZE];
+
+	bno = atl / (BLKSIZE/2);
+	off = (atl<<1) & (BLKSIZE-1) & ~03;
+	if(bno >= NBLK) {
+		lastc = '\n';
+		error(T);
+	}
+	nleft = BLKSIZE - off;
+	if(bno == iblock) {
+		ichanged |= iof;
+		return (Rune*)(ibuff+off);
+	}
+	if(bno == oblock)
+		return (Rune*)(obuff+off);
+	if(iof == OREAD) {
+		if(ichanged)
+			blkio(iblock, ibuff, 0);
+		ichanged = 0;
+		iblock = bno;
+		blkio(bno, ibuff, 1);
+		return (Rune*)(ibuff+off);
+	}
+	if(oblock >= 0)
+		blkio(oblock, obuff, 0);
+	oblock = bno;
+	return (Rune*)(obuff+off);
+}
+
+void
+init(void)
+{
+	int *markp;
+
+	close(tfile);
+	tline = 2;
+	for(markp = names; markp < &names[26]; )
+		*markp++ = 0;
+	subnewa = 0;
+	anymarks = 0;
+	iblock = -1;
+	oblock = -1;
+	ichanged = 0;
+	if((tfile = create(tfname, ORDWR, 0600)) < 0){
+		error1(T);
+		exits(0);
+	}
+	dot = dol = zero;
+}
+
+void
+global(int k)
+{
+	Rune *gp, globuf[GBSIZE];
+	int c, *a1;
+
+	if(globp)
+		error(Q);
+	setwide();
+	squeeze(dol > zero);
+	c = getchr();
+	if(c == '\n')
+		error(Q);
+	compile(c);
+	gp = globuf;
+	while((c=getchr()) != '\n') {
+		if(c == EOF)
+			error(Q);
+		if(c == '\\') {
+			c = getchr();
+			if(c != '\n')
+				*gp++ = '\\';
+		}
+		*gp++ = c;
+		if(gp >= &globuf[GBSIZE-2])
+			error(Q);
+	}
+	if(gp == globuf)
+		*gp++ = 'p';
+	*gp++ = '\n';
+	*gp = 0;
+	for(a1=zero; a1<=dol; a1++) {
+		*a1 &= ~01;
+		if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
+			*a1 |= 01;
+	}
+
+	/*
+	 * Special case: g/.../d (avoid n^2 algorithm)
+	 */
+	if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
+		gdelete();
+		return;
+	}
+	for(a1=zero; a1<=dol; a1++) {
+		if(*a1 & 01) {
+			*a1 &= ~01;
+			dot = a1;
+			globp = globuf;
+			commands();
+			a1 = zero;
+		}
+	}
+}
+
+void
+join(void)
+{
+	Rune *gp, *lp;
+	int *a1;
+
+	nonzero();
+	gp = genbuf;
+	for(a1=addr1; a1<=addr2; a1++) {
+		lp = getline(*a1);
+		while(*gp = *lp++)
+			if(gp++ >= &genbuf[LBSIZE-2])
+				error(Q);
+	}
+	lp = linebuf;
+	gp = genbuf;
+	while(*lp++ = *gp++)
+		;
+	*addr1 = putline();
+	if(addr1 < addr2)
+		rdelete(addr1+1, addr2);
+	dot = addr1;
+}
+
+void
+substitute(int inglob)
+{
+	int *mp, *a1, nl, gsubf, n;
+
+	n = getnum();	/* OK even if n==0 */
+	gsubf = compsub();
+	for(a1 = addr1; a1 <= addr2; a1++) {
+		if(match(a1)){
+			int *ozero;
+			int m = n;
+
+			do {
+				int span = loc2-loc1;
+
+				if(--m <= 0) {
+					dosub();
+					if(!gsubf)
+						break;
+					if(span == 0) {	/* null RE match */
+						if(*loc2 == 0)
+							break;
+						loc2++;
+					}
+				}
+			} while(match(0));
+			if(m <= 0) {
+				inglob |= 01;
+				subnewa = putline();
+				*a1 &= ~01;
+				if(anymarks) {
+					for(mp=names; mp<&names[26]; mp++)
+						if(*mp == *a1)
+							*mp = subnewa;
+				}
+				subolda = *a1;
+				*a1 = subnewa;
+				ozero = zero;
+				nl = append(getsub, a1);
+				addr2 += nl;
+				nl += zero-ozero;
+				a1 += nl;
+			}
+		}
+	}
+	if(inglob == 0)
+		error(Q);
+}
+
+int
+compsub(void)
+{
+	int seof, c;
+	Rune *p;
+
+	seof = getchr();
+	if(seof == '\n' || seof == ' ')
+		error(Q);
+	compile(seof);
+	p = rhsbuf;
+	for(;;) {
+		c = getchr();
+		if(c == '\\') {
+			c = getchr();
+			*p++ = ESCFLG;
+			if(p >= &rhsbuf[LBSIZE/2])
+				error(Q);
+		} else
+		if(c == '\n' && (!globp || !globp[0])) {
+			peekc = c;
+			pflag++;
+			break;
+		} else
+		if(c == seof)
+			break;
+		*p++ = c;
+		if(p >= &rhsbuf[LBSIZE/2])
+			error(Q);
+	}
+	*p = 0;
+	peekc = getchr();
+	if(peekc == 'g') {
+		peekc = 0;
+		newline();
+		return 1;
+	}
+	newline();
+	return 0;
+}
+
+int
+getsub(void)
+{
+	Rune *p1, *p2;
+
+	p1 = linebuf;
+	if((p2 = linebp) == 0)
+		return EOF;
+	while(*p1++ = *p2++)
+		;
+	linebp = 0;
+	return 0;
+}
+
+void
+dosub(void)
+{
+	Rune *lp, *sp, *rp;
+	int c, n;
+
+	lp = linebuf;
+	sp = genbuf;
+	rp = rhsbuf;
+	while(lp < loc1)
+		*sp++ = *lp++;
+	while(c = *rp++) {
+		if(c == '&'){
+			sp = place(sp, loc1, loc2);
+			continue;
+		}
+		if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
+			n = c-'0';
+			if(subexp[n].s.rsp && subexp[n].e.rep) {
+				sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
+				continue;
+			}
+			error(Q);
+		}
+		*sp++ = c;
+		if(sp >= &genbuf[LBSIZE])
+			error(Q);
+	}
+	lp = loc2;
+	loc2 = sp - genbuf + linebuf;
+	while(*sp++ = *lp++)
+		if(sp >= &genbuf[LBSIZE])
+			error(Q);
+	lp = linebuf;
+	sp = genbuf;
+	while(*lp++ = *sp++)
+		;
+}
+
+Rune*
+place(Rune *sp, Rune *l1, Rune *l2)
+{
+
+	while(l1 < l2) {
+		*sp++ = *l1++;
+		if(sp >= &genbuf[LBSIZE])
+			error(Q);
+	}
+	return sp;
+}
+
+void
+move(int cflag)
+{
+	int *adt, *ad1, *ad2;
+
+	nonzero();
+	if((adt = address())==0)	/* address() guarantees addr is in range */
+		error(Q);
+	newline();
+	if(cflag) {
+		int *ozero, delta;
+		ad1 = dol;
+		ozero = zero;
+		append(getcopy, ad1++);
+		ad2 = dol;
+		delta = zero - ozero;
+		ad1 += delta;
+		adt += delta;
+	} else {
+		ad2 = addr2;
+		for(ad1 = addr1; ad1 <= ad2;)
+			*ad1++ &= ~01;
+		ad1 = addr1;
+	}
+	ad2++;
+	if(adt<ad1) {
+		dot = adt + (ad2-ad1);
+		if((++adt)==ad1)
+			return;
+		reverse(adt, ad1);
+		reverse(ad1, ad2);
+		reverse(adt, ad2);
+	} else
+	if(adt >= ad2) {
+		dot = adt++;
+		reverse(ad1, ad2);
+		reverse(ad2, adt);
+		reverse(ad1, adt);
+	} else
+		error(Q);
+	fchange = 1;
+}
+
+void
+reverse(int *a1, int *a2)
+{
+	int t;
+
+	for(;;) {
+		t = *--a2;
+		if(a2 <= a1)
+			return;
+		*a2 = *a1;
+		*a1++ = t;
+	}
+}
+
+int
+getcopy(void)
+{
+	if(addr1 > addr2)
+		return EOF;
+	getline(*addr1++);
+	return 0;
+}
+
+void
+compile(int eof)
+{
+	Rune c;
+	char *ep;
+	char expbuf[ESIZE];
+
+	if((c = getchr()) == '\n') {
+		peekc = c;
+		c = eof;
+	}
+	if(c == eof) {
+		if(!pattern)
+			error(Q);
+		return;
+	}
+	if(pattern) {
+		free(pattern);
+		pattern = 0;
+	}
+	ep = expbuf;
+	do {
+		if(c == '\\') {
+			if(ep >= expbuf+sizeof(expbuf)) {
+				error(Q);
+				return;
+			}
+			ep += runetochar(ep, &c);
+			if((c = getchr()) == '\n') {
+				error(Q);
+				return;
+			}
+		}
+		if(ep >= expbuf+sizeof(expbuf)) {
+			error(Q);
+			return;
+		}
+		ep += runetochar(ep, &c);
+	} while((c = getchr()) != eof && c != '\n');
+	if(c == '\n')
+		peekc = c;
+	*ep = 0;
+	pattern = regcomp(expbuf);
+}
+
+int
+match(int *addr)
+{
+	if(!pattern)
+		return 0;
+	if(addr){
+		if(addr == zero)
+			return 0;
+		subexp[0].s.rsp = getline(*addr);
+	} else
+		subexp[0].s.rsp = loc2;
+	subexp[0].e.rep = 0;
+	if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
+		loc1 = subexp[0].s.rsp;
+		loc2 = subexp[0].e.rep;
+		return 1;
+	}
+	loc1 = loc2 = 0;
+	return 0;
+	
+}
+
+void
+putd(void)
+{
+	int r;
+
+	r = count%10;
+	count /= 10;
+	if(count)
+		putd();
+	putchr(r + L'0');
+}
+
+void
+putst(char *sp)
+{
+	Rune r;
+
+	col = 0;
+	for(;;) {
+		sp += chartorune(&r, sp);
+		if(r == 0)
+			break;
+		putchr(r);
+	}
+	putchr(L'\n');
+}
+
+void
+putshst(Rune *sp)
+{
+	col = 0;
+	while(*sp)
+		putchr(*sp++);
+	putchr(L'\n');
+}
+
+void
+putchr(int ac)
+{
+	char *lp;
+	int c;
+	Rune rune;
+
+	lp = linp;
+	c = ac;
+	if(listf) {
+		if(c == '\n') {
+			if(linp != line && linp[-1] == ' ') {
+				*lp++ = '\\';
+				*lp++ = 'n';
+			}
+		} else {
+			if(col > (72-6-2)) {
+				col = 8;
+				*lp++ = '\\';
+				*lp++ = '\n';
+				*lp++ = '\t';
+			}
+			col++;
+			if(c=='\b' || c=='\t' || c=='\\') {
+				*lp++ = '\\';
+				if(c == '\b')
+					c = 'b';
+				else
+				if(c == '\t')
+					c = 't';
+				col++;
+			} else
+			if(c<' ' || c>='\177') {
+				*lp++ = '\\';
+				*lp++ = 'x';
+				*lp++ =  hex[c>>12];
+				*lp++ =  hex[c>>8&0xF];
+				*lp++ =  hex[c>>4&0xF];
+				c     =  hex[c&0xF];
+				col += 5;
+			}
+		}
+	}
+
+	rune = c;
+	lp += runetochar(lp, &rune);
+
+	if(c == '\n' || lp >= &line[sizeof(line)-5]) {
+		linp = line;
+		write(oflag? 2: 1, line, lp-line);
+		return;
+	}
+	linp = lp;
+}
+
+char*
+mktemp(char *as)
+{
+	char *s;
+	unsigned pid;
+	int i;
+
+	pid = getpid();
+	s = as;
+	while(*s++)
+		;
+	s--;
+	while(*--s == 'X') {
+		*s = pid % 10 + '0';
+		pid /= 10;
+	}
+	s++;
+	i = 'a';
+	while(access(as, 0) != -1) {
+		if(i == 'z')
+			return "/";
+		*s = i++;
+	}
+	return as;
+}
+
+void
+regerror(char *s)
+{
+	USED(s);
+	error(Q);
+}