blob: 79b90e7eb78b2fd07e7d27cf7fae859725b308a6 [file] [log] [blame]
/*
* Editor
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <regexp.h>
#undef EOF /* stdio? */
enum
{
FNSIZE = 128, /* file name */
LBSIZE = 4096, /* max line size */
BLKSIZE = 4096, /* block size in temp file */
NBLK = 8191, /* max size of temp file */
ESIZE = 256, /* max size of reg exp */
GBSIZE = 256, /* max size of global command */
MAXSUB = 9, /* max number of sub reg exp */
ESCFLG = 0xFFFF, /* escape Rune - user defined code */
EOF = -1
};
void (*oldhup)(int);
void (*oldquit)(int);
int* addr1;
int* addr2;
int anymarks;
int col;
long count;
int* dol;
int* dot;
int fchange;
char file[FNSIZE];
Rune genbuf[LBSIZE];
int given;
Rune* globp;
int iblock;
int ichanged;
int io;
Biobuf iobuf;
int lastc;
char line[70];
Rune* linebp;
Rune linebuf[LBSIZE];
int listf;
int listn;
Rune* loc1;
Rune* loc2;
int names[26];
int nleft;
int oblock;
int oflag;
Reprog *pattern;
int peekc;
int pflag;
int rescuing;
Rune rhsbuf[LBSIZE/sizeof(Rune)];
char savedfile[FNSIZE];
jmp_buf savej;
int subnewa;
int subolda;
Resub subexp[MAXSUB];
char* tfname;
int tline;
int waiting;
int wrapp;
int* zero;
char Q[] = "";
char T[] = "TMP";
char WRERR[] = "WRITE ERROR";
int bpagesize = 20;
char hex[] = "0123456789abcdef";
char* linp = line;
ulong nlall = 128;
int tfile = -1;
int vflag = 1;
void add(int);
int* address(void);
int append(int(*)(void), int*);
void browse(void);
void callunix(void);
void commands(void);
void compile(int);
int compsub(void);
void dosub(void);
void error(char*);
int match(int*);
void exfile(int);
void filename(int);
Rune* getblock(int, int);
int getchr(void);
int getcopy(void);
int getfile(void);
Rune* getline(int);
int getnum(void);
int getsub(void);
int gettty(void);
void global(int);
void init(void);
void join(void);
void move(int);
void newline(void);
void nonzero(void);
void notifyf(void*, char*);
Rune* place(Rune*, Rune*, Rune*);
void printcom(void);
void putchr(int);
void putd(void);
void putfile(void);
int putline(void);
void putshst(Rune*);
void putst(char*);
void quit(void);
void rdelete(int*, int*);
void regerror(char *);
void reverse(int*, int*);
void setnoaddr(void);
void setwide(void);
void squeeze(int);
void substitute(int);
Rune La[] = { 'a', 0 };
Rune Lr[] = { 'r', 0 };
char tmp[] = "/var/tmp/eXXXXX";
void
main(int argc, char *argv[])
{
char *p1, *p2;
notify(notifyf);
ARGBEGIN {
case 'o':
oflag = 1;
vflag = 0;
break;
} ARGEND
USED(argc);
if(*argv && (strcmp(*argv, "-") == 0)) {
argv++;
vflag = 0;
}
if(oflag) {
p1 = "/dev/stdout";
p2 = savedfile;
while(*p2++ = *p1++)
;
globp = La;
} else
if(*argv) {
p1 = *argv;
p2 = savedfile;
while(*p2++ = *p1++)
if(p2 >= &savedfile[sizeof(savedfile)])
p2--;
globp = Lr;
}
zero = malloc((nlall+5)*sizeof(int*));
tfname = mktemp(tmp);
init();
setjmp(savej);
commands();
quit();
}
void
commands(void)
{
int *a1, c, temp;
char lastsep;
Dir *d;
for(;;) {
if(pflag) {
pflag = 0;
addr1 = addr2 = dot;
printcom();
}
c = '\n';
for(addr1 = 0;;) {
lastsep = c;
a1 = address();
c = getchr();
if(c != ',' && c != ';')
break;
if(lastsep == ',')
error(Q);
if(a1 == 0) {
a1 = zero+1;
if(a1 > dol)
a1--;
}
addr1 = a1;
if(c == ';')
dot = a1;
}
if(lastsep != '\n' && a1 == 0)
a1 = dol;
if((addr2=a1) == 0) {
given = 0;
addr2 = dot;
} else
given = 1;
if(addr1 == 0)
addr1 = addr2;
switch(c) {
case 'a':
add(0);
continue;
case 'b':
nonzero();
browse();
continue;
case 'c':
nonzero();
newline();
rdelete(addr1, addr2);
append(gettty, addr1-1);
continue;
case 'd':
nonzero();
newline();
rdelete(addr1, addr2);
continue;
case 'E':
fchange = 0;
c = 'e';
case 'e':
setnoaddr();
if(vflag && fchange) {
fchange = 0;
error(Q);
}
filename(c);
init();
addr2 = zero;
goto caseread;
case 'f':
setnoaddr();
filename(c);
putst(savedfile);
continue;
case 'g':
global(1);
continue;
case 'i':
add(-1);
continue;
case 'j':
if(!given)
addr2++;
newline();
join();
continue;
case 'k':
nonzero();
c = getchr();
if(c < 'a' || c > 'z')
error(Q);
newline();
names[c-'a'] = *addr2 & ~01;
anymarks |= 01;
continue;
case 'm':
move(0);
continue;
case 'n':
listn++;
newline();
printcom();
continue;
case '\n':
if(a1==0) {
a1 = dot+1;
addr2 = a1;
addr1 = a1;
}
if(lastsep==';')
addr1 = a1;
printcom();
continue;
case 'l':
listf++;
case 'p':
case 'P':
newline();
printcom();
continue;
case 'Q':
fchange = 0;
case 'q':
setnoaddr();
newline();
quit();
case 'r':
filename(c);
caseread:
if((io=open(file, OREAD)) < 0) {
lastc = '\n';
error(file);
}
if((d = dirfstat(io)) != nil){
if(d->mode & DMAPPEND)
print("warning: %s is append only\n", file);
free(d);
}
Binit(&iobuf, io, OREAD);
setwide();
squeeze(0);
c = zero != dol;
append(getfile, addr2);
exfile(OREAD);
fchange = c;
continue;
case 's':
nonzero();
substitute(globp != 0);
continue;
case 't':
move(1);
continue;
case 'u':
nonzero();
newline();
if((*addr2&~01) != subnewa)
error(Q);
*addr2 = subolda;
dot = addr2;
continue;
case 'v':
global(0);
continue;
case 'W':
wrapp++;
case 'w':
setwide();
squeeze(dol>zero);
temp = getchr();
if(temp != 'q' && temp != 'Q') {
peekc = temp;
temp = 0;
}
filename(c);
if(!wrapp ||
((io = open(file, OWRITE)) == -1) ||
((seek(io, 0L, 2)) == -1))
if((io = create(file, OWRITE, 0666)) < 0)
error(file);
Binit(&iobuf, io, OWRITE);
wrapp = 0;
if(dol > zero)
putfile();
exfile(OWRITE);
if(addr1<=zero+1 && addr2==dol)
fchange = 0;
if(temp == 'Q')
fchange = 0;
if(temp)
quit();
continue;
case '=':
setwide();
squeeze(0);
newline();
count = addr2 - zero;
putd();
putchr('\n');
continue;
case '!':
callunix();
continue;
case EOF:
return;
}
error(Q);
}
}
void
printcom(void)
{
int *a1;
nonzero();
a1 = addr1;
do {
if(listn) {
count = a1-zero;
putd();
putchr('\t');
}
putshst(getline(*a1++));
} while(a1 <= addr2);
dot = addr2;
listf = 0;
listn = 0;
pflag = 0;
}
int*
address(void)
{
int sign, *a, opcnt, nextopand, *b, c;
nextopand = -1;
sign = 1;
opcnt = 0;
a = dot;
do {
do {
c = getchr();
} while(c == ' ' || c == '\t');
if(c >= '0' && c <= '9') {
peekc = c;
if(!opcnt)
a = zero;
a += sign*getnum();
} else
switch(c) {
case '$':
a = dol;
case '.':
if(opcnt)
error(Q);
break;
case '\'':
c = getchr();
if(opcnt || c < 'a' || c > 'z')
error(Q);
a = zero;
do {
a++;
} while(a <= dol && names[c-'a'] != (*a & ~01));
break;
case '?':
sign = -sign;
case '/':
compile(c);
b = a;
for(;;) {
a += sign;
if(a <= zero)
a = dol;
if(a > dol)
a = zero;
if(match(a))
break;
if(a == b)
error(Q);
}
break;
default:
if(nextopand == opcnt) {
a += sign;
if(a < zero || dol < a)
continue; /* error(Q); */
}
if(c != '+' && c != '-' && c != '^') {
peekc = c;
if(opcnt == 0)
a = 0;
return a;
}
sign = 1;
if(c != '+')
sign = -sign;
nextopand = ++opcnt;
continue;
}
sign = 1;
opcnt++;
} while(zero <= a && a <= dol);
error(Q);
return 0;
}
int
getnum(void)
{
int r, c;
r = 0;
for(;;) {
c = getchr();
if(c < '0' || c > '9')
break;
r = r*10 + (c-'0');
}
peekc = c;
return r;
}
void
setwide(void)
{
if(!given) {
addr1 = zero + (dol>zero);
addr2 = dol;
}
}
void
setnoaddr(void)
{
if(given)
error(Q);
}
void
nonzero(void)
{
squeeze(1);
}
void
squeeze(int i)
{
if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
error(Q);
}
void
newline(void)
{
int c;
c = getchr();
if(c == '\n' || c == EOF)
return;
if(c == 'p' || c == 'l' || c == 'n') {
pflag++;
if(c == 'l')
listf++;
else
if(c == 'n')
listn++;
c = getchr();
if(c == '\n')
return;
}
error(Q);
}
void
filename(int comm)
{
char *p1, *p2;
Rune rune;
int c;
count = 0;
c = getchr();
if(c == '\n' || c == EOF) {
p1 = savedfile;
if(*p1 == 0 && comm != 'f')
error(Q);
p2 = file;
while(*p2++ = *p1++)
;
return;
}
if(c != ' ')
error(Q);
while((c=getchr()) == ' ')
;
if(c == '\n')
error(Q);
p1 = file;
do {
if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
error(Q);
rune = c;
p1 += runetochar(p1, &rune);
} while((c=getchr()) != '\n');
*p1 = 0;
if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
p1 = savedfile;
p2 = file;
while(*p1++ = *p2++)
;
}
}
void
exfile(int om)
{
if(om == OWRITE)
if(Bflush(&iobuf) < 0)
error(Q);
close(io);
io = -1;
if(vflag) {
putd();
putchr('\n');
}
}
void
error1(char *s)
{
int c;
wrapp = 0;
listf = 0;
listn = 0;
count = 0;
seek(0, 0, 2);
pflag = 0;
if(globp)
lastc = '\n';
globp = 0;
peekc = lastc;
if(lastc)
for(;;) {
c = getchr();
if(c == '\n' || c == EOF)
break;
}
if(io > 0) {
close(io);
io = -1;
}
putchr('?');
putst(s);
}
void
error(char *s)
{
error1(s);
longjmp(savej, 1);
}
void
rescue(void)
{
rescuing = 1;
if(dol > zero) {
addr1 = zero+1;
addr2 = dol;
io = create("ed.hup", OWRITE, 0666);
if(io > 0){
Binit(&iobuf, io, OWRITE);
putfile();
}
}
fchange = 0;
quit();
}
void
notifyf(void *a, char *s)
{
if(strcmp(s, "interrupt") == 0){
if(rescuing || waiting)
noted(NCONT);
putchr('\n');
lastc = '\n';
error1(Q);
notejmp(a, savej, 0);
}
if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){
if(rescuing)
noted(NDFLT);
rescue();
}
if(strstr(s, "child"))
noted(NCONT);
fprint(2, "ed: note: %s\n", s);
abort();
}
int
getchr(void)
{
char s[UTFmax];
int i;
Rune r;
if(lastc = peekc) {
peekc = 0;
return lastc;
}
if(globp) {
if((lastc=*globp++) != 0)
return lastc;
globp = 0;
return EOF;
}
for(i=0;;) {
if(read(0, s+i, 1) <= 0)
return lastc = EOF;
i++;
if(fullrune(s, i))
break;
}
chartorune(&r, s);
lastc = r;
return lastc;
}
int
gety(void)
{
int c;
Rune *gf, *p;
p = linebuf;
gf = globp;
for(;;) {
c = getchr();
if(c == '\n') {
*p = 0;
return 0;
}
if(c == EOF) {
if(gf)
peekc = c;
return c;
}
if(c == 0)
continue;
*p++ = c;
if(p >= &linebuf[LBSIZE-2])
error(Q);
}
}
int
gettty(void)
{
int rc;
rc = gety();
if(rc)
return rc;
if(linebuf[0] == '.' && linebuf[1] == 0)
return EOF;
return 0;
}
int
getfile(void)
{
int c;
Rune *lp;
lp = linebuf;
do {
c = Bgetrune(&iobuf);
if(c < 0) {
if(lp > linebuf) {
putst("'\\n' appended");
c = '\n';
} else
return EOF;
}
if(lp >= &linebuf[LBSIZE]) {
lastc = '\n';
error(Q);
}
*lp++ = c;
count++;
} while(c != '\n');
lp[-1] = 0;
return 0;
}
void
putfile(void)
{
int *a1;
Rune *lp;
long c;
a1 = addr1;
do {
lp = getline(*a1++);
for(;;) {
count++;
c = *lp++;
if(c == 0) {
if(Bputrune(&iobuf, '\n') < 0)
error(Q);
break;
}
if(Bputrune(&iobuf, c) < 0)
error(Q);
}
} while(a1 <= addr2);
if(Bflush(&iobuf) < 0)
error(Q);
}
int
append(int (*f)(void), int *a)
{
int *a1, *a2, *rdot, nline, d;
nline = 0;
dot = a;
while((*f)() == 0) {
if((dol-zero) >= nlall) {
nlall += 512;
a1 = realloc(zero, (nlall+50)*sizeof(int*));
if(a1 == 0) {
error("MEM?");
rescue();
}
/* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */
d = addr1 - zero;
addr1 = a1 + d;
d = addr2 - zero;
addr2 = a1 + d;
d = dol - zero;
dol = a1 + d;
d = dot - zero;
dot = a1 + d;
zero = a1;
}
d = putline();
nline++;
a1 = ++dol;
a2 = a1+1;
rdot = ++dot;
while(a1 > rdot)
*--a2 = *--a1;
*rdot = d;
}
return nline;
}
void
add(int i)
{
if(i && (given || dol > zero)) {
addr1--;
addr2--;
}
squeeze(0);
newline();
append(gettty, addr2);
}
void
browse(void)
{
int forward, n;
static int bformat, bnum; /* 0 */
forward = 1;
peekc = getchr();
if(peekc != '\n'){
if(peekc == '-' || peekc == '+') {
if(peekc == '-')
forward = 0;
getchr();
}
n = getnum();
if(n > 0)
bpagesize = n;
}
newline();
if(pflag) {
bformat = listf;
bnum = listn;
} else {
listf = bformat;
listn = bnum;
}
if(forward) {
addr1 = addr2;
addr2 += bpagesize;
if(addr2 > dol)
addr2 = dol;
} else {
addr1 = addr2-bpagesize;
if(addr1 <= zero)
addr1 = zero+1;
}
printcom();
}
void
callunix(void)
{
int c, pid;
Rune rune;
char buf[512];
char *p;
setnoaddr();
p = buf;
while((c=getchr()) != EOF && c != '\n')
if(p < &buf[sizeof(buf) - 6]) {
rune = c;
p += runetochar(p, &rune);
}
*p = 0;
pid = fork();
if(pid == 0) {
execlp("rc", "rc", "-c", buf, (char*)0);
sysfatal("exec failed: %r");
exits("execl failed");
}
waiting = 1;
while(waitpid() != pid)
;
waiting = 0;
if(vflag)
putst("!");
}
void
quit(void)
{
if(vflag && fchange && dol!=zero) {
fchange = 0;
error(Q);
}
remove(tfname);
exits(0);
}
void
onquit(int sig)
{
USED(sig);
quit();
}
void
rdelete(int *ad1, int *ad2)
{
int *a1, *a2, *a3;
a1 = ad1;
a2 = ad2+1;
a3 = dol;
dol -= a2 - a1;
do {
*a1++ = *a2++;
} while(a2 <= a3);
a1 = ad1;
if(a1 > dol)
a1 = dol;
dot = a1;
fchange = 1;
}
void
gdelete(void)
{
int *a1, *a2, *a3;
a3 = dol;
for(a1=zero; (*a1&01)==0; a1++)
if(a1>=a3)
return;
for(a2=a1+1; a2<=a3;) {
if(*a2 & 01) {
a2++;
dot = a1;
} else
*a1++ = *a2++;
}
dol = a1-1;
if(dot > dol)
dot = dol;
fchange = 1;
}
Rune*
getline(int tl)
{
Rune *lp, *bp;
int nl;
lp = linebuf;
bp = getblock(tl, OREAD);
nl = nleft;
tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
while(*lp++ = *bp++) {
nl -= sizeof(Rune);
if(nl == 0) {
bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);
nl = nleft;
}
}
return linebuf;
}
int
putline(void)
{
Rune *lp, *bp;
int nl, tl;
fchange = 1;
lp = linebuf;
tl = tline;
bp = getblock(tl, OWRITE);
nl = nleft;
tl &= ~((BLKSIZE/sizeof(Rune))-1);
while(*bp = *lp++) {
if(*bp++ == '\n') {
bp[-1] = 0;
linebp = lp;
break;
}
nl -= sizeof(Rune);
if(nl == 0) {
tl += BLKSIZE/sizeof(Rune);
bp = getblock(tl, OWRITE);
nl = nleft;
}
}
nl = tline;
tline += ((lp-linebuf) + 03) & 077776;
return nl;
}
void
blkio(int b, uchar *buf, int isread)
{
int n;
seek(tfile, b*BLKSIZE, 0);
if(isread)
n = read(tfile, buf, BLKSIZE);
else
n = write(tfile, buf, BLKSIZE);
if(n != BLKSIZE)
error(T);
}
Rune*
getblock(int atl, int iof)
{
int bno, off;
static uchar ibuff[BLKSIZE];
static uchar obuff[BLKSIZE];
bno = atl / (BLKSIZE/sizeof(Rune));
off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;
if(bno >= NBLK) {
lastc = '\n';
error(T);
}
nleft = BLKSIZE - off;
if(bno == iblock) {
ichanged |= iof;
return (Rune*)(ibuff+off);
}
if(bno == oblock)
return (Rune*)(obuff+off);
if(iof == OREAD) {
if(ichanged)
blkio(iblock, ibuff, 0);
ichanged = 0;
iblock = bno;
blkio(bno, ibuff, 1);
return (Rune*)(ibuff+off);
}
if(oblock >= 0)
blkio(oblock, obuff, 0);
oblock = bno;
return (Rune*)(obuff+off);
}
void
init(void)
{
int *markp;
close(tfile);
tline = 2;
for(markp = names; markp < &names[26]; )
*markp++ = 0;
subnewa = 0;
anymarks = 0;
iblock = -1;
oblock = -1;
ichanged = 0;
if((tfile = create(tfname, ORDWR, 0600)) < 0){
error1(T);
exits(0);
}
dot = dol = zero;
}
void
global(int k)
{
Rune *gp, globuf[GBSIZE];
int c, *a1;
if(globp)
error(Q);
setwide();
squeeze(dol > zero);
c = getchr();
if(c == '\n')
error(Q);
compile(c);
gp = globuf;
while((c=getchr()) != '\n') {
if(c == EOF)
error(Q);
if(c == '\\') {
c = getchr();
if(c != '\n')
*gp++ = '\\';
}
*gp++ = c;
if(gp >= &globuf[GBSIZE-2])
error(Q);
}
if(gp == globuf)
*gp++ = 'p';
*gp++ = '\n';
*gp = 0;
for(a1=zero; a1<=dol; a1++) {
*a1 &= ~01;
if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
*a1 |= 01;
}
/*
* Special case: g/.../d (avoid n^2 algorithm)
*/
if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
gdelete();
return;
}
for(a1=zero; a1<=dol; a1++) {
if(*a1 & 01) {
*a1 &= ~01;
dot = a1;
globp = globuf;
commands();
a1 = zero;
}
}
}
void
join(void)
{
Rune *gp, *lp;
int *a1;
nonzero();
gp = genbuf;
for(a1=addr1; a1<=addr2; a1++) {
lp = getline(*a1);
while(*gp = *lp++)
if(gp++ >= &genbuf[LBSIZE-2])
error(Q);
}
lp = linebuf;
gp = genbuf;
while(*lp++ = *gp++)
;
*addr1 = putline();
if(addr1 < addr2)
rdelete(addr1+1, addr2);
dot = addr1;
}
void
substitute(int inglob)
{
int *mp, *a1, nl, gsubf, n;
n = getnum(); /* OK even if n==0 */
gsubf = compsub();
for(a1 = addr1; a1 <= addr2; a1++) {
if(match(a1)){
int *ozero;
int m = n;
do {
int span = loc2-loc1;
if(--m <= 0) {
dosub();
if(!gsubf)
break;
if(span == 0) { /* null RE match */
if(*loc2 == 0)
break;
loc2++;
}
}
} while(match(0));
if(m <= 0) {
inglob |= 01;
subnewa = putline();
*a1 &= ~01;
if(anymarks) {
for(mp=names; mp<&names[26]; mp++)
if(*mp == *a1)
*mp = subnewa;
}
subolda = *a1;
*a1 = subnewa;
ozero = zero;
nl = append(getsub, a1);
addr2 += nl;
nl += zero-ozero;
a1 += nl;
}
}
}
if(inglob == 0)
error(Q);
}
int
compsub(void)
{
int seof, c;
Rune *p;
seof = getchr();
if(seof == '\n' || seof == ' ')
error(Q);
compile(seof);
p = rhsbuf;
for(;;) {
c = getchr();
if(c == '\\') {
c = getchr();
*p++ = ESCFLG;
if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
error(Q);
} else
if(c == '\n' && (!globp || !globp[0])) {
peekc = c;
pflag++;
break;
} else
if(c == seof)
break;
*p++ = c;
if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
error(Q);
}
*p = 0;
peekc = getchr();
if(peekc == 'g') {
peekc = 0;
newline();
return 1;
}
newline();
return 0;
}
int
getsub(void)
{
Rune *p1, *p2;
p1 = linebuf;
if((p2 = linebp) == 0)
return EOF;
while(*p1++ = *p2++)
;
linebp = 0;
return 0;
}
void
dosub(void)
{
Rune *lp, *sp, *rp;
int c, n;
lp = linebuf;
sp = genbuf;
rp = rhsbuf;
while(lp < loc1)
*sp++ = *lp++;
while(c = *rp++) {
if(c == '&'){
sp = place(sp, loc1, loc2);
continue;
}
if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
n = c-'0';
if(subexp[n].s.rsp && subexp[n].e.rep) {
sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);
continue;
}
error(Q);
}
*sp++ = c;
if(sp >= &genbuf[LBSIZE])
error(Q);
}
lp = loc2;
loc2 = sp - genbuf + linebuf;
while(*sp++ = *lp++)
if(sp >= &genbuf[LBSIZE])
error(Q);
lp = linebuf;
sp = genbuf;
while(*lp++ = *sp++)
;
}
Rune*
place(Rune *sp, Rune *l1, Rune *l2)
{
while(l1 < l2) {
*sp++ = *l1++;
if(sp >= &genbuf[LBSIZE])
error(Q);
}
return sp;
}
void
move(int cflag)
{
int *adt, *ad1, *ad2;
nonzero();
if((adt = address())==0) /* address() guarantees addr is in range */
error(Q);
newline();
if(cflag) {
int *ozero, delta;
ad1 = dol;
ozero = zero;
append(getcopy, ad1++);
ad2 = dol;
delta = zero - ozero;
ad1 += delta;
adt += delta;
} else {
ad2 = addr2;
for(ad1 = addr1; ad1 <= ad2;)
*ad1++ &= ~01;
ad1 = addr1;
}
ad2++;
if(adt<ad1) {
dot = adt + (ad2-ad1);
if((++adt)==ad1)
return;
reverse(adt, ad1);
reverse(ad1, ad2);
reverse(adt, ad2);
} else
if(adt >= ad2) {
dot = adt++;
reverse(ad1, ad2);
reverse(ad2, adt);
reverse(ad1, adt);
} else
error(Q);
fchange = 1;
}
void
reverse(int *a1, int *a2)
{
int t;
for(;;) {
t = *--a2;
if(a2 <= a1)
return;
*a2 = *a1;
*a1++ = t;
}
}
int
getcopy(void)
{
if(addr1 > addr2)
return EOF;
getline(*addr1++);
return 0;
}
void
compile(int eof)
{
Rune c;
char *ep;
char expbuf[ESIZE];
if((c = getchr()) == '\n') {
peekc = c;
c = eof;
}
if(c == eof) {
if(!pattern)
error(Q);
return;
}
if(pattern) {
free(pattern);
pattern = 0;
}
ep = expbuf;
do {
if(c == '\\') {
if(ep >= expbuf+sizeof(expbuf)) {
error(Q);
return;
}
ep += runetochar(ep, &c);
if((c = getchr()) == '\n') {
error(Q);
return;
}
}
if(ep >= expbuf+sizeof(expbuf)) {
error(Q);
return;
}
ep += runetochar(ep, &c);
} while((c = getchr()) != eof && c != '\n');
if(c == '\n')
peekc = c;
*ep = 0;
pattern = regcomp(expbuf);
}
int
match(int *addr)
{
if(!pattern)
return 0;
if(addr){
if(addr == zero)
return 0;
subexp[0].s.rsp = getline(*addr);
} else
subexp[0].s.rsp = loc2;
subexp[0].e.rep = 0;
if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
loc1 = subexp[0].s.rsp;
loc2 = subexp[0].e.rep;
return 1;
}
loc1 = loc2 = 0;
return 0;
}
void
putd(void)
{
int r;
r = count%10;
count /= 10;
if(count)
putd();
putchr(r + '0');
}
void
putst(char *sp)
{
Rune r;
col = 0;
for(;;) {
sp += chartorune(&r, sp);
if(r == 0)
break;
putchr(r);
}
putchr('\n');
}
void
putshst(Rune *sp)
{
col = 0;
while(*sp)
putchr(*sp++);
putchr('\n');
}
void
putchr(int ac)
{
char *lp;
int c;
Rune rune;
lp = linp;
c = ac;
if(listf) {
if(c == '\n') {
if(linp != line && linp[-1] == ' ') {
*lp++ = '\\';
*lp++ = 'n';
}
} else {
if(col > (72-6-2)) {
col = 8;
*lp++ = '\\';
*lp++ = '\n';
*lp++ = '\t';
}
col++;
if(c=='\b' || c=='\t' || c=='\\') {
*lp++ = '\\';
if(c == '\b')
c = 'b';
else
if(c == '\t')
c = 't';
col++;
} else
if(c<' ' || c>='\177') {
*lp++ = '\\';
*lp++ = 'x';
*lp++ = hex[c>>12];
*lp++ = hex[c>>8&0xF];
*lp++ = hex[c>>4&0xF];
c = hex[c&0xF];
col += 5;
}
}
}
rune = c;
lp += runetochar(lp, &rune);
if(c == '\n' || lp >= &line[sizeof(line)-5]) {
linp = line;
write(oflag? 2: 1, line, lp-line);
return;
}
linp = lp;
}
char*
mktemp(char *as)
{
char *s;
unsigned pid;
int i;
pid = getpid();
s = as;
while(*s++)
;
s--;
while(*--s == 'X') {
*s = pid % 10 + '0';
pid /= 10;
}
s++;
i = 'a';
while(access(as, 0) != -1) {
if(i == 'z')
return "/";
*s = i++;
}
return as;
}
void
regerror(char *s)
{
USED(s);
error(Q);
}