aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ed.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-11-23 18:04:47 +0000
committerrsc <devnull@localhost>2003-11-23 18:04:47 +0000
commitbc7cb1a15a67c859c8c71c4b52bb35fe9425a63d (patch)
tree8ca0fe4e2418e6aa18dc74a236c577a719f6c6ed /src/cmd/ed.c
parentf08fdedcee12c06e3ce9ac9bec363915978e8289 (diff)
downloadplan9port-bc7cb1a15a67c859c8c71c4b52bb35fe9425a63d.tar.gz
plan9port-bc7cb1a15a67c859c8c71c4b52bb35fe9425a63d.tar.bz2
plan9port-bc7cb1a15a67c859c8c71c4b52bb35fe9425a63d.zip
new utilities.
the .C files compile but are renamed to avoid building automatically.
Diffstat (limited to 'src/cmd/ed.c')
-rw-r--r--src/cmd/ed.c1608
1 files changed, 1608 insertions, 0 deletions
diff --git a/src/cmd/ed.c b/src/cmd/ed.c
new file mode 100644
index 00000000..42fa3e07
--- /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);
+}