diff options
Diffstat (limited to 'appl/cmd/ed.b')
| -rw-r--r-- | appl/cmd/ed.b | 1588 |
1 files changed, 1588 insertions, 0 deletions
diff --git a/appl/cmd/ed.b b/appl/cmd/ed.b new file mode 100644 index 00000000..e374ce4e --- /dev/null +++ b/appl/cmd/ed.b @@ -0,0 +1,1588 @@ +# +# Editor +# + +implement Editor; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "regex.m"; + regex: Regex; + Re: import regex; +include "sh.m"; + sh: Sh; + +Editor: module { + init: fn(nil: ref Draw->Context, args: list of string); +}; + +FNSIZE: con 128; # file name +LBSIZE: con 4096; # max line size +BLKSIZE: con 4096; # block size in temp file +NBLK: con 8191; # max size of temp file +ESIZE: con 256; # max size of reg exp +GBSIZE: con 256; # max size of global command +MAXSUB: con 9; # max number of sub reg exp +ESCFLG: con 16rFFFF; # escape Rune - user defined code +EOF: con -1; +BytesPerRune: con 2; +RunesPerBlock: con BLKSIZE / BytesPerRune; + +APPEND_GETTTY, APPEND_GETSUB, APPEND_GETCOPY, APPEND_GETFILE: con iota; + +Subexp: adt { + rsp, rep: int; +}; + +Globp: adt { + s: string; + isnil: int; +}; + +addr1: int; +addr2: int; +anymarks: int; +col: int; +count: int; +dol: int; +dot: int; +fchange: int; +file: string; +genbuf := array[LBSIZE] of int; +given: int; +globp: Globp; +iblock: int; +ichanged: int; +io: ref Sys->FD; +iobuf: ref Iobuf; +lastc: int; +line := array [70] of byte; +linebp := -1; +linebuf := array [LBSIZE] of int; +listf: int; +listn: int; +loc1: int; +loc2: int; +names := array [26] of int; +oblock: int; +oflag: int; +pattern: Re; +peekc: int; +pflag: int; +rescuing: int; +rhsbuf := array [LBSIZE/2] of int; +savedfile: string; +subnewa: int; +subolda: int; +subexp: array of Subexp; +tfname: string; +tline: int; +waiting: int; +wrapp: int; +zero: array of int; +drawctxt: ref Draw->Context; + +Q: con ""; +T: con "TMP"; +WRERR: con "WRITE ERROR"; +bpagesize := 20; +hex: con "0123456789abcdef"; +linp: int; +nlall := 128; +tfile: ref Sys->FD; +vflag := 1; + +debug(s: string) +{ + sys->print("%s", s); +} + +init(ctxt: ref Draw->Context, args: list of string) +{ + drawctxt = ctxt; + + sys = load Sys Sys->PATH; + bufio = load Bufio Bufio->PATH; + if (bufio == nil) { + sys->fprint(sys->fildes(2), "can't load %s\n", Bufio->PATH); + return; + } + regex = load Regex Regex->PATH; + if (regex == nil) { + sys->fprint(sys->fildes(2), "can't load %s\n", Regex->PATH); + return; + } + +# notify(notifyf); + + if (args != nil) + args = tl args; + + if (args != nil && hd args == "-o") { + oflag = 1; + vflag = 0; + args = tl args; + } + + if (args != nil && hd args == "-") { + vflag = 0; + args = tl args; + } + + if (oflag) { + savedfile = "/fd/1"; + globp = ("a", 0); + } else if (args != nil) { + savedfile = hd args; + globp = ("r", 0); + } + else + globp = (nil, 1); + zero = array [nlall + 5] of int; + tfname = mktemp("/tmp/eXXXXX"); +# debug(sys->sprint("tfname %s\n", tfname)); + _init(); + for(;;){ + { + commands(); + quit(); + }exception{ + "savej" => + ; + } + } +} + +casee(c: int) +{ + setnoaddr(); + if(vflag && fchange) { + fchange = 0; + error(Q); + } + filename(c); + _init(); + addr2 = 0; + caseread(); +} + +casep() +{ + newline(); + printcom(); +} + +caseq() +{ + setnoaddr(); + newline(); + quit(); +} + +caseread() +{ +#debug("caseread " + file); + if((io=sys->open(file, Sys->OREAD)) == nil) { + lastc = '\n'; + error(file); + } + iobuf = bufio->fopen(io, Sys->OREAD); + setwide(); + squeeze(0); + c := 0 != dol; + append(APPEND_GETFILE, addr2); + exfile(Sys->OREAD); + + fchange = c; +} + +commands() +{ + a1: int; + c, temp: int; + lastsep: int; + + for(;;) { + if(pflag) { + pflag = 0; + addr1 = addr2 = dot; + printcom(); + } + c = '\n'; + for(addr1 = -1;;) { + lastsep = c; + a1 = address(); + c = getchr(); + if(c != ',' && c != ';') + break; + if(lastsep == ',') + error(Q); + if(a1 < 0) { + a1 = 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; +#debug(sys->sprint("%d,%d %c\n", addr1, addr2, c)); + case c { + 'a' => + add(0); + continue; + + 'b' => + nonzero(); + browse(); + continue; + + 'c' => + nonzero(); + newline(); + rdelete(addr1, addr2); + append(APPEND_GETTTY, addr1-1); + continue; + + 'd' => + nonzero(); + newline(); + rdelete(addr1, addr2); + continue; + + 'E' => + fchange = 0; + c = 'e'; + casee(c); + continue; + + 'e' => + casee(c); + continue; + + 'f' => + setnoaddr(); + filename(c); + putst(savedfile); + continue; + + 'g' => + global(1); + continue; + + 'i' => + add(-1); + continue; + + 'j' => + if(!given) + addr2++; + newline(); + join(); + continue; + + 'k' => + nonzero(); + c = getchr(); + if(c < 'a' || c > 'z') + error(Q); + newline(); + names[c-'a'] = zero[addr2] & ~16r1; + anymarks |= 16r1; + continue; + + 'm' => + move(0); + continue; + + 'n' => + listn++; + newline(); + printcom(); + continue; + + '\n' => + if(a1 < 0) { + a1 = dot+1; + addr2 = a1; + addr1 = a1; + } + if(lastsep==';') + addr1 = a1; + printcom(); + continue; + + 'l' => + listf++; + casep(); + continue; + + 'p' or 'P' => + casep(); + continue; + + 'Q' => + fchange = 0; + caseq(); + continue; + + 'q' => + caseq(); + continue; + + 'r' => + filename(c); + caseread(); + continue; + + 's' => + nonzero(); + substitute(!globp.isnil); + continue; + + 't' => + move(1); + continue; + + 'u' => + nonzero(); + newline(); + if((zero[addr2]&~8r01) != subnewa) + error(Q); + zero[addr2] = subolda; + dot = addr2; + continue; + + 'v' => + global(0); + continue; + + 'W' or 'w' => + if (c == 'W') + wrapp++; + setwide(); + squeeze(dol>0); + temp = getchr(); + if(temp != 'q' && temp != 'Q') { + peekc = temp; + temp = 0; + } + filename(c); + if(!wrapp || + ((io = sys->open(file, Sys->OWRITE)) == nil) || + ((sys->seek(io, big 0, Sys->SEEKEND)) < big 0)) + if((io = sys->create(file, Sys->OWRITE, 8r0666)) == nil) + error(file); + iobuf = bufio->fopen(io, Sys->OWRITE); + wrapp = 0; + if(dol > 0) + putfile(); + exfile(Sys->OWRITE); + if(addr1<=1 && addr2==dol) + fchange = 0; + if(temp == 'Q') + fchange = 0; + if(temp) + quit(); + continue; + + '=' => + setwide(); + squeeze(0); + newline(); + count = addr2 - 0; + putd(); + putchr('\n'); + continue; + + '!' => + callunix(); + continue; + + EOF => + return; + + } + error(Q); + } +} + +printcom() +{ + a1: int; + + nonzero(); + a1 = addr1; + do { + if(listn) { + count = a1-0; + putd(); + putchr('\t'); + } + putshst(getline(zero[a1++])); + } while(a1 <= addr2); + dot = addr2; + listf = 0; + listn = 0; + pflag = 0; +} + + +address(): int +{ + sign, a, opcnt, nextopand, b, c: int; + + 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 = 0; + a += sign*getnum(); + } else + case c { + '$' or '.' => + if (c == '$') + a = dol; + if(opcnt) + error(Q); + + '\'' => + c = getchr(); + if(opcnt || c < 'a' || c > 'z') + error(Q); + a = 0; + do { + a++; + } while(a <= dol && names[c-'a'] != (zero[a] & ~8r01)); + + '?' or '/' => + if (c == '?') + sign = -sign; + compile(c); + b = a; + for(;;) { + a += sign; + if(a <= 0) + a = dol; + if(a > dol) + a = 0; + if(match(a)) + break; + if(a == b) + error(Q); + } + break; + + * => + if(nextopand == opcnt) { + a += sign; + if(a < 0 || dol < a) + continue; # error(Q); + } + if(c != '+' && c != '-' && c != '^') { + peekc = c; + if(opcnt == 0) + a = -1; + return a; + } + sign = 1; + if(c != '+') + sign = -sign; + nextopand = ++opcnt; + continue; + } + sign = 1; + opcnt++; + } while(0 <= a && a <= dol); + error(Q); + return -1; +} + +getnum(): int +{ + r, c: int; + + r = 0; + for(;;) { + c = getchr(); + if(c < '0' || c > '9') + break; + r = r*10 + (c-'0'); + } + peekc = c; + return r; +} + +setwide() +{ + if(!given) { + addr1 = 0 + (dol>0); + addr2 = dol; + } +} + +setnoaddr() +{ + if(given) + error(Q); +} + +nonzero() +{ + squeeze(1); +} + +squeeze(i: int) +{ + if(addr1 < 0+i || addr2 > dol || addr1 > addr2) + error(Q); +} + +newline() +{ + c: int; + + 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); +} + +filename(comm: int) +{ + rune: int; + c: int; + + count = 0; + c = getchr(); + if(c == '\n' || c == EOF) { + if(savedfile == nil && comm != 'f') + error(Q); + file = savedfile; + return; + } + if(c != ' ') + error(Q); + while((c=getchr()) == ' ') + ; + if(c == '\n') + error(Q); + file = nil; + do { + if(c == ' ' || c == EOF) + error(Q); + rune = c; + file[len file] = c; + } while((c=getchr()) != '\n'); + if(savedfile == nil || comm == 'e' || comm == 'f') + savedfile = file; +} + +exfile(om: int) +{ + + if(om == Sys->OWRITE) + if(iobuf.flush() < 0) + error(Q); + iobuf.close(); + iobuf = nil; + io = nil; + if(vflag) { + putd(); + putchr('\n'); + } +} + +error1(s: string) +{ + c: int; + + wrapp = 0; + listf = 0; + listn = 0; + count = 0; + sys->seek(sys->fildes(0), big 0, Sys->SEEKEND); # what does this do? + pflag = 0; + if(!globp.isnil) + lastc = '\n'; + globp = (nil, 1); + peekc = lastc; + if(lastc) + for(;;) { + c = getchr(); + if(c == '\n' || c == EOF) + break; + } + if(io != nil) + io = nil; + putchr('?'); + putst(s); +} + +error(s: string) +{ + error1(s); + raise "savej"; +} + +rescue() +{ + rescuing = 1; + if(dol > 0) { + addr1 = 0+1; + addr2 = dol; + io = sys->create("ed.hup", Sys->OWRITE, 8r0666); + if(io != nil){ + iobuf = bufio->fopen(io, Sys->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(); +# } + +getchr(): int +{ + s := array [Sys->UTFmax] of byte; + i: int; + r: int; + status: int; + if(lastc = peekc) { + peekc = 0; +#debug(sys->sprint("getchr: peekc %c\n", lastc)); + return lastc; + } + if(!globp.isnil) { + if (globp.s != nil) { + lastc = globp.s[0]; + globp.s = globp.s[1:]; +#debug(sys->sprint("getchr: globp %c remaining %d\n", lastc, len globp.s)); + return lastc; + } + globp = (nil, 1); +#debug(sys->sprint("getchr: globp end\n")); + return EOF; + } +#debug("globp nil\n"); + for(i=0;;) { + if(sys->read(sys->fildes(0), s[i:], 1) <= 0) + return lastc = EOF; + i++; + (r, nil, status) = sys->byte2char(s, 0); + if (status > 0) + break; + + } + lastc = r; + return lastc; +} + +gety(): int +{ + c: int; + gf: int; + p: int; + + p = 0; + gf = !globp.isnil; + for(;;) { + c = getchr(); + if(c == '\n') { + linebuf[p] = 0; + return 0; + } + if(c == EOF) { + if(gf) + peekc = c; + return c; + } + if(c == 0) + continue; + linebuf[p++] = c; + if(p >= len linebuf) + error(Q); + } + return 0; +} + +gettty(): int +{ + rc: int; + + rc = gety(); + if(rc) + return rc; + if(linebuf[0] == '.' && linebuf[1] == 0) + return EOF; + return 0; +} + +getfile(): int +{ + c: int; + lp: int; + + lp = 0; + do { + c = iobuf.getc(); + if(c < 0) { + if(lp > 0) { + putst("'\\n' appended"); + c = '\n'; + } else + return EOF; + } + if(lp >= len linebuf) { + lastc = '\n'; + error(Q); + } + linebuf[lp++] = c; + count++; + } while(c != '\n'); + linebuf[lp - 1] = 0; +#debug(sys->sprint("getline read %d\n", lp)); + return 0; +} + +putfile() +{ + a1: int; + lp: int; + c: int; + + a1 = addr1; + do { + lp = getline(zero[a1++]); + for(;;) { + count++; + c = linebuf[lp++]; + if(c == 0) { + if (iobuf.putc('\n') < 0) + error(Q); + break; + } + if (iobuf.putc(c) < 0) + error(Q); + } + } while(a1 <= addr2); + if(iobuf.flush() < 0) + error(Q); +} + +append(f: int, a: int): int +{ + a1, a2, rdot, nline, _tl: int; + rv: int; + + nline = 0; + dot = a; + for (;;) { + case f { + APPEND_GETTTY => rv = gettty(); + APPEND_GETSUB => rv = getsub(); + APPEND_GETCOPY => rv = getcopy(); + APPEND_GETFILE => rv = getfile(); + } + if (rv != 0) + break; + if(dol >= nlall) { + nlall += 512; + newzero := array [nlall + 5] of int; + if(newzero == nil) { + error("MEM?"); + rescue(); + } + newzero[0:] = zero; + zero = newzero; + } + _tl = putline(); + nline++; + a1 = ++dol; + a2 = a1+1; + rdot = ++dot; + zero[rdot:] = zero[rdot - 1: a1]; + zero[rdot] = _tl; + } +#debug(sys->sprint("end of append - dot %d\n", dot)); + return nline; +} + +add(i: int) +{ + if(i && (given || dol > 0)) { + addr1--; + addr2--; + } + squeeze(0); + newline(); + append(APPEND_GETTTY, addr2); +} + +bformat, bnum: int; + +browse() +{ + forward, n: int; + + 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 <= 0) + addr1 = 0+1; + } + printcom(); +} + +callunix() +{ + buf: string; + c: int; + + if (sh == nil) + sh = load Sh Sh->PATH; + if (sh == nil) { + putst("can't load shell"); + return; + } + setnoaddr(); + while((c=getchr()) != EOF && c != '\n') + buf[len buf] = c; + sh->system(drawctxt, buf); + if(vflag) + putst("!"); +} + +quit() +{ + if(vflag && fchange && dol!=0) { + fchange = 0; + error(Q); + } + sys->remove(tfname); + exit; +} + +onquit(nil: int) +{ + quit(); +} + +rdelete(ad1, ad2: int) +{ + a1, a2, a3: int; + + a1 = ad1; + a2 = ad2+1; + a3 = dol; + dol -= a2 - a1; + do { + zero[a1++] = zero[a2++]; + } while (a2 <= a3); + a1 = ad1; + if(a1 > dol) + a1 = dol; + dot = a1; + fchange = 1; +} + +gdelete() +{ + a1, a2, a3: int; + + a3 = dol; + for(a1=0; (zero[a1]&8r01)==0; a1++) + if(a1>=a3) + return; + for(a2=a1+1; a2<=a3;) { + if(zero[a2] & 8r01) { + a2++; + dot = a1; + } else + zero[a1++] = zero[a2++]; + } + dol = a1-1; + if(dot > dol) + dot = dol; + fchange = 1; +} + +getline(_tl: int): int +{ + lp, bp: int; + nl: int; + block: array of int; +#debug(sys->sprint("getline %d\n", _tl)); + lp = 0; + (block, bp) = getblock(_tl, Sys->OREAD); + nl = len block - bp; + _tl &= ~(RunesPerBlock - 1); + while(linebuf[lp++] = block[bp++]) { + nl--; + if(nl == 0) { + (block, bp) = getblock(_tl += RunesPerBlock, Sys->OREAD); + nl = len block; + } + } + return 0; +} + +putline(): int +{ + lp, bp: int; + nl, _tl: int; + block: array of int; + fchange = 1; + lp = 0; + _tl = tline; + (block, bp) = getblock(_tl, Sys->OWRITE); + nl = len block - bp; + _tl &= ~(RunesPerBlock-1); # _tl is now at the beginning of the block + while(block[bp] = linebuf[lp++]) { + if(block[bp++] == '\n') { + block[bp-1] = 0; + linebp = lp; + break; + } + nl--; + if(nl == 0) { + _tl += RunesPerBlock; + (block, bp) = getblock(_tl, Sys->OWRITE); + nl = len block; + } + } + nl = tline; + tline += ((lp) + 8r03) & 8r077776; + return nl; +} + +tbuf := array [BLKSIZE] of byte; + +getrune(buf: array of byte): int +{ + return int buf[0] + (int buf[1] << 8); +} + +putrune(buf: array of byte, v: int) +{ + buf[0] = byte (v); + buf[1] = byte (v >> 8); +} + +blkio(b: int, buf: array of int, writefunc: int) +{ + sys->seek(tfile, big b * big BLKSIZE, Sys->SEEKSTART); + if (writefunc) { + # flatten buf into tbuf + for (x := 0; x < RunesPerBlock; x++) + putrune(tbuf[x * BytesPerRune:], buf[x]); + if (sys->write(tfile, tbuf, BLKSIZE) != len tbuf) { + error(T); + } + } + else { + if (sys->read(tfile, tbuf, len tbuf) != len tbuf) { + error(T); + } + for (x := 0; x < RunesPerBlock; x++) + buf[x] = getrune(tbuf[x * BytesPerRune:]); + } +} + +ibuff := array [RunesPerBlock] of int; +obuff := array [RunesPerBlock] of int; + +getblock(atl, iof: int): (array of int, int) +{ + bno, off: int; + + bno = atl / RunesPerBlock; + off = (atl * BytesPerRune) & (BLKSIZE-1) & ~8r03; + if(bno >= NBLK) { + lastc = '\n'; + error(T); + } + off /= BytesPerRune; + if(bno == iblock) { + ichanged |= iof; +#debug(sys->sprint("getblock(%d, %d): returns ibuff offset %d\n", atl, iof, off)); + return (ibuff, off); + } + if(bno == oblock) { +#debug(sys->sprint("getblock(%d, %d): returns obuff offset %d\n", atl, iof, off)); + return (obuff, off); + } + if(iof == Sys->OREAD) { + if(ichanged) + blkio(iblock, ibuff, 1); + ichanged = 0; + iblock = bno; + blkio(bno, ibuff, 0); +#debug(sys->sprint("getblock(%d, %d): returns ibuff offset %d\n", atl, iof, off)); + return (ibuff, off); + } + if(oblock >= 0) + blkio(oblock, obuff, 1); + oblock = bno; +#debug(sys->sprint("getblock(%d, %d): returns offset %d\n", atl, iof, off)); + return (obuff, off); +} + +_init() +{ + markp: int; + + tfile = nil; + tline = RunesPerBlock; + for(markp = 0; markp < len names; markp++) + names[markp] = 0; + subnewa = 0; + anymarks = 0; + iblock = -1; + oblock = -1; + ichanged = 0; + if((tfile = sys->create(tfname, Sys->ORDWR, 8r0600)) == nil){ + error1(T); + exit; + } + dot = dol = 0; +} + +global(k: int) +{ + globuf: string; + c, a1: int; + + if(!globp.isnil) + error(Q); + setwide(); + squeeze(dol > 0); + c = getchr(); + if(c == '\n') + error(Q); + compile(c); + globuf = nil; + while((c=getchr()) != '\n') { + if(c == EOF) + error(Q); + if(c == '\\') { + c = getchr(); + if(c != '\n') + globuf[len globuf] = '\\'; + } + globuf[len globuf] = c; + } + if(globuf == nil) + globuf = "p"; + globuf[len globuf] = '\n'; + for(a1=0; a1<=dol; a1++) { + zero[a1] &= ~8r01; + if(a1 >= addr1 && a1 <= addr2 && match(a1) == k) + zero[a1] |= 8r01; + } + + # + # Special case: g/.../d (avoid n^2 algorithm) + + if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) { + gdelete(); + return; + } + for(a1=0; a1<=dol; a1++) { + if(zero[a1] & 8r01) { + zero[a1] &= ~8r01; + dot = a1; + globp = (globuf, 0); + commands(); + a1 = 0; + } + } +} + +join() +{ + gp, lp: int; + a1: int; + + nonzero(); + gp = 0; + for(a1=addr1; a1<=addr2; a1++) { + lp = getline(zero[a1]); + while(genbuf[gp] = linebuf[lp++]) + if(gp++ >= LBSIZE-2) + error(Q); + } + lp = 0; + gp = 0; + while(linebuf[lp++] = genbuf[gp++]) + ; + zero[addr1] = putline(); + if(addr1 < addr2) + rdelete(addr1+1, addr2); + dot = addr1; +} + +substitute(inglob: int) +{ + mp, a1, nl, gsubf, n: int; + + n = getnum(); # OK even if n==0 + gsubf = compsub(); + for(a1 = addr1; a1 <= addr2; a1++) { + if(match(a1)){ + m := n; + + do { + span := loc2-loc1; + + if(--m <= 0) { + dosub(); + if(!gsubf) + break; + if(span == 0) { # null RE match + if(zero[loc2] == 0) + break; + loc2++; + } + } + } while(match(-1)); + if(m <= 0) { + inglob |= 8r01; + subnewa = putline(); + zero[a1] &= ~8r01; + if(anymarks) { + for(mp=0; mp<len names; mp++) + if(names[mp] == zero[a1]) + names[mp] = subnewa; + } + subolda = zero[a1]; + zero[a1] = subnewa; +#debug(sys->sprint("append-getsub linebp = %d\n", linebp)); + nl = append(APPEND_GETSUB, a1); + addr2 += nl; + } + } + } + if(inglob == 0) + error(Q); +} + +compsub(): int +{ + seof, c: int; + p: int; + + seof = getchr(); + if(seof == '\n' || seof == ' ') + error(Q); + compile(seof); + p = 0; + for(;;) { + c = getchr(); + if(c == '\\') { + c = getchr(); + rhsbuf[p++] = ESCFLG; + if(p >= LBSIZE / 2) + error(Q); + } else + if(c == '\n' && (globp.isnil || globp.s == nil)) { + peekc = c; + pflag++; + break; + } else + if(c == seof) + break; + rhsbuf[p++] = c; + if(p >= LBSIZE / 2) + error(Q); + } + rhsbuf[p] = 0; + peekc = getchr(); + if(peekc == 'g') { + peekc = 0; + newline(); + return 1; + } + newline(); + return 0; +} + +getsub(): int +{ + p1, p2: int; + + p1 = 0; + if((p2 = linebp) == -1) + return EOF; + while(linebuf[p1++] = linebuf[p2++]) + ; + linebp = -1; + return 0; +} + +dosub() +{ + lp, sp, rp: int; + c, n: int; + +# lp = linebuf; +# sp = genbuf; +# rp = rhsbuf; + lp = 0; + sp = 0; + rp = 0; + while(lp < loc1) + genbuf[sp++] = linebuf[lp++]; + while(c = rhsbuf[rp++]) { + if(c == '&'){ + sp = place(sp, loc1, loc2); + continue; + } + if(c == ESCFLG && (c = rhsbuf[rp++]) >= '1' && c < MAXSUB+'0') { + n = c-'0'; + if(subexp != nil && subexp[n].rsp >= 0 && subexp[n].rep >= 0) { + sp = place(sp, subexp[n].rsp, subexp[n].rep); + continue; + } + error(Q); + } + genbuf[sp++] = c; + if(sp >= LBSIZE) + error(Q); + } + lp = loc2; + loc2 = sp; + while(genbuf[sp++] = linebuf[lp++]) + if(sp >= LBSIZE) + error(Q); + linebuf[0:] = genbuf[0: sp]; +} + +place(sp: int, l1: int, l2: int): int +{ + + while(l1 < l2) { + genbuf[sp++] = linebuf[l1++]; + if(sp >= LBSIZE) + error(Q); + } + return sp; +} + +move(cflag: int) +{ + _adt, ad1, ad2: int; + + nonzero(); + if((_adt = address()) < 0) # address() guarantees addr is in range + error(Q); + newline(); + if(cflag) { + ad1 = dol; + append(APPEND_GETCOPY, ad1++); + ad2 = dol; + } else { + ad2 = addr2; + for(ad1 = addr1; ad1 <= ad2;) + zero[ad1++] &= ~8r01; + 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; +} + +reverse(a1, a2: int) +{ + t: int; + + for(;;) { + t = zero[--a2]; + if(a2 <= a1) + return; + zero[a2] = zero[a1]; + zero[a1++] = t; + } +} + +getcopy(): int +{ + if(addr1 > addr2) + return EOF; + getline(zero[addr1++]); + return 0; +} + +compile(eof: int) +{ + c: int; + + if((c = getchr()) == '\n') { + peekc = c; + c = eof; + } + if(c == eof) { + if(pattern == nil) + error(Q); + return; + } + pattern = nil; + program := ""; + do { + + if(c == '\\') { + program[len program] = '\\'; + if((c = getchr()) == '\n') { + error(Q); + return; + } + } + program[len program] = c; + } while((c = getchr()) != eof && c != '\n'); + if(c == '\n') + peekc = c; + diag: string; +#debug("program " + program + "\n"); + (pattern, diag) = regex->compile(program, 1); +#if (diag != nil) +# debug("diag " + diag + "\n"); + if (diag != nil) + pattern = nil; +} + +mkstring(a: array of int): string +{ + s: string; + for (x := 0; x < len a; x++) { + if (a[x] == 0) + break; + s[x] = a[x]; + } + return s; +} + +match(addr: int): int +{ + rsp: int; + if(pattern == nil) + return 0; + if(addr >= 0){ + if(addr == 0) + return 0; + rsp = getline(zero[addr]); + } else + rsp = loc2; + s := mkstring(linebuf); + subexp = regex->executese(pattern, s, (rsp, len s), rsp == 0, 1); + if(subexp != nil) { + (loc1, loc2) = subexp[0]; + return 1; + } + loc1 = loc2 = -1; + return 0; +} + +putd() +{ + r: int; + + r = count%10; + count /= 10; + if(count) + putd(); + putchr(r + '0'); +} + +putst(s: string) +{ + col = 0; + for(x := 0; x < len s; x++) + putchr(s[x]); + putchr('\n'); +} + +putshst(sp: int) +{ + col = 0; + while(linebuf[sp]) { + putchr(linebuf[sp++]); + } + putchr('\n'); +} + +putchr(ac: int) +{ + lp: int; + c: int; + rune: int; + lp = linp; + c = ac; + if(listf) { + if(c == '\n') { + if(linp != 0 && line[linp - 1] == byte ' ') { + line[lp++] = byte '\\'; + line[lp++] = byte 'n'; + } + } else { + if(col > (72-6-2)) { + col = 8; + line[lp++] = byte '\\'; + line[lp++] = byte '\n'; + line[lp++] = byte '\t'; + } + col++; + if(c=='\b' || c=='\t' || c=='\\') { + line[lp++] = byte '\\'; + if(c == '\b') + c = 'b'; + else + if(c == '\t') + c = 't'; + col++; + } else + if(c<' ' || c>=8r0177) { + line[lp++] = byte '\\'; + line[lp++] = byte 'x'; + line[lp++] = byte hex[c>>12]; + line[lp++] = byte hex[c>>8&16rF]; + line[lp++] = byte hex[c>>4&16rF]; + c = hex[c&16rF]; + col += 5; + } + } + } + + rune = c; + lp += sys->char2byte(rune, line, lp); + + if(c == '\n' || lp >= len line - 5) { + linp = 0; + if (oflag) + sys->write(sys->fildes(2), line, lp); + else + sys->write(sys->fildes(1), line, lp); + return; + } + linp = lp; +} + +stringfromint(i: int): string +{ + s: string; + s[0] = i; + return s; +} + +mktemp(as: string): string +{ + pid: int; + s: string; + + s = nil; + pid = sys->pctl(0, nil); + for (x := len as - 1; x >= 0; x--) + if (as[x] == 'X') { + s = stringfromint('0' + pid % 10) + s; + pid /= 10; + } + else + s = stringfromint(as[x]) + s; + s[len s] = 'a'; + for (;;) { + (rv, nil) := sys->stat(s); + if (rv < 0) + break; + if (s[len s - 1] == 'z') + return "/"; + s[len s - 1]++; + } + return s; +} |
