|  | /* | 
|  | * Editor | 
|  | */ | 
|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include <regexp.h> | 
|  |  | 
|  | #undef EOF	/* stdio? */ | 
|  |  | 
|  | 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/sizeof(Rune)]; | 
|  | 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[] = "/var/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 = "/dev/stdout"; | 
|  | 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('\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('\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('\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('?'); | 
|  | 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('\n'); | 
|  | lastc = '\n'; | 
|  | error1(Q); | 
|  | notejmp(a, savej, 0); | 
|  | } | 
|  | if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){ | 
|  | if(rescuing) | 
|  | noted(NDFLT); | 
|  | rescue(); | 
|  | } | 
|  | if(strstr(s, "child")) | 
|  | noted(NCONT); | 
|  | 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); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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, d; | 
|  |  | 
|  | nline = 0; | 
|  | dot = a; | 
|  | while((*f)() == 0) { | 
|  | if((dol-zero) >= nlall) { | 
|  | nlall += 512; | 
|  | a1 = realloc(zero, (nlall+50)*sizeof(int*)); | 
|  | if(a1 == 0) { | 
|  | error("MEM?"); | 
|  | rescue(); | 
|  | } | 
|  | /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */ | 
|  | d = addr1 - zero; | 
|  | addr1 = a1 + d; | 
|  | d = addr2 - zero; | 
|  | addr2 = a1 + d; | 
|  | d = dol - zero; | 
|  | dol = a1 + d; | 
|  | d = dot - zero; | 
|  | dot = a1 + d; | 
|  | zero = a1; | 
|  | } | 
|  | d = putline(); | 
|  | nline++; | 
|  | a1 = ++dol; | 
|  | a2 = a1+1; | 
|  | rdot = ++dot; | 
|  | while(a1 > rdot) | 
|  | *--a2 = *--a1; | 
|  | *rdot = d; | 
|  | } | 
|  | 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) { | 
|  | execlp("rc", "rc", "-c", buf, (char*)0); | 
|  | sysfatal("exec failed: %r"); | 
|  | 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/sizeof(Rune)) - 1); | 
|  | while(*lp++ = *bp++) { | 
|  | nl -= sizeof(Rune); | 
|  | if(nl == 0) { | 
|  | bp = getblock(tl += BLKSIZE/sizeof(Rune), 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/sizeof(Rune))-1); | 
|  | while(*bp = *lp++) { | 
|  | if(*bp++ == '\n') { | 
|  | bp[-1] = 0; | 
|  | linebp = lp; | 
|  | break; | 
|  | } | 
|  | nl -= sizeof(Rune); | 
|  | if(nl == 0) { | 
|  | tl += BLKSIZE/sizeof(Rune); | 
|  | 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/sizeof(Rune)); | 
|  | off = (atl*sizeof(Rune)) & (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/sizeof(Rune)]) | 
|  | error(Q); | 
|  | } else | 
|  | if(c == '\n' && (!globp || !globp[0])) { | 
|  | peekc = c; | 
|  | pflag++; | 
|  | break; | 
|  | } else | 
|  | if(c == seof) | 
|  | break; | 
|  | *p++ = c; | 
|  | if(p >= &rhsbuf[LBSIZE/sizeof(Rune)]) | 
|  | 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 + '0'); | 
|  | } | 
|  |  | 
|  | void | 
|  | putst(char *sp) | 
|  | { | 
|  | Rune r; | 
|  |  | 
|  | col = 0; | 
|  | for(;;) { | 
|  | sp += chartorune(&r, sp); | 
|  | if(r == 0) | 
|  | break; | 
|  | putchr(r); | 
|  | } | 
|  | putchr('\n'); | 
|  | } | 
|  |  | 
|  | void | 
|  | putshst(Rune *sp) | 
|  | { | 
|  | col = 0; | 
|  | while(*sp) | 
|  | putchr(*sp++); | 
|  | putchr('\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); | 
|  | } |