#/* Module Name: xed.c -- Editor Copyright 1974, Bell Telephone Laboratories, Incorporated Modifications by UCB (the o command) Modifications by UCLA (the b,j, & z commands; misc improvements) Modifications by U of Illinois misc improvements Installation: if $1x = finalx goto final cc xed.c mv a.out ../xed exit : final cc -O -s -n xed.c su cp a.out /usr/bin/xed rm a.out ../xed Synopsis: xed [ - ] [ filename ] */ #define SIGHUP 1 #define SIGINTR 2 #define SIGQUIT 3 #define FNSIZE 64 #define LBSIZE 512 #define ESIZE 128 #define GBSIZE 256 #define NBRA 5 #define EOF (-1) #define CTLA 001 #define NP 014 #define snap(a) printf("a is %o\n",a); #define CBRA 1 #define CCHR 2 #define CDOT 4 #define CCL 6 #define NCCL 8 #define CDOL 10 #define CEOF 11 #define CKET 12 #define STAR 01 #define error errr() #define READ 0 #define WRITE 1 #define BOOL char #define FID int #define UNSIGNED char * UNSIGNED flushlim 15; /* number of changed lines before temp updated */ UNSIGNED saveit 15; /* a very short stack of flushlim values */ UNSIGNED fchanged; /* fchanged=0 means internal file = external file */ /* fchanged=1 means internal file = temp files */ /* fchanged>1 means internal file differs from temp files by less than fchanged lines */ #define BIGLIM 0177777 /* a very big limit on number of changed lines */ int peekc; char savedfile[FNSIZE]; char file[FNSIZE]; char linebuf[LBSIZE]; char rhsbuf[LBSIZE/2]; char expbuf[ESIZE+4]; char genbuf[LBSIZE]; int *zero; int *dot; int *dol; int *endcore; int *fendcore; int *addr1; int *addr2; #ifdef LCOUNT long lcount; #endif #ifndef LCOUNT int count[2]; #endif char *nextip; char *linebp; int ninbuf; FID io; struct { BOOL circfl; /* circumflex flag--circumflex in search string */ BOOL pflag; BOOL vflag; BOOL zflag; BOOL hiding; char listf; } flags; struct { int integer[2]; }; FID tfile -1; FID tlpfile; int onhup(); /*int onquit;*/ int col; char *globp; int tline; char *tfname; /* tfname = "etmp.Exxxxx" where xxxxx is process id in decimal, and E is either 'e' for text temporary (maintained by append and delete routines) or 'E' for line index temporary (maintained by flushtmp routine) if for some reason etmp.Exxxxx can't be created on entry, /tmp/Exxxxx is tried. */ char *loc1; char *loc2; char *locs; char ibuff[512]; int iblock -1; char obuff[512]; int oblock -1; int ichanged; int nleft; int errfunc(); int names[26]; char *braslist[NBRA]; char *braelist[NBRA]; #define RIGHT 1 #define LEFT 0 #define COPY 1 #define NOCOPY 0 #define EOT 004 char *to, *fr; /*int istty 0;*/ int ttmode[3]; int ttnorm; /* saves ttmode[2] during 'o' commands */ int zlength 23; main(argc, argv) char **argv; { register char *p1, *p2; register pid; extern int onintr(); /* onquit = signal(SIGQUIT, 1); */ signal(SIGQUIT, 1); signal(SIGHUP,onhup); if(gtty(0,ttmode) != -1) { /* istty++;*/ ttnorm = ttmode[2]; } argv++; flags.vflag++; /* default is verbose mode */ if (argc > 1 && **argv=='-') { /* allow debugging quits? */ switch ((*argv)[1]) { case 'q': signal(SIGQUIT, 0); break; case 0: flags.vflag=0; break; } argv++; argc--; } tfname = "etmp.exxxxx"; pid = getpid(); for (p1 = &tfname[11]; p1 > &tfname[6];) { *--p1 = (pid%10) + '0'; pid =/ 10; } if ((signal(SIGINTR, 1) & 01) == 0) signal(SIGINTR, onintr); fendcore = sbrk(2) + 2; /* *(dol+1) = -1 */ /* see init() */ init(); setexit(); /* All Errors return to this point via reset() */ if (argc>1) { /* read in input; has to be after setexit() */ argc = 0; p1 = *argv; p2 = savedfile; while(*p2++ = *p1++); p1 = *argv; p2 = file; while (*p2++ = *p1++); readfile(zero); fchanged = 0; } commands(0); rmfiles(); } commands(depth) { int getfile(), gettty(); register *a1, c; register char *p; int r; extern char CRERR[]; extern char BELL[]; extern char PROMPT[]; for (;;) { if (flags.pflag) { flags.pflag = 0; addr1 = addr2 = dot; printlines(); } if(flags.vflag && !globp) writef1(PROMPT); /* brute farce */ addr1 = addr2 = address(); c = getchar(); if (addr1) { if (c==';') { dot = addr1; addr2 = address(); c = getchar(); } else if (c==',') { addr2 = address(); c = getchar(); } } switch(c) { case 'a': setdot(); newline(); append(gettty, addr2); continue; case 'B': numout(flushlim); saveit = flushlim = addr2-zero; case 'b': /* update temp */ numout(flushlim); numout(fchanged); newline(); flushtmp(); continue; case 'c': setdot(); newline(); nonzero(); delete(); append(gettty, addr1-1); continue; case 'd': setdot(); newline(); nonzero(); delete(); continue; case 'E': fchanged = 0; case 'e': setnoaddr(); if ((peekc = getchar()) != ' ') error; dontgo(); savedfile[0] = 0; filename(); init(); readfile(zero); fchanged = 0; continue; case 'f': setnoaddr(); if ((c = getchar()) != '\n') { peekc = c; savedfile[0] = 0; filename(); } puts(savedfile); continue; case 'G': global(2); continue; case 'g': global(1); continue; case 'i': setdot(); nonzero(); newline(); append(gettty, addr2-1); continue; case 'j': setdot(); nonzero(); newline(); join(); continue; case 'k': if ((c = getchar()) < 'a' || c > 'z') error; setdot(); nonzero(); newline(); names[c-'a'] = *addr2 | 01; continue; case 'm': move(0); continue; case 'n': flags.listf = 2; goto print; case '\n': if (addr2==0) addr2 = dot+1; addr1 = addr2; printlines(); continue; case 'l': flags.listf = 1; print: case 'p': newline(); setdot(); printlines(); continue; case 'o': setdot(); nonzero(); if ((c=getchar()) != '\n') { peekc = c; ilsubst(); } else { ttmode[2] =| 040; ttmode[2] =& ~010; stty(0,ttmode); writef1(BELL); /* put out a bell */ ilsubst(); ttmode[2] = ttnorm; stty(0,ttmode); } continue; case 'Q': fchanged = 0; case 'q': setnoaddr(); if((peekc = getchar()) != '\n') error; quit: dontgo(); newline(); rmfiles(); exit(); case EOF: /* I put this here JSK */ if (depth) return; /* for global changes */ setnoaddr(); dontgo(); rmfiles(); exit(); case 'r': caseread: filename(); setall(); readfile(addr2); continue; case 's': setdot(); nonzero(); substitute(globp); continue; case 't': move(1); continue; case 'v': global(0); continue; case 'W': case 'w': setall(); nonzero(); p = getchar(); if (p != '-') { peekc = p; p = 0; } filename(); io = p ? open(file,1): -1; if (io<0) io = creat(file,0644); if (io < 0) errfunc(CRERR); seek(io,0,2); /* go to end of file */ putfile(); exfile(); fchanged = 0; if (c == 'W') goto quit; continue; case 'z': getzlen(); flags.zflag++; printlines(); flags.zflag = flags.pflag = 0; continue; case '=': setall(); newline(); /* #ifndef LCOUNT count[1] = (addr2-zero)&077777; #endif #ifdef LCOUNT lcount = (addr2-zero)&077777; #endif putd(); ptchar('\n'); */ numout((addr2-zero)&077777); continue; case '!': unix(); continue; } error; } } address() { register *a1, minus, c; int n, relerr; extern char PROMPT[]; minus = 0; a1 = 0; for (;;) { c = getchar(); if ('0'<=c && c<='9') { n = 0; do { n =* 10; n =+ c - '0'; } while ((c = getchar())>='0' && c<='9'); peekc = c; if (a1==0) a1 = zero; if (minus<0) n = -n; a1 =+ n; minus = 0; continue; } relerr = 0; if (a1 || minus) relerr++; switch(c) { case ' ': case '\t': continue; case '+': minus++; if (a1==0) a1 = dot; continue; case '-': case '^': minus--; if (a1==0) a1 = dot; continue; case '?': case '/': compile(c); a1 = dot; for (;;) { if (c=='/') { a1++; if (a1 > dol) a1 = zero; } else { a1--; if (a1 < zero) a1 = dol; } if (execute(0, a1)) break; if (a1==dot) error; } break; case '$': a1 = dol; break; case '.': a1 = dot; break; case '\'': if ((c = getchar()) < 'a' || c > 'z') error; for (a1=zero; a1<=dol; a1++) if (names[c-'a'] == (*a1|01)) break; break; default: peekc = c; if (a1==0) return(0); a1 =+ minus; if (a1<zero) a1=zero; else if (a1>dol) a1=dol; return(a1); } if (relerr) error; } } setdot() { if (addr2 == 0) { if (dot>dol) error; addr1 = addr2 = dot; } if (addr1 > addr2) error; } setall() { if (addr2==0) { addr1 = zero+1; addr2 = dol; if (dol==zero) addr1 = zero; } setdot(); } setnoaddr() { if (addr2) error; } nonzero() { if (addr1 > dol) error; if (addr1 <= zero) addr1 = zero+1; if (addr2 > dol) addr2 = dol; if (addr1>addr2) error; } newline() { register c; if ((c = getchar()) == '\n') return; flags.pflag++; if (c=='l') flags.listf = 1; else if (c=='p'); else if (c=='n') flags.listf = 2; else error; if (getchar() != '\n') error; return; } filename() { register char *p1, *p2; register c; #ifndef LCOUNT count[1] = 0; #endif #ifdef LCOUNT lcount.integer[1] = 0; #endif c = getchar(); if (c=='\n' || c==EOF) { p1 = savedfile; if (*p1==0) error; p2 = file; while (*p2++ = *p1++); return; } if (c!=' ') error; while ((c = getchar()) == ' '); if (c=='\n') error; p1 = file; do { *p1++ = c; } while ((c = getchar()) != '\n'); *p1++ = 0; if (savedfile[0]==0) { p1 = savedfile; p2 = file; while (*p1++ = *p2++); } } exfile() { close(io); io = -1; if (flags.vflag) { putd(); ptchar('\n'); } } getzlen() { register int c; register int zmode; register int i; for(;;) switch(zmode=getchar()) { case '\t': case ' ': continue; case '.': case '-': case '+': case ',': c = getchar(); goto out; default: c = zmode; zmode = '+'; goto out; } out: c =- '0'; if (c >= 0 && c <= 9) { i = c; while ((c=getchar()-'0') >= 0 && c <= 9) i = i*10 + c; } else i = zlength; peekc = c+'0'; newline(); if(i!=0) zlength = i; if (addr2 == 0) addr1 = dot; switch (zmode) { case '.': addr1 =- zlength/2; break; case '-': addr1 =- zlength-1; break; case ',': addr1 =- 2*(zlength-1); } addr2 = addr1 + zlength-1; } onintr() { signal(SIGINTR, onintr); ptchar('\n'); error; } onhup() { extern char WREDHUP[]; globp = WREDHUP; commands(1); rmfiles(); exit(-1); } dontgo() { register char c; extern char DONTGO[]; if(!fchanged) { /*UPDATE*/ return; } fchanged = 0; errfunc(DONTGO); } errfunc(s) char *s; { flags.listf = 0; puts(s); #ifndef LCOUNT count[0] = 0; #endif LCOUNT #ifdef LCOUNT lcount = 0; #endif seek(0, 0, 2); flags.pflag = 0; globp = 0; if (io > 0) { close(io); io = -1; } peekc = 0; ttmode[2] = ttnorm; stty(0,ttmode); /* reset tty if necessary */ /* and flush all pending input */ flushlim = saveit; reset(); /* returns to top command level */ } getchar() { register int c; char cc; if (c=peekc) { peekc = 0; return c; } if (globp) { if ((c = *globp++) != 0) return c; globp = 0; return EOF; } if (read(0,&cc,1) <= 0) return EOF; return cc; } gettty() { register c, gf; register char *p; p = linebuf; gf = globp; while ((c = getchar()) != '\n') { if (c==EOF) { if (gf) peekc = c; return(c); } if (c == '\0') continue; *p++ = c; if (p >= &linebuf[LBSIZE-2]) error; } *p++ = 0; if (linebuf[0]=='.' && linebuf[1]==0) return(EOF); return(0); } getfile() { register c; register char *lp, *fp; extern char BUFERR[]; lp = linebuf; fp = nextip; do { if (--ninbuf < 0) { if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0) return(EOF); fp = genbuf; } if (lp >= &linebuf[LBSIZE]) errfunc(BUFERR); if ((*lp++ = c = *fp++ & 0177) == 0) { lp--; continue; } #ifndef LCOUNT if (++count[1] == 0) ++count[0]; #endif #ifdef LCOUNT lcount++; #endif } while (c != '\n'); *--lp = 0; nextip = fp; return(0); } putfile() { register char *fp, *lp; register int i; int *a1; extern char IOERR[]; i = 0; fp = genbuf; a1 = addr1; lp = getline(*a1); for (;;) { /* i = fp-genbuf; fp points to next place to put char to output genbuf[0..i-1] contains chars created to output a1 = line number of current line being moved lp points to next character to move count[0,1] contains total # of bytes moved */ #ifndef LCOUNT if (++count[1] == 0) ++count[0]; #endif #ifdef LCOUNT lcount++; #endif i++; if ((*fp++ = *lp++) == 0) { fp[-1] = '\n'; if (a1++ >= addr2) break; lp = getline(*a1); } if ( i == 512) { if (write(io,genbuf,i) != i) errfunc(IOERR); fp = genbuf; i = 0; } } if (write(io,genbuf,i) != i) errfunc(IOERR); } append(f, a) int (*f)(); { register *a1, *a2, *rdot; int nline, tl; extern char NMCERR[]; nline = 0; dot = a; while ((*f)() == 0) { tl = putline(); nline++; a1 = ++dol; rdot = endcore; if (dol >= rdot) { rdot = (rdot|07777) + 1; /* 2k bytes */ if(brk(rdot) < 0) errfunc(NMCERR); endcore = rdot; } a2 = a1+1; rdot = ++dot; while (a1 > rdot) *--a2 = *--a1; *rdot = tl; } rdot = (dol|037) + 1; /* tighten up data */ if(rdot!=endcore) brk(endcore); /* space to nearest */ /* 64 bytes */ /* possibly put in */ /* flushtmp */ return(nline); } unix() { register pid, rpid; register char *p; int retcode; extern char BANG[]; extern char BUFERR[]; extern char MC[]; extern char SH[]; extern char MSH[]; setnoaddr(); p = linebuf; while ( (*p = getchar()) != '\n' && *p != EOF ) if (p++ >= linebuf + LBSIZE) errfunc(BUFERR); *p = 0; if ((pid = fork()) == 0) { /* unneeded: signal(SIGHUP, onhup); signal(SIGQUIT, onquit); */ execl(SH, MSH, *linebuf?MC:0, linebuf, 0); error; } p = signal(SIGINTR, 1); while ((rpid = wait(&retcode)) != pid && rpid != -1); signal(SIGINTR, p); puts(BANG); } delete() { register *a1, *a2; register int a3; extern int *dol; extern int *dot; extern int *addr1; extern int *addr2; extern UNSIGNED flushlim; extern UNSIGNED fchanged; struct { int* ptr; }; a1 = addr1; a2 = addr2+1; a3 = dol-a2+2; while(--a3) *a1++ = *a2++; fchanged =+ a2 - a1; a3 = (dol =- a2 - a1); a1 = addr1; if (a1 > a3.ptr) a1 = a3; dot = a1; if (fchanged>flushlim) flushtmp(); } join() { register char *a1,*a2; a1 = genbuf; addr1 = addr2-1; if (addr1 <= zero) error; a2 = getline(*addr2); while (*a1++ = *a2++); a1 = getline(*addr1); while (*a1++); --a1; a2 = genbuf; while (*a1++ = *a2++); *addr2 = putline(); addr2 = addr1; delete(); } getline(tl) { register char *bp, *lp; register nl; lp = linebuf; bp = getblock(tl, READ); nl = nleft; tl =& ~0377; while (*lp++ = *bp++) if (--nl == 0) { bp = getblock(tl=+0400, READ); nl = nleft; } return(linebuf); } putline() { register char *bp, *lp; register nl; int tl; lp = linebuf; tl = tline; bp = getblock(tl, WRITE); nl = nleft; tl =& ~0377; while (*bp = *lp++) { if (*bp++ == '\n') { *--bp = 0; linebp = lp; break; } if (--nl == 0) { bp = getblock(tl=+0400, WRITE); nl = nleft; } } nl = tline; tline =+ (((lp-linebuf)+03)>>1)&077776; fchanged++; if (fchanged>flushlim) flushtmp(); return(nl); } getblock(atl, iof) { register bno, off; extern char TMPERR[]; extern read(), write(); bno = (atl>>8)&0377; off = (atl<<1)&0774; if (bno >= 255) errfunc(TMPERR); nleft = 512 - off; if (bno==iblock) { ichanged =| iof; return(ibuff+off); } if (bno==oblock) return(obuff+off); if (iof==READ) { if (ichanged) blkio(iblock, ibuff, write); ichanged = 0; iblock = bno; blkio(bno, ibuff, read); return(ibuff+off); } if (oblock>=0) blkio(oblock, obuff, write); oblock = bno; return(obuff+off); } flushtmp() { /* this causes temporaries to be updated to most current state. Then reset fchanged to 1 if fchanged was > 0. */ register int *a; register int i; extern read(), write(); extern char NMCERR[]; extern char IOERR[]; #ifdef TELLME /*%%*/ puts("flushtmp"); #endif if (ichanged) blkio(iblock,ibuff,write); ichanged = 0; blkio(oblock,obuff,write); if (tlpfile) seek(tlpfile,0,0); /* go back to start */ else { tfname[5] = 'E'; tlpfile = creat(tfname, 0600); tfname[5] = 'e'; } a = endcore; if (dol+1 >= a) { a = (a|037) + 1; /* 64 bytes */ if(dol<a || brk(a) < 0) errfunc(NMCERR); endcore = a; } *(dol+1) = -1; /* mark eof */ for (a = zero+1; a < (dol-255); a =+ 256) if ( write(tlpfile,a,512) != 512) errfunc(IOERR); i = dol - a + 2; /* length of last write */ i =* 2; if ( write(tlpfile,a,i) != i ) errfunc(IOERR); if (fchanged) fchanged=1; /* don't set to 0 because 'w' command wasn't issued */ } blkio(b, buf, iofcn) int (*iofcn)(); { extern char TMPERR[]; if( seek(tfile, b, 3)<0 || (*iofcn)(tfile, buf, 512) != 512) /*%%*/ errfunc("IO to tmp"); } init() { close(tfile); rmfiles(); fchanged = ichanged = 0; tline = 0; iblock = -1; oblock = -1; tfname[0] = 'e'; tfname[4] = '.'; tfile = creat(tfname,0600); if (tfile < 0) { /* couldn't make temp in local area, try /tmp */ tfname[0] = '/'; tfname[4] = '/'; tfile = creat(tfname,0600); } /* must close and open it to get the right access! */ close(tfile); open(tfname, 2); brk(fendcore); dot = zero = dol = fendcore; endcore = fendcore - 4; } rmfiles() { tfname[5] = 'E'; unlink(tfname); tfname[5] = 'e'; unlink(tfname); if (tlpfile) close (tlpfile); tlpfile = 0; } global(k) { register c; register int *a1; register char *gp; char globuf[GBSIZE]; extern char BUFERR[]; if (globp) error; setall(); nonzero(); if ((c=getchar())=='\n') error; compile(c); gp = globuf; while ((c = getchar()) != '\n') { if (c==EOF) error; if (c=='\\') { c = getchar(); if (c!='\n') *gp++ = '\\'; } *gp++ = c; if (gp >= &globuf[GBSIZE-2]) errfunc(BUFERR); } *gp++ = '\n'; *gp++ = 0; for (a1=zero; a1<=dol; a1++) { *a1 =& ~01; if (a1>=addr1 && a1<=addr2 && execute(0, a1)==k) *a1 =| 01; } /* fewer flushtmps during global change */ saveit = flushlim; flushlim = BIGLIM; for (a1=zero; a1<=dol; a1++) { if (*a1 & 01) { *a1 =& ~01; dot = a1; globp = globuf; commands(1); a1 = zero; } } flushlim = saveit; if(fchanged>flushlim) flushtmp (); } substitute(inglob) { register gsubf, *a1, nl; int getsub(); gsubf = compsub(); for (a1 = addr1; a1 <= addr2; a1++) { if (execute(0, a1)==0) continue; inglob =| 01; dosub(); if (gsubf) { while (*loc2) { if (execute(1)==0) break; dosub(); } } *a1 = putline(); nl = append(getsub, a1); a1 =+ nl; addr2 =+ nl; } if (inglob==0) error; } compsub() { register seof, c; register char *p; int gsubf; extern char BUFERR[]; if ((seof = getchar()) == '\n') return(0); if (seof >= 'a' && seof <= 'z') { if (seof != 'g') peekc=seof; newline(); if (seof == 'g') return(1); /* signal global parm */ else return(0); } compile(seof); p = rhsbuf; for (;;) { c = getchar(); if (c=='\\') c = getchar() | 0200; if (c=='\n') error; if (c==seof) break; *p++ = c; if (p >= &rhsbuf[LBSIZE/2]) errfunc(BUFERR); } *p++ = 0; if ((peekc = getchar()) == 'g') { peekc = 0; newline(); return(1); } newline(); return(0); } getsub() { register char *p1, *p2; p1 = linebuf; if ((p2 = linebp) == 0) return(EOF); while (*p1++ = *p2++); linebp = 0; return(0); } dosub() { register char *lp, *sp, *rp; int c; extern char BUFERR[]; lp = linebuf; sp = genbuf; rp = rhsbuf; while (lp < loc1) *sp++ = *lp++; while (c = *rp++) { if (c=='&') { sp = place(sp, loc1, loc2); continue; } else if (c<0 && (c =& 0177) >='1' && c < NBRA+'1') { sp = place(sp, braslist[c-'1'], braelist[c-'1']); continue; } *sp++ = c&0177; if (sp >= &genbuf[LBSIZE]) errfunc(BUFERR); } lp = loc2; loc2 = sp + linebuf - genbuf; while (*sp++ = *lp++) if (sp >= &genbuf[LBSIZE]) errfunc(BUFERR); lp = linebuf; sp = genbuf; while (*lp++ = *sp++); } place(asp, al1, al2) { register char *sp, *l1, *l2; extern char BUFERR[]; sp = asp; l1 = al1; l2 = al2; while (l1 < l2) { *sp++ = *l1++; if (sp >= &genbuf[LBSIZE]) errfunc(BUFERR); } return(sp); } move(copy) int copy; { register int *adt, *ad1, *ad2; int getcopy(); setdot(); nonzero(); if ((adt = address())==0) error; newline(); saveit = flushlim; flushlim = BIGLIM; if (copy) { ad1 = dol+1; append(getcopy,dol); /* getcopy delivers addr1 thru addr2; append changes dol */ ad2 = dol+1; } else { ad1 = addr1; ad2 = addr2+1; } 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; fchanged =+ ad1-ad2; if(!globp) flushtmp(); flushlim = saveit; } reverse(aa1, aa2) { register int *a1, *a2, t; a1 = aa1; a2 = aa2; for (;;) { t = *--a2; if (a2 <= a1) return; *a2 = *a1; *a1++ = t; } } getcopy() { if (addr1 > addr2) return(EOF); getline(*addr1++); return(0); } compile(aeof) { register eof, c; register char *ep; char *lastep; char bracket[NBRA], *bracketp; int nbra; int cclcnt; ep = expbuf; eof = aeof; bracketp = bracket; nbra = 0; if ((c = getchar()) == eof) { if (*ep==0) error; return; } else if (c == '\n') { peekc = c; return; } flags.circfl = 0; if (c=='^') { c = getchar(); flags.circfl++; } if (c=='*') goto cerror; peekc = c; for (;;) { if (ep >= &expbuf[ESIZE]) goto cerror; c = getchar(); if (c==eof) { *ep++ = CEOF; return; } if (c!='*') lastep = ep; switch (c) { case '\\': if ((c = getchar())=='(') { if (nbra >= NBRA) goto cerror; *bracketp++ = nbra; *ep++ = CBRA; *ep++ = nbra++; continue; } if (c == ')') { if (bracketp <= bracket) goto cerror; *ep++ = CKET; *ep++ = *--bracketp; continue; } if (c=='\n') cerror; goto defchar; case '.': *ep++ = CDOT; continue; case '\n': *ep++ = CEOF; peekc = c; return; case '*': if (*lastep==CBRA || *lastep==CKET) error; *lastep =| STAR; continue; case '$': if ((peekc=getchar()) != eof) goto defchar; *ep++ = CDOL; continue; case '[': *ep++ = CCL; *ep++ = 0; cclcnt = 1; if ((c=getchar()) == '^') { c = getchar(); ep[-2] = NCCL; } do { if (c=='\n') goto cerror; *ep++ = c; cclcnt++; if (ep >= &expbuf[ESIZE]) goto cerror; } while ((c = getchar()) != ']'); lastep[1] = cclcnt; continue; defchar: default: *ep++ = CCHR; *ep++ = c; } } cerror: expbuf[0] = 0; error; } execute(gf, addr) int *addr; { register char *p1, *p2, c; if (gf) { if (flags.circfl) return(0); p1 = linebuf; p2 = genbuf; while (*p1++ = *p2++); locs = p1 = loc2; } else { if (addr==zero) return(0); p1 = getline(*addr); locs = 0; } p2 = expbuf; if (flags.circfl) { loc1 = p1; return(advance(p1, p2)); } /* fast check for first character */ if (*p2==CCHR) { c = p2[1]; do { if (*p1!=c) continue; if (advance(p1, p2)) { loc1 = p1; return(1); } } while (*p1++); return(0); } /* regular algorithm */ do { if (advance(p1, p2)) { loc1 = p1; return(1); } } while (*p1++); return(0); } advance(alp, aep) { register char *lp, *ep, *curlp; char *nextep; lp = alp; ep = aep; for (;;) switch (*ep++) { case CCHR: if (*ep++ == *lp++) continue; return(0); case CDOT: if (*lp++) continue; return(0); case CDOL: if (*lp==0) continue; return(0); case CEOF: loc2 = lp; return(1); case CCL: if (cclass(ep, *lp++, 1)) { ep =+ *ep; continue; } return(0); case NCCL: if (cclass(ep, *lp++, 0)) { ep =+ *ep; continue; } return(0); case CBRA: braslist[*ep++] = lp; continue; case CKET: braelist[*ep++] = lp; continue; case CDOT|STAR: curlp = lp; while (*lp++); goto star; case CCHR|STAR: curlp = lp; while (*lp++ == *ep); ep++; goto star; case CCL|STAR: case NCCL|STAR: curlp = lp; while (cclass(ep, *lp++, ep[-1]==(CCL|STAR))); ep =+ *ep; goto star; star: do { lp--; if (lp==locs) break; if (advance(lp, ep)) return(1); } while (lp > curlp); return(0); default: error; } } cclass(aset, ac, af) { register char *set, c; register n; set = aset; if ((c = ac) == 0) return(0); n = *set++; while (--n) if (*set++ == c) return(af); return(!af); } putd() { register r; extern ldivr; #ifndef LCOUNT count[1] = ldiv(count[0], count[1], 10); count[0] = 0; r = ldivr; if (count[1]) putd(); #endif #ifdef LCOUNT lcount.integer[1] = ldiv(lcount.integer[0],lcount.integer[1], 10); lcount.integer[0] = 0; r = ldivr; if (lcount.integer[1]) putd(); #endif ptchar(r + '0'); } puts(as) { register char *sp; sp = as; col = 0; while (*sp) ptchar(*sp++); ptchar('\n'); } char line[70]; char *linp line; ptchar(ac) { register char *lp; register c; register char i; static char linx; lp = linp; c = ac; if (flags.listf == 1) { col++; if (col >= 72) { col = 0; *lp++ = '\\'; *lp++ = '\n'; } if (c=='\t') { c = '>'; goto esc; } if (c=='\b') { c = '<'; esc: *lp++ = '\\'; col++; goto out1; } if (c == '\\') { goto esc; } if (c<' ' && c!= '\n') { *lp++ = '\\'; /**lp++ = ((c>>6)&3)+'0';*//* would be nice ... */ *lp++ = (c>>3)+'0'; *lp++ = (c&7)+'0'; col =+ 2; goto out; } } out1: *lp++ = c; out: if(c == '\n' || lp >= &line[64]) { linp = line; write(1, line, lp-line); return; } linp = lp; } /* * Get process ID routine if system call is unavailable. getpid() { register f; int b[1]; f = open("/dev/kmem", 0); if(f < 0) return(-1); seek(f, 0140074, 0); read(f, b, 2); seek(f, b[0]+8, 0); read(f, b, 2); close(f); return(b[0]); } */ ilsubst() { register int *a1, nl; extern int getsub(); for(a1=addr1; a1<=addr2; a1++) { getline(*a1); if(ildo()) { *a1=putline(); nl=append(getsub,a1); a1=+ nl; addr2=+ nl; } } } ildo() { register char *t1; register int n; register int c; extern char BELL[]; restart: for(t1 = &linebuf[0]; *t1++;); t1++; /* copy '\0' also */ fr = &genbuf[LBSIZE]; for(n = t1-&linebuf[0]; n--;) *--fr = *--t1; to = &genbuf[0]; for(;;) { t1=0; c=ilgetchar(); if(c=='-') { t1++; /* indicate minus */ c = ilgetchar(); } if(c>='0' && c<='9') { n=0; do { n=* 10; n=+ c-'0'; } while((c=ilgetchar())>='0' && c<='9'); } else if (c=='$') { n = &genbuf[LBSIZE]-fr; c = ilgetchar(); } else n = 1; if(t1) n= -n; switch(c) { case '\b': n= -n; case ' ': if(n<0) while(n++ && ilmove(LEFT,COPY)); else { c = n; t1 = fr; while(n-- && ilmoveR(COPY)); write(1,t1,fr-t1); } break; case CTLA: n= -n; case 'd': if(n<0) while(n++ && ilmove(LEFT,NOCOPY)); else { c = n; t1 = fr; while(n-- && ilmoveR(NOCOPY)); write(1,t1,fr-t1); } break; case 'c': while(n) { c=ilgetchar(); if(! *fr) break; if(c==EOT||c=='') break;/*cntd or esc*/ if(n>0) { *fr = c; n--; } else { *--fr = c; n++; } ilmove(n>=0?RIGHT:LEFT,COPY); } break; case 'r': if(n<0) while(n++ && ilmove(LEFT,NOCOPY)); else { c = n; t1 = fr; while(n-- && ilmoveR(NOCOPY)); write(1,t1,fr-t1); } case 'i': /* while !cntd and !esc */ while((c=ilgetchar())!=EOT&&c!=''&&c!=EOF) { if(to == fr) break; if (c == '\b') ilmove(LEFT,NOCOPY); else { *--fr = c; ilmove(RIGHT,COPY); } } break; case '@': writenl(); goto restart; case 'e': while(ilmoveR(COPY)); case 'f': show(); if((ttmode[2]&050)!=040) /* if !raw */ ilgetchar(); goto finish; case '\t': show(); if(n>0) { writef1(fr); while(ilmoveR(COPY)); } else while(ilmove(LEFT,COPY)); break; case '\n': show(); writef1(fr); while(ilmoveR(COPY)); finish: *to = 0; to= &linebuf[0]; fr= &genbuf[0]; for(n=0;;) { if(*fr!=*to) { *to = *fr; n = 1; } if(*fr=='\0') { *to = *fr; /* always */ break; } to++; fr++; } writenl(); flags.hiding=0; return n; /* indicates if line has been modified */ case 'p': show(); writef1(fr); writenl(); t1 = &genbuf[0]; if(to>t1) write(1,t1,to-t1); break; case 'l': show(); writef1(fr); writenl(); n = to - &genbuf[0]; while(n--) *--fr = *--to; break; case 's': show(); c=ilgetchar(); if(n<0) while(n++) { do ilmove(LEFT,COPY); while(to != &genbuf[0] && *(to-1) != c); } else for(t1 = fr; n--&&*t1!='\0';) { for(;;) { if(*++t1 == '\0' || *t1 == c) { write(1,fr,t1-fr); break; } } while(ilmoveR(COPY) && *fr != c); } break; case 'k': c=ilgetchar(); if(n<0) { t1=to-1; while(n++) { while(t1 != &genbuf[0]) if(*--t1==c) { t1=to-t1; while(t1--) ilmove(LEFT,NOCOPY); break; } } } else { t1 = fr+1; while(n--) { while(*t1) if(*t1==c) { t1=- fr; hide(); write(1,fr,t1); while(t1--) ilmoveR(NOCOPY); break; } else t1++; } } break; default: writef1(BELL); } } } char ilmove(dir,cp) int dir,cp; { register char c; if(dir==LEFT) { if(to == &genbuf[0]) return(0); hide(); c = *--to; write(1,to,1); if(cp==COPY) *--fr = c; return(c); } else { if(! *fr) return(0); if(cp==COPY) show(); else hide(); write(1,fr,1); c = *fr++; if(cp==COPY) *to++ = c; return(c); } } char ilmoveR(cp) int cp; { register char c; if(! *fr) return(0); if(cp==COPY) show(); else hide(); c = *fr++; if(cp==COPY) *to++ = c; return(c); } ilgetchar() { register char c,d; c = getchar(); if(c == '\\') { d = getchar(); if(d=='@' || d=='\b' || d==CTLA || d=='\\')return(d); if(ttmode[2] & 04) { /* half-ascii terminal escapes */ if(d >= 'a' && d <= 'z') return(d-'a'+'A'); switch(d) { case '!': return('|'); case '\'': return('`'); case '^': return('~'); case '(': return('{'); case ')': return('}'); } } peekc = d; /* ASSERT: c == backslash */ } return c; } show() { extern char BACKSL[]; if(flags.hiding) { writef1(BACKSL); flags.hiding=0; } } hide() { extern char BACKSL[]; if(!flags.hiding) { writef1(BACKSL); flags.hiding=1; } } printlines() { register char *p,*s; register int *a1; nonzero(); for (a1 = addr1; a1 <= addr2; a1++) { if (flags.listf == 2) { #ifndef LCOUNT count[1] = (a1-zero) & 077777; #endif #ifdef LCOUNT lcount.integer[1] = (a1-zero) & 077777; #endif putd(); ptchar('\t'); } #ifdef DONTLIKEIT p = getline(*a1); if (flags.zflag) for (s=p; *s; s++) if (*s==NP) { *s = 0; puts(p); dot = a1+1; goto exit; } puts(p); #endif DONTLIKEIT #ifndef DONTLIKEIT puts(getline(*a1)); #endif } dot = addr2; exit: flags.listf = 0; } readfile(addr) { extern char OPERR[]; if ((io = open(file, 0)) < 0) errfunc(OPERR); ninbuf = 0; /* don't flush during read */ saveit = flushlim; flushlim = BIGLIM; append(getfile, addr); exfile(); flushlim = saveit; } /* name: writef1 function: Write a null terminated string without the terminator algorithm: Determine the length of the string. Write it out. CAVEAT This call is not buffered, so use it carefully or pay the cost of high I/O expense. It was writted to decrease subroutine linkage global variable referencing and module size. But those gains can easily be lost if writef is consistantly called with small strings. where buffered i/o would be possible. parameters: *char pointer to null terminated string. returns: int value returned by write. globals: calls: write() called by: lotsa people history: Coded by R. Balocca (CAC) sometime in 1976 */ writef1(str) char* str; { register char *r; register char *s; s = str; r = s; while(*s++); return write(1, r, --s-r); } writenl() { extern char NL[]; writef1(NL); } errr() { extern char Q[]; errfunc(Q); } numout(i) int i; { #ifndef LCOUNT count[1] = i; #endif #ifdef LCOUNT lcount = i; #endif putd(); ptchar('\n'); } #ifndef EXTERNAL char TMPERR[] "Temp file error"; char IOERR[] "Write error"; char BUFERR[] "Buffer overflow"; char NMCERR[] "No more core"; char BELL[] ""; /* ascii bell */ char BACKSL[] "\\"; /* ascii backslash */ char SH[] "/bin/sh"; char MSH[] "-sh"; char CRERR[] "Can't create"; char PROMPT[] "* "; char WREDHUP[] "w ed-hup\n"; char NL[] "\n"; char OPERR[] "Can't open"; char BANG[] "!"; char Q[] "?"; char MC[] "-c"; char DONTGO[] "Modified file not written out"; #endif