/* * Editor */ #include #include #include #include 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; Biobuf bcons; 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); void main(int argc, char *argv[]) { char *p1, *p2; Binit(&bcons, 0, OREAD); 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 = L"a"; } else if(*argv) { p1 = *argv; p2 = savedfile; while(*p2++ = *p1++) if(p2 >= &savedfile[sizeof(savedfile)]) p2--; globp = L"r"; } zero = malloc((nlall+5)*sizeof(int*)); tfname = mktemp("/tmp/eXXXXX"); 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) { if(lastc = peekc) { peekc = 0; return lastc; } if(globp) { if((lastc=*globp++) != 0) return lastc; globp = 0; return EOF; } lastc = Bgetrune(&bcons); 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, 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, nil); 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, long (*iofcn)(int, void *, long)) { seek(tfile, b*BLKSIZE, 0); if((*iofcn)(tfile, buf, BLKSIZE) != 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, write); ichanged = 0; iblock = bno; blkio(bno, ibuff, read); return (Rune*)(ibuff+off); } if(oblock >= 0) blkio(oblock, obuff, write); 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].rsp && subexp[n].rep) { sp = place(sp, subexp[n].rsp, subexp[n].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= 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].rsp = getline(*addr); } else subexp[0].rsp = loc2; subexp[0].rep = 0; if(rregexec(pattern, linebuf, subexp, MAXSUB)) { loc1 = subexp[0].rsp; loc2 = subexp[0].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); }