2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Editor
|
|
|
|
*/
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
#include <lib9.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
#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 = Runemax, /* escape Rune - user defined code */
|
|
|
|
EOF = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
void (*oldhup)(int);
|
|
|
|
void (*oldquit)(int);
|
|
|
|
int* addr1;
|
|
|
|
int* addr2;
|
|
|
|
int anymarks;
|
|
|
|
Biobuf bcons;
|
|
|
|
int col;
|
|
|
|
int32_t 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;
|
|
|
|
uint32_t 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 *c, 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);
|
|
|
|
|
|
|
|
static Rune la;
|
|
|
|
static Rune lr;
|
|
|
|
|
|
|
|
#undef read
|
|
|
|
extern int read(int, void*, int);
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char *p1, *p2;
|
|
|
|
|
|
|
|
chartorune(&la, "a");
|
|
|
|
chartorune(&lr, "r");
|
|
|
|
Binit(&bcons, 0, OREAD);
|
|
|
|
notify(notifyf);
|
|
|
|
ARGBEGIN {
|
|
|
|
case 'o':
|
|
|
|
oflag = 1;
|
|
|
|
vflag = 0;
|
|
|
|
break;
|
|
|
|
} ARGEND
|
|
|
|
USED(argc);
|
|
|
|
if(*argv && (strcmp(*argv, "-") == 0)) {
|
|
|
|
argv++;
|
|
|
|
vflag = 0;
|
|
|
|
}
|
|
|
|
if(oflag) {
|
|
|
|
p1 = "/fd/1";
|
|
|
|
p2 = savedfile;
|
|
|
|
while(*p2++ = *p1++)
|
|
|
|
;
|
|
|
|
globp = &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/eXXXXX");
|
|
|
|
init();
|
|
|
|
setjmp(savej);
|
|
|
|
commands();
|
|
|
|
quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
commands(void)
|
|
|
|
{
|
|
|
|
int *a1, c, temp;
|
|
|
|
char lastsep;
|
|
|
|
Dir *d;
|
|
|
|
for(;;) {
|
|
|
|
if(pflag) {
|
|
|
|
pflag = 0;
|
|
|
|
addr1 = addr2 = dot;
|
|
|
|
printcom();
|
|
|
|
}
|
|
|
|
c = '\n';
|
|
|
|
for(addr1 = 0;;) {
|
|
|
|
lastsep = c;
|
|
|
|
a1 = address();
|
|
|
|
c = getchr();
|
|
|
|
if(c != ',' && c != ';')
|
|
|
|
break;
|
|
|
|
if(lastsep == ',')
|
|
|
|
error(Q);
|
|
|
|
if(a1 == 0) {
|
|
|
|
a1 = zero+1;
|
|
|
|
if(a1 > dol)
|
|
|
|
a1--;
|
|
|
|
}
|
|
|
|
addr1 = a1;
|
|
|
|
if(c == ';')
|
|
|
|
dot = a1;
|
|
|
|
}
|
|
|
|
if(lastsep != '\n' && a1 == 0)
|
|
|
|
a1 = dol;
|
|
|
|
if((addr2=a1) == 0) {
|
|
|
|
given = 0;
|
|
|
|
addr2 = dot;
|
|
|
|
} else
|
|
|
|
given = 1;
|
|
|
|
if(addr1 == 0)
|
|
|
|
addr1 = addr2;
|
|
|
|
switch(c) {
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
add(0);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
nonzero();
|
|
|
|
browse();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
nonzero();
|
|
|
|
newline();
|
|
|
|
rdelete(addr1, addr2);
|
|
|
|
append(gettty, addr1-1);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
nonzero();
|
|
|
|
newline();
|
|
|
|
rdelete(addr1, addr2);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'E':
|
|
|
|
fchange = 0;
|
|
|
|
c = 'e';
|
|
|
|
case 'e':
|
|
|
|
setnoaddr();
|
|
|
|
if(vflag && fchange) {
|
|
|
|
fchange = 0;
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
filename(c);
|
|
|
|
init();
|
|
|
|
addr2 = zero;
|
|
|
|
goto caseread;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
setnoaddr();
|
|
|
|
filename(c);
|
|
|
|
putst(savedfile);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'g':
|
|
|
|
global(1);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'i':
|
|
|
|
add(-1);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
case 'j':
|
|
|
|
if(!given)
|
|
|
|
addr2++;
|
|
|
|
newline();
|
|
|
|
join();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'k':
|
|
|
|
nonzero();
|
|
|
|
c = getchr();
|
|
|
|
if(c < 'a' || c > 'z')
|
|
|
|
error(Q);
|
|
|
|
newline();
|
|
|
|
names[c-'a'] = *addr2 & ~01;
|
|
|
|
anymarks |= 01;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'm':
|
|
|
|
move(0);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
listn++;
|
|
|
|
newline();
|
|
|
|
printcom();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
if(a1==0) {
|
|
|
|
a1 = dot+1;
|
|
|
|
addr2 = a1;
|
|
|
|
addr1 = a1;
|
|
|
|
}
|
|
|
|
if(lastsep==';')
|
|
|
|
addr1 = a1;
|
|
|
|
printcom();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
listf++;
|
|
|
|
case 'p':
|
|
|
|
case 'P':
|
|
|
|
newline();
|
|
|
|
printcom();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'Q':
|
|
|
|
fchange = 0;
|
|
|
|
case 'q':
|
|
|
|
setnoaddr();
|
|
|
|
newline();
|
|
|
|
quit();
|
|
|
|
|
|
|
|
case 'r':
|
|
|
|
filename(c);
|
|
|
|
caseread:
|
|
|
|
if((io=open(file, OREAD)) < 0) {
|
|
|
|
lastc = '\n';
|
|
|
|
error(file);
|
|
|
|
}
|
|
|
|
if((d = dirfstat(io)) != nil){
|
|
|
|
if(d->mode & DMAPPEND)
|
|
|
|
print("warning: %s is append only\n", file);
|
|
|
|
free(d);
|
|
|
|
}
|
|
|
|
Binit(&iobuf, io, OREAD);
|
|
|
|
setwide();
|
|
|
|
squeeze(0);
|
|
|
|
c = zero != dol;
|
|
|
|
append(getfile, addr2);
|
|
|
|
exfile(OREAD);
|
|
|
|
|
|
|
|
fchange = c;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
nonzero();
|
|
|
|
substitute(globp != 0);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
move(1);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
nonzero();
|
|
|
|
newline();
|
|
|
|
if((*addr2&~01) != subnewa)
|
|
|
|
error(Q);
|
|
|
|
*addr2 = subolda;
|
|
|
|
dot = addr2;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'v':
|
|
|
|
global(0);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'W':
|
|
|
|
wrapp++;
|
|
|
|
case 'w':
|
|
|
|
setwide();
|
|
|
|
squeeze(dol>zero);
|
|
|
|
temp = getchr();
|
|
|
|
if(temp != 'q' && temp != 'Q') {
|
|
|
|
peekc = temp;
|
|
|
|
temp = 0;
|
|
|
|
}
|
|
|
|
filename(c);
|
|
|
|
if(!wrapp ||
|
|
|
|
((io = open(file, OWRITE)) == -1) ||
|
|
|
|
((seek(io, 0L, 2)) == -1))
|
2016-12-24 21:25:20 +01:00
|
|
|
if((io = ocreate(file, OWRITE, 0666)) < 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
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;
|
2016-12-24 21:25:20 +01:00
|
|
|
io = ocreate("ed.hup", OWRITE, 0666);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(io > 0){
|
|
|
|
Binit(&iobuf, io, OWRITE);
|
|
|
|
putfile();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fchange = 0;
|
|
|
|
quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
notifyf(void *a, char *s)
|
|
|
|
{
|
|
|
|
if(strcmp(s, "interrupt") == 0){
|
|
|
|
if(rescuing || waiting)
|
|
|
|
noted(NCONT);
|
|
|
|
putchr(L'\n');
|
|
|
|
lastc = '\n';
|
|
|
|
error1(Q);
|
|
|
|
notejmp(a, savej, 0);
|
|
|
|
}
|
|
|
|
if(strcmp(s, "hangup") == 0){
|
|
|
|
if(rescuing)
|
|
|
|
noted(NDFLT);
|
|
|
|
rescue();
|
|
|
|
}
|
|
|
|
fprint(2, "ed: note: %s\n", s);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getchr(void)
|
|
|
|
{
|
|
|
|
if(lastc = peekc) {
|
|
|
|
peekc = 0;
|
|
|
|
return lastc;
|
|
|
|
}
|
|
|
|
if(globp) {
|
|
|
|
if((lastc=*globp++) != 0)
|
|
|
|
return lastc;
|
|
|
|
globp = 0;
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
lastc = Bgetrune(&bcons);
|
|
|
|
return lastc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gety(void)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
Rune *gf, *p;
|
|
|
|
|
|
|
|
p = linebuf;
|
|
|
|
gf = globp;
|
|
|
|
for(;;) {
|
|
|
|
c = getchr();
|
|
|
|
if(c == '\n') {
|
|
|
|
*p = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(c == EOF) {
|
|
|
|
if(gf)
|
|
|
|
peekc = c;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
if(c == 0)
|
|
|
|
continue;
|
|
|
|
*p++ = c;
|
|
|
|
if(p >= &linebuf[LBSIZE-sizeof(Rune)])
|
|
|
|
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;
|
|
|
|
int32_t 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("/cmd/rc", "rc", "-c", buf, nil);
|
|
|
|
exits("execl failed");
|
|
|
|
}
|
|
|
|
waiting = 1;
|
|
|
|
while(waitpid() != pid)
|
|
|
|
;
|
|
|
|
waiting = 0;
|
|
|
|
if(vflag)
|
|
|
|
putst("!");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
quit(void)
|
|
|
|
{
|
|
|
|
if(vflag && fchange && dol!=zero) {
|
|
|
|
fchange = 0;
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
remove(tfname);
|
|
|
|
exits(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
onquit(int sig)
|
|
|
|
{
|
|
|
|
USED(sig);
|
|
|
|
quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rdelete(int *ad1, int *ad2)
|
|
|
|
{
|
|
|
|
int *a1, *a2, *a3;
|
|
|
|
|
|
|
|
a1 = ad1;
|
|
|
|
a2 = ad2+1;
|
|
|
|
a3 = dol;
|
|
|
|
dol -= a2 - a1;
|
|
|
|
do {
|
|
|
|
*a1++ = *a2++;
|
|
|
|
} while(a2 <= a3);
|
|
|
|
a1 = ad1;
|
|
|
|
if(a1 > dol)
|
|
|
|
a1 = dol;
|
|
|
|
dot = a1;
|
|
|
|
fchange = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gdelete(void)
|
|
|
|
{
|
|
|
|
int *a1, *a2, *a3;
|
|
|
|
|
|
|
|
a3 = dol;
|
|
|
|
for(a1=zero; (*a1&01)==0; a1++)
|
|
|
|
if(a1>=a3)
|
|
|
|
return;
|
|
|
|
for(a2=a1+1; a2<=a3;) {
|
|
|
|
if(*a2 & 01) {
|
|
|
|
a2++;
|
|
|
|
dot = a1;
|
|
|
|
} else
|
|
|
|
*a1++ = *a2++;
|
|
|
|
}
|
|
|
|
dol = a1-1;
|
|
|
|
if(dot > dol)
|
|
|
|
dot = dol;
|
|
|
|
fchange = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getline(int tl)
|
|
|
|
{
|
|
|
|
Rune *lp, *bp;
|
|
|
|
int nl;
|
|
|
|
|
|
|
|
lp = linebuf;
|
|
|
|
bp = getblock(tl, OREAD);
|
|
|
|
nl = nleft;
|
|
|
|
tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
|
|
|
|
while(*lp++ = *bp++) {
|
|
|
|
nl -= sizeof(Rune);
|
|
|
|
if(nl == 0) {
|
|
|
|
tl += BLKSIZE/sizeof(Rune);
|
|
|
|
bp = getblock(tl, 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, uint8_t *buf, int32_t (*iofcn)(int, void *, int32_t))
|
|
|
|
{
|
|
|
|
seek(tfile, b*BLKSIZE, 0);
|
|
|
|
if((*iofcn)(tfile, buf, BLKSIZE) != BLKSIZE) {
|
|
|
|
error(T);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t
|
|
|
|
writewrap(int a, void *b, int32_t c)
|
|
|
|
{
|
|
|
|
return write(a, (const void *)b, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getblock(int atl, int iof)
|
|
|
|
{
|
|
|
|
int bno, off;
|
|
|
|
|
|
|
|
static uint8_t ibuff[BLKSIZE];
|
|
|
|
static uint8_t obuff[BLKSIZE];
|
|
|
|
|
|
|
|
bno = atl / (BLKSIZE/sizeof(Rune));
|
|
|
|
/* &~3 so the ptr is aligned to 4 (?) */
|
|
|
|
off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~3;
|
|
|
|
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, writewrap);
|
|
|
|
ichanged = 0;
|
|
|
|
iblock = bno;
|
|
|
|
blkio(bno, ibuff, read);
|
|
|
|
return (Rune*)(ibuff+off);
|
|
|
|
}
|
|
|
|
if(oblock >= 0)
|
|
|
|
blkio(oblock, obuff, writewrap);
|
|
|
|
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;
|
2016-12-24 21:25:20 +01:00
|
|
|
if((tfile = ocreate(tfname, ORDWR, 0600)) < 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
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-sizeof(Rune)])
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
lp = linebuf;
|
|
|
|
gp = genbuf;
|
|
|
|
while(*lp++ = *gp++)
|
|
|
|
;
|
|
|
|
*addr1 = putline();
|
|
|
|
if(addr1 < addr2)
|
|
|
|
rdelete(addr1+1, addr2);
|
|
|
|
dot = addr1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
substitute(int inglob)
|
|
|
|
{
|
|
|
|
int *mp, *a1, nl, gsubf, n;
|
|
|
|
|
|
|
|
n = getnum(); /* OK even if n==0 */
|
|
|
|
gsubf = compsub();
|
|
|
|
for(a1 = addr1; a1 <= addr2; a1++) {
|
|
|
|
if(match(a1)){
|
|
|
|
int *ozero;
|
|
|
|
int m = n;
|
|
|
|
|
|
|
|
do {
|
|
|
|
int span = loc2-loc1;
|
|
|
|
|
|
|
|
if(--m <= 0) {
|
|
|
|
dosub();
|
|
|
|
if(!gsubf)
|
|
|
|
break;
|
|
|
|
if(span == 0) { /* null RE match */
|
|
|
|
if(*loc2 == 0)
|
|
|
|
break;
|
|
|
|
loc2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(match(0));
|
|
|
|
if(m <= 0) {
|
|
|
|
inglob |= 01;
|
|
|
|
subnewa = putline();
|
|
|
|
*a1 &= ~01;
|
|
|
|
if(anymarks) {
|
|
|
|
for(mp=names; mp<&names[26]; mp++)
|
|
|
|
if(*mp == *a1)
|
|
|
|
*mp = subnewa;
|
|
|
|
}
|
|
|
|
subolda = *a1;
|
|
|
|
*a1 = subnewa;
|
|
|
|
ozero = zero;
|
|
|
|
nl = append(getsub, a1);
|
|
|
|
addr2 += nl;
|
|
|
|
nl += zero-ozero;
|
|
|
|
a1 += nl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(inglob == 0)
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
compsub(void)
|
|
|
|
{
|
|
|
|
int seof, c;
|
|
|
|
Rune *p;
|
|
|
|
|
|
|
|
seof = getchr();
|
|
|
|
if(seof == '\n' || seof == ' ')
|
|
|
|
error(Q);
|
|
|
|
compile(seof);
|
|
|
|
p = rhsbuf;
|
|
|
|
for(;;) {
|
|
|
|
c = getchr();
|
|
|
|
if(c == '\\') {
|
|
|
|
c = getchr();
|
|
|
|
*p++ = ESCFLG;
|
|
|
|
if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
|
|
|
|
error(Q);
|
|
|
|
} else
|
|
|
|
if(c == '\n' && (!globp || !globp[0])) {
|
|
|
|
peekc = c;
|
|
|
|
pflag++;
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
if(c == seof)
|
|
|
|
break;
|
|
|
|
*p++ = c;
|
|
|
|
if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
peekc = getchr();
|
|
|
|
if(peekc == 'g') {
|
|
|
|
peekc = 0;
|
|
|
|
newline();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
newline();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getsub(void)
|
|
|
|
{
|
|
|
|
Rune *p1, *p2;
|
|
|
|
|
|
|
|
p1 = linebuf;
|
|
|
|
if((p2 = linebp) == 0)
|
|
|
|
return EOF;
|
|
|
|
while(*p1++ = *p2++)
|
|
|
|
;
|
|
|
|
linebp = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dosub(void)
|
|
|
|
{
|
|
|
|
Rune *lp, *sp, *rp;
|
|
|
|
int c, n;
|
|
|
|
|
|
|
|
lp = linebuf;
|
|
|
|
sp = genbuf;
|
|
|
|
rp = rhsbuf;
|
|
|
|
while(lp < loc1)
|
|
|
|
*sp++ = *lp++;
|
|
|
|
while(c = *rp++) {
|
|
|
|
if(c == '&'){
|
|
|
|
sp = place(sp, loc1, loc2);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
|
|
|
|
n = c-'0';
|
|
|
|
if(subexp[n].rsp && subexp[n].rep) {
|
|
|
|
sp = place(sp, subexp[n].rsp, subexp[n].rep);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
*sp++ = c;
|
|
|
|
if(sp >= &genbuf[LBSIZE])
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
lp = loc2;
|
|
|
|
loc2 = sp - genbuf + linebuf;
|
|
|
|
while(*sp++ = *lp++)
|
|
|
|
if(sp >= &genbuf[LBSIZE])
|
|
|
|
error(Q);
|
|
|
|
lp = linebuf;
|
|
|
|
sp = genbuf;
|
|
|
|
while(*lp++ = *sp++)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
place(Rune *sp, Rune *l1, Rune *l2)
|
|
|
|
{
|
|
|
|
|
|
|
|
while(l1 < l2) {
|
|
|
|
*sp++ = *l1++;
|
|
|
|
if(sp >= &genbuf[LBSIZE])
|
|
|
|
error(Q);
|
|
|
|
}
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
move(int cflag)
|
|
|
|
{
|
|
|
|
int *adt, *ad1, *ad2;
|
|
|
|
|
|
|
|
nonzero();
|
|
|
|
if((adt = address())==0) /* address() guarantees addr is in range */
|
|
|
|
error(Q);
|
|
|
|
newline();
|
|
|
|
if(cflag) {
|
|
|
|
int *ozero, delta;
|
|
|
|
ad1 = dol;
|
|
|
|
ozero = zero;
|
|
|
|
append(getcopy, ad1++);
|
|
|
|
ad2 = dol;
|
|
|
|
delta = zero - ozero;
|
|
|
|
ad1 += delta;
|
|
|
|
adt += delta;
|
|
|
|
} else {
|
|
|
|
ad2 = addr2;
|
|
|
|
for(ad1 = addr1; ad1 <= ad2;)
|
|
|
|
*ad1++ &= ~01;
|
|
|
|
ad1 = addr1;
|
|
|
|
}
|
|
|
|
ad2++;
|
|
|
|
if(adt<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].rsp = getline(*addr);
|
|
|
|
} else
|
|
|
|
subexp[0].rsp = loc2;
|
|
|
|
subexp[0].rep = 0;
|
|
|
|
if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
|
|
|
|
loc1 = subexp[0].rsp;
|
|
|
|
loc2 = subexp[0].rep;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
loc1 = loc2 = 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putd(void)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = count%10;
|
|
|
|
count /= 10;
|
|
|
|
if(count)
|
|
|
|
putd();
|
|
|
|
putchr(r + L'0');
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putst(char *sp)
|
|
|
|
{
|
|
|
|
Rune r;
|
|
|
|
|
|
|
|
col = 0;
|
|
|
|
for(;;) {
|
|
|
|
sp += chartorune(&r, sp);
|
|
|
|
if(r == 0)
|
|
|
|
break;
|
|
|
|
putchr(r);
|
|
|
|
}
|
|
|
|
putchr(L'\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putshst(Rune *sp)
|
|
|
|
{
|
|
|
|
col = 0;
|
|
|
|
while(*sp)
|
|
|
|
putchr(*sp++);
|
|
|
|
putchr(L'\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putchr(int ac)
|
|
|
|
{
|
|
|
|
char *lp;
|
|
|
|
int c;
|
|
|
|
Rune rune;
|
|
|
|
|
|
|
|
lp = linp;
|
|
|
|
c = ac;
|
|
|
|
if(listf) {
|
|
|
|
if(c == '\n') {
|
|
|
|
if(linp != line && linp[-1] == ' ') {
|
|
|
|
*lp++ = '\\';
|
|
|
|
*lp++ = 'n';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(col > (72-6-2)) {
|
|
|
|
col = 8;
|
|
|
|
*lp++ = '\\';
|
|
|
|
*lp++ = '\n';
|
|
|
|
*lp++ = '\t';
|
|
|
|
}
|
|
|
|
col++;
|
|
|
|
if(c=='\b' || c=='\t' || c=='\\') {
|
|
|
|
*lp++ = '\\';
|
|
|
|
if(c == '\b')
|
|
|
|
c = 'b';
|
|
|
|
else
|
|
|
|
if(c == '\t')
|
|
|
|
c = 't';
|
|
|
|
col++;
|
|
|
|
} else
|
|
|
|
if(c<' ' || c>='\177') {
|
|
|
|
*lp++ = '\\';
|
|
|
|
*lp++ = 'x';
|
|
|
|
*lp++ = hex[c>>12];
|
|
|
|
*lp++ = hex[c>>8&0xF];
|
|
|
|
*lp++ = hex[c>>4&0xF];
|
|
|
|
c = hex[c&0xF];
|
|
|
|
col += 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rune = c;
|
|
|
|
lp += runetochar(lp, &rune);
|
|
|
|
|
|
|
|
if(c == '\n' || lp >= &line[sizeof(line)-5]) {
|
|
|
|
linp = line;
|
|
|
|
write(oflag? 2: 1, line, lp-line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
linp = lp;
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
mktemp(char *as)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
unsigned pid;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pid = getpid();
|
|
|
|
s = as = strdup(as);
|
|
|
|
while(*s++)
|
|
|
|
;
|
|
|
|
s--;
|
|
|
|
while(*--s == 'X') {
|
|
|
|
*s = pid % 10 + '0';
|
|
|
|
pid /= 10;
|
|
|
|
}
|
|
|
|
s++;
|
|
|
|
i = 'a';
|
2016-12-01 00:09:42 +01:00
|
|
|
while(access(as, AEXIST) != -1) {
|
2016-11-25 17:18:40 +01:00
|
|
|
if(i == 'z')
|
|
|
|
return "/";
|
|
|
|
*s = i++;
|
|
|
|
}
|
|
|
|
return as;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
regerror(char *s)
|
|
|
|
{
|
|
|
|
USED(s);
|
|
|
|
error(Q);
|
|
|
|
}
|