1434 lines
23 KiB
C
1434 lines
23 KiB
C
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)bfs:bfs.c 1.22"
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <regexpr.h>
|
|
#include <limits.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <locale.h>
|
|
int setjmp();
|
|
jmp_buf env;
|
|
|
|
|
|
#ifdef pdp11
|
|
|
|
#define BRKTYP char
|
|
#define BRKSIZ 4096
|
|
#define BRKTWO 2
|
|
#define BFSAND &0377
|
|
#define BFSLIM 254
|
|
#define BFSTRU 255
|
|
#define BFSBUF 256
|
|
|
|
#else
|
|
|
|
#define BRKTYP short
|
|
#define BRKSIZ 8192
|
|
#define BRKTWO 4
|
|
#define BFSAND
|
|
#define BFSLIM 511
|
|
#define BFSTRU 511
|
|
#define BFSBUF 512
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct Comd {
|
|
int Cnumadr;
|
|
int Cadr[2];
|
|
char Csep;
|
|
char Cop;
|
|
};
|
|
|
|
int Dot, Dollar;
|
|
int markarray[26], *mark;
|
|
int fstack[15]={1, -1};
|
|
int infildes=0;
|
|
int outfildes=1;
|
|
char internal[512], *intptr;
|
|
char comdlist[100];
|
|
char *endds; /* See brk(2) in manual. */
|
|
char charbuf='\n';
|
|
int peeked;
|
|
char currex[100];
|
|
int trunc=BFSTRU;
|
|
int crunch = -1;
|
|
int txtfd;
|
|
off64_t segblk[512],prevblk;
|
|
int segoff[512], prevoff;
|
|
int oldfd=0;
|
|
int flag4=0;
|
|
int flag3=0;
|
|
int flag2=0;
|
|
int flag1=0;
|
|
int flag=0;
|
|
int lprev=1;
|
|
int status[1];
|
|
|
|
BRKTYP *lincnt;
|
|
char *perbuf;
|
|
char *rebuf;
|
|
char *glbuf;
|
|
char tty, *bigfile;
|
|
char fle[80];
|
|
char prompt=1;
|
|
char verbose=1; /* 1=print # of bytes read in; 0=silent. */
|
|
char varray[10][100]; /* Holds xv cmd parameters. */
|
|
double outcnt;
|
|
char strtmp[32];
|
|
|
|
/*
|
|
** The following structure and declaration are in
|
|
** stdio.h but that file can't be included in bfs.c
|
|
** because of name conflicts (e.g. getc) with functions
|
|
** used throughout the program.
|
|
*/
|
|
typedef struct {
|
|
int _cnt;
|
|
unsigned char *_ptr;
|
|
unsigned char *_base;
|
|
char _flag;
|
|
char _file;
|
|
} FILE;
|
|
extern FILE _iob[1];
|
|
#define stdout &_iob[1]
|
|
|
|
static char
|
|
getc()
|
|
{
|
|
if(!peeked) {
|
|
while((!(infildes == oldfd && flag)) && (!flag1) && (!readc(infildes,&charbuf))) {
|
|
if(infildes == 100 && (!flag)) flag1 = 1;
|
|
if((infildes=pop(fstack)) == -1) quit();
|
|
if((!flag1) && infildes == 0 && flag3 && prompt) printf("*");
|
|
}
|
|
if(infildes == oldfd && flag) flag2 = 0;
|
|
flag1 = 0;
|
|
}
|
|
else peeked = 0;
|
|
return(charbuf);
|
|
}
|
|
|
|
|
|
main(argc,argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
void reset();
|
|
struct Comd comdstruct, *p;
|
|
|
|
(void)setlocale(LC_ALL, "");
|
|
if(argc < 2 || argc > 3) {
|
|
err(1,"arg count");
|
|
quit();
|
|
}
|
|
mark = markarray-'a';
|
|
if(argc == 3) verbose = 0;
|
|
setbuf(stdout, 0);
|
|
if(bigopen(bigfile=argv[argc-1])) quit();
|
|
tty = isatty(0);
|
|
|
|
p = &comdstruct;
|
|
/* Look for 0 or more non-'%' char followed by a '%' */
|
|
perbuf = compile("[^%]*%",(char *)0,(char *)0);
|
|
if(regerrno)
|
|
regerr(regerrno);
|
|
setjmp(env);
|
|
#if defined(__STDC__)
|
|
signal(SIGINT, (void (*)(int))reset);
|
|
#else
|
|
signal(SIGINT, reset);
|
|
#endif
|
|
err(0,"");
|
|
printf("\n");
|
|
flag = 0;
|
|
prompt = 0;
|
|
while(1) begin(p);
|
|
}
|
|
|
|
void
|
|
reset() /* for longjmp on signal */
|
|
{
|
|
longjmp(env,1);
|
|
}
|
|
|
|
|
|
begin(p)
|
|
struct Comd *p;
|
|
{
|
|
char line[256];
|
|
|
|
strtagn: if(flag == 0) eat();
|
|
if(infildes != 100) {
|
|
if(infildes == 0 && prompt) printf("*");
|
|
flag3 = 1;
|
|
getstr(1,line,0,0,0);
|
|
flag3 = 0;
|
|
if(percent(line) < 0) goto strtagn;
|
|
newfile(1,"");
|
|
}
|
|
if(!(getcomd(p,1) < 0)) {
|
|
|
|
switch(p->Cop) {
|
|
|
|
case 'e': if(!flag) ecomd(p);
|
|
else err(0,"");
|
|
break;
|
|
|
|
case 'f': fcomd(p);
|
|
break;
|
|
|
|
case 'g': if(flag == 0) gcomd(p,1);
|
|
else err(0,"");
|
|
break;
|
|
|
|
case 'k': kcomd(p);
|
|
break;
|
|
|
|
case 'p': pcomd(p);
|
|
break;
|
|
|
|
case 'q': qcomd(p);
|
|
break;
|
|
|
|
case 'v': if(flag == 0) gcomd(p,0);
|
|
else err(0,"");
|
|
break;
|
|
|
|
case 'x': if(!flag) xcomds(p);
|
|
else err(0,"");
|
|
break;
|
|
|
|
case 'w': wcomd(p);
|
|
break;
|
|
|
|
case '\n': nlcomd(p);
|
|
break;
|
|
|
|
case '=': eqcomd(p);
|
|
break;
|
|
|
|
case ':': colcomd(p);
|
|
break;
|
|
|
|
case '!': excomd(p);
|
|
break;
|
|
|
|
case 'P': prompt = !prompt;
|
|
break;
|
|
|
|
|
|
default: if(flag) err(0,"");
|
|
else err(1,"bad command");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bigopen(file)
|
|
char file[];
|
|
{
|
|
register int l, off, cnt;
|
|
int newline, n, s;
|
|
char block[512];
|
|
off64_t blk;
|
|
|
|
if((txtfd=open(file,0)) < 0) return(err(1,"can't open"));
|
|
|
|
blk = -1;
|
|
newline = 1;
|
|
l = cnt = s = 0;
|
|
off = 512;
|
|
if((lincnt=(BRKTYP*)sbrk(BRKSIZ)) == (BRKTYP*)-1)
|
|
return(err(1,"too many lines"));
|
|
endds = (char *)lincnt; /* Save initial data space address. */
|
|
|
|
while((n=read(txtfd,block,512)) > 0) {
|
|
blk++;
|
|
for(off=0; off<n; off++) {
|
|
if(newline) {
|
|
newline = 0;
|
|
if(l>0 && !(l&07777))
|
|
if((BRKTYP*)sbrk(BRKSIZ) == (BRKTYP*)-1)
|
|
return(err(1,"too many lines"));
|
|
lincnt[l] = cnt;
|
|
cnt = 0;
|
|
if(!(l++ & 077)) {
|
|
segblk[s] = blk;
|
|
segoff[s++] = off;
|
|
}
|
|
if(l < 0 || l > 32767) return(err(1,"too many lines"));
|
|
}
|
|
if(block[off] == '\n') newline = 1;
|
|
cnt++;
|
|
#ifdef pdp11
|
|
if(cnt > 255)
|
|
{printf("Line %d too long\n",l);
|
|
return(-1);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if(!(l&07777)) if((BRKTYP*)sbrk(BRKTWO) == (BRKTYP*)-1)
|
|
return(err(1,"too many lines"));
|
|
lincnt[Dot = Dollar = l] = cnt;
|
|
sizeprt(blk,off);
|
|
return(0);
|
|
}
|
|
|
|
|
|
sizeprt(blk, off)
|
|
int blk, off;
|
|
{
|
|
if(verbose) printf("%.0f",512.*blk+off);
|
|
}
|
|
|
|
|
|
off64_t saveblk = -1;
|
|
|
|
|
|
bigread(l,rec)
|
|
int l;
|
|
char rec[];
|
|
{
|
|
register int i;
|
|
register char *r, *b;
|
|
int off;
|
|
static char savetxt[512];
|
|
|
|
if((i=l-lprev) == 1) prevoff += lincnt[lprev]BFSAND;
|
|
else if(i >= 0 && i <= 32)
|
|
for(i=lprev; i<l; i++) prevoff += lincnt[i]BFSAND;
|
|
else if(i < 0 && i >= -32)
|
|
for(i=lprev-1; i>=l; i--) prevoff -= lincnt[i]BFSAND;
|
|
else {
|
|
prevblk = segblk[i=(l-1)>>6];
|
|
prevoff = segoff[i];
|
|
for(i=(i<<6)+1; i<l; i++) prevoff += lincnt[i]BFSAND;
|
|
}
|
|
|
|
prevblk += prevoff>>9;
|
|
prevoff &= 0777;
|
|
lprev = l;
|
|
|
|
if(prevblk != saveblk) {
|
|
lseek64(txtfd,((off64_t)(saveblk=prevblk))<<9,0);
|
|
read(txtfd,savetxt,512);
|
|
}
|
|
|
|
r = rec;
|
|
off = prevoff;
|
|
while(1) {
|
|
for(b=savetxt+off; b<savetxt+512; b++) {
|
|
if((*r++ = *b) == '\n') {
|
|
*(r-1) = '\0';
|
|
return;
|
|
}
|
|
if(((unsigned)r - (unsigned)rec) > BFSLIM) {
|
|
#ifdef pdp11
|
|
write(2, "line too long\n", 14);
|
|
exit(1);
|
|
#else
|
|
write(2, "Line too long--output truncated\n", 32);
|
|
return;
|
|
#endif
|
|
}
|
|
}
|
|
read(txtfd,savetxt,512);
|
|
off = 0;
|
|
saveblk++;
|
|
}
|
|
}
|
|
|
|
|
|
ecomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int i = 0;
|
|
|
|
while(peekc() == ' ') getc();
|
|
while((fle[i++] = getc()) != '\n');
|
|
fle[--i] = '\0';
|
|
close(txtfd); /* Without this, ~20 "e" cmds gave "can't open" msg. */
|
|
brk(endds); /* Reset data space addr. - mostly for 16-bit cpu's. */
|
|
lprev=1; prevblk=0; prevoff=0; saveblk = -1; /* Reset parameters. */
|
|
if(bigopen(bigfile =fle)) quit();
|
|
printf("\n");
|
|
}
|
|
|
|
fcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
if(more() || defaults(p,1,0,0,0,0,0)) return(-1);
|
|
printf("%s\n",bigfile);
|
|
return(0);
|
|
}
|
|
|
|
|
|
gcomd(p,k)
|
|
int k;
|
|
struct Comd *p;
|
|
{
|
|
register char d;
|
|
register int i, end;
|
|
char line[BFSBUF];
|
|
|
|
if(defaults(p,1,2,1,Dollar,0,0)) return(-1);
|
|
|
|
if((d=getc()) == '\n') return(err(1,"syntax"));
|
|
if(peekc() == d) getc();
|
|
else
|
|
if(getstr(1,currex,d,0,1)) return(-1);
|
|
glbuf = compile(currex,(char *)0,(char *)0);
|
|
if(regerrno) {
|
|
regerr(regerrno);
|
|
return(-1);
|
|
} else {
|
|
if(glbuf)
|
|
free(glbuf);
|
|
}
|
|
|
|
if(getstr(1,comdlist,0,0,0)) return(-1);
|
|
i = p->Cadr[0];
|
|
end = p->Cadr[1];
|
|
while (i<=end) {
|
|
bigread(i,line);
|
|
if(!(step(line,glbuf))) {
|
|
if(!k) {
|
|
Dot = i;
|
|
if (xcomdlist(p)) return(err(1,"bad comd list"));
|
|
}
|
|
i++;
|
|
}
|
|
else {
|
|
if(k) {
|
|
Dot = i;
|
|
if (xcomdlist(p)) return(err(1,"bad comd list"));
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
kcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register char c;
|
|
|
|
if((c=peekc()) < 'a' || c > 'z') return(err(1,"bad mark"));
|
|
getc();
|
|
if(more() || defaults(p,1,1,Dot,0,1,0)) return(-1);
|
|
|
|
mark[c] = Dot = p->Cadr[0];
|
|
return(0);
|
|
}
|
|
|
|
|
|
xncomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register char c;
|
|
|
|
if(more() || defaults(p,1,0,0,0,0,0)) return(-1);
|
|
|
|
for(c='a'; c<='z'; c++)
|
|
if(mark[c]) printf("%c\n",c);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
pcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int i;
|
|
char line[BFSBUF];
|
|
|
|
if(more() || defaults(p,1,2,Dot,Dot,1,0)) return(-1);
|
|
|
|
for(i=p->Cadr[0]; i<=p->Cadr[1] && i>0; i++) {
|
|
bigread(i,line);
|
|
out(line);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
qcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
if(more()) return(-1);
|
|
quit();
|
|
}
|
|
|
|
|
|
xcomds(p)
|
|
struct Comd *p;
|
|
{
|
|
switch(getc()) {
|
|
case 'b': return(xbcomd(p));
|
|
case 'c': return(xccomd(p));
|
|
case 'f': return(xfcomd(p));
|
|
case 'n': return(xncomd(p));
|
|
case 'o': return(xocomd(p));
|
|
case 't': return(xtcomd(p));
|
|
case 'v': return(xvcomd(p));
|
|
default: return(err(1,"bad command"));
|
|
}
|
|
}
|
|
|
|
|
|
xbcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int fail, n;
|
|
register char d;
|
|
char str[50];
|
|
|
|
fail = 0;
|
|
if(defaults(p,0,2,Dot,Dot,0,1)) fail = 1;
|
|
else {
|
|
if((d=getc()) == '\n') return(err(1,"syntax"));
|
|
if(d == 'z') {
|
|
if(status[0] != 0) return(0);
|
|
getc();
|
|
if(getstr(1,str,0,0,0)) return(-1);
|
|
return(jump(1,str));
|
|
}
|
|
if(d == 'n') {
|
|
if(status[0] == 0) return(0);
|
|
getc();
|
|
if(getstr(1,str,0,0,0)) return(-1);
|
|
return(jump(1,str));
|
|
}
|
|
if(getstr(1,str,d,' ',0)) return(-1);
|
|
if((n=hunt(0,str,p->Cadr[0]-1,1,0,1)) < 0) fail = 1;
|
|
if(getstr(1,str,0,0,0)) return(-1);
|
|
if(more()) return(err(1,"syntax"));
|
|
}
|
|
|
|
if(!fail) {
|
|
Dot = n;
|
|
return(jump(1,str));
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
xccomd(p)
|
|
struct Comd *p;
|
|
{
|
|
char arg[100];
|
|
|
|
if(getstr(1,arg,0,' ',0) || defaults(p,1,0,0,0,0,0)) return(-1);
|
|
|
|
if(equal(arg,"")) crunch = -crunch;
|
|
else if(equal(arg,"0")) crunch = -1;
|
|
else if(equal(arg,"1")) crunch = 1;
|
|
else return(err(1,"syntax"));
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
xfcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
char fl[100];
|
|
register char *f;
|
|
|
|
if(defaults(p,1,0,0,0,0,0)) return(-1);
|
|
|
|
while(peekc() == ' ') getc();
|
|
for(f=fl; (*f=getc()) != '\n'; f++);
|
|
if(f==fl) return(err(1,"no file"));
|
|
*f = '\0';
|
|
|
|
return(newfile(1,fl));
|
|
}
|
|
|
|
|
|
xocomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int fd;
|
|
char arg[100];
|
|
|
|
if(getstr(1,arg,0,' ',0) || defaults(p,1,0,0,0,0,0)) return(-1);
|
|
|
|
if(!arg[0]) {
|
|
if(outfildes == 1) return(err(1,"no diversion"));
|
|
close(outfildes);
|
|
outfildes = 1;
|
|
}
|
|
else {
|
|
if(outfildes != 1) return(err(1,"already diverted"));
|
|
if((fd=creat(arg,(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) < 0)
|
|
return(err(1,"can't create"));
|
|
outfildes = fd;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
xtcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int t;
|
|
|
|
while(peekc() == ' ') getc();
|
|
if((t=rdnumb(1)) < 0 || more() || defaults(p,1,0,0,0,0,0))
|
|
return(-1);
|
|
|
|
trunc = t;
|
|
return(0);
|
|
}
|
|
|
|
|
|
xvcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register char c;
|
|
register int i;
|
|
int temp0, temp1, temp2;
|
|
int fildes[2];
|
|
|
|
if((c=peekc()) < '0' || c > '9') return(err(1,"digit required"));
|
|
getc();
|
|
c -= '0';
|
|
while(peekc() == ' ') getc();
|
|
if(peekc()=='\\') getc();
|
|
else if(peekc() == '!') {
|
|
if(pipe(fildes) < 0) {
|
|
printf("Try again");
|
|
return;
|
|
}
|
|
temp0 = dup(0);
|
|
temp1 = dup(1);
|
|
temp2 = infildes;
|
|
close(0);
|
|
dup(fildes[0]);
|
|
close(1);
|
|
dup(fildes[1]);
|
|
close(fildes[0]);
|
|
close(fildes[1]);
|
|
getc();
|
|
flag4 = 1;
|
|
excomd(p);
|
|
close(1);
|
|
infildes = 0;
|
|
}
|
|
for(i=0;(varray[c][i] = getc()) != '\n';i++);
|
|
varray[c][i] = '\0';
|
|
if(flag4) {
|
|
infildes = temp2;
|
|
close(0);
|
|
dup(temp0);
|
|
close(temp0);
|
|
dup(temp1);
|
|
close(temp1);
|
|
flag4 = 0;
|
|
charbuf = ' ';
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
wcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register int i,fd, savefd;
|
|
int savecrunch, savetrunc;
|
|
char arg[100], line[BFSBUF];
|
|
|
|
if(getstr(1,arg,0,' ',0) || defaults(p,1,2,1,Dollar,1,0)) return(-1);
|
|
if(!arg[0]) return(err(1,"no file name"));
|
|
if(equal(arg,bigfile)) return(err(1,"no change indicated"));
|
|
if((fd=creat(arg,(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) <0)
|
|
return(err(1,"can't create"));
|
|
|
|
savefd = outfildes;
|
|
savetrunc = trunc;
|
|
savecrunch = crunch;
|
|
outfildes = fd;
|
|
trunc = BFSTRU;
|
|
crunch = -1;
|
|
|
|
outcnt = 0;
|
|
for(i=p->Cadr[0]; i<=p->Cadr[1] && i>0; i++) {
|
|
bigread(i,line);
|
|
out(line);
|
|
}
|
|
if(verbose) printf("%.0f\n",outcnt);
|
|
close(fd);
|
|
|
|
outfildes = savefd;
|
|
trunc = savetrunc;
|
|
crunch = savecrunch;
|
|
return(0);
|
|
}
|
|
|
|
|
|
nlcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
if(defaults(p,1,2,Dot+1,Dot+1,1,0)) {
|
|
getc();
|
|
return(-1);
|
|
}
|
|
return(pcomd(p));
|
|
}
|
|
|
|
|
|
eqcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
if(more() || defaults(p,1,1,Dollar,0,0,0)) return(-1);
|
|
printf("%d\n",p->Cadr[0]);
|
|
}
|
|
|
|
|
|
colcomd(p)
|
|
struct Comd *p;
|
|
{
|
|
return(defaults(p,1,0,0,0,0,0));
|
|
}
|
|
|
|
|
|
xcomdlist(p)
|
|
struct Comd *p;
|
|
{
|
|
flag = 1;
|
|
flag2 = 1;
|
|
newfile(1,"");
|
|
while(flag2) begin(p);
|
|
if(flag == 0) return(1);
|
|
flag = 0;
|
|
return(0);
|
|
}
|
|
|
|
|
|
excomd(p)
|
|
struct Comd *p;
|
|
{
|
|
register pid_t i;
|
|
register int j;
|
|
void reset();
|
|
|
|
if(infildes != 100) charbuf = '\n';
|
|
while((i=fork()) < (pid_t)0) sleep(10);
|
|
if(i == (pid_t)0) {
|
|
signal(SIGINT, SIG_DFL); /*Guarantees child can be intr. */
|
|
if(infildes == 100 || flag4) {
|
|
execl("/usr/bin/sh","sh","-c",intptr,0);
|
|
exit(0);
|
|
}
|
|
if(infildes != 0) {
|
|
close(0);
|
|
dup(infildes);
|
|
}
|
|
for(j=3; j<15; j++) close(j);
|
|
execl("/usr/bin/sh","sh","-t",0);
|
|
exit(0);
|
|
}
|
|
signal(SIGINT, SIG_IGN);
|
|
while(wait(status) != i);
|
|
status[0] = status[0] >> 8;
|
|
|
|
#if defined(__STDC__)
|
|
signal(SIGINT, (void (*)(int))reset);
|
|
#else
|
|
signal(SIGINT, reset); /* Restore signal to previous status */
|
|
#endif
|
|
|
|
if((infildes == 0 || (infildes == 100 && fstack[fstack[0]] == 0))
|
|
&& verbose && (!flag4)) printf("!\n");
|
|
return(0);
|
|
}
|
|
|
|
|
|
defaults(p,prt,max,def1,def2,setdot,errsok)
|
|
struct Comd *p;
|
|
int prt, max, def1, def2, setdot, errsok;
|
|
{
|
|
if(!def1) def1 = Dot;
|
|
if(!def2) def2 = def1;
|
|
if(p->Cnumadr >= max) return(errsok?-1:err(prt,"adr count"));
|
|
if(p->Cnumadr < 0) {
|
|
p->Cadr[++p->Cnumadr] = def1;
|
|
p->Cadr[++p->Cnumadr] = def2;
|
|
}
|
|
else if(p->Cnumadr < 1)
|
|
p->Cadr[++p->Cnumadr] = p->Cadr[0];
|
|
if(p->Cadr[0] < 1 || p->Cadr[0] > Dollar ||
|
|
p->Cadr[1] < 1 || p->Cadr[1] > Dollar)
|
|
return(errsok?-1:err(prt,"range"));
|
|
if(p->Cadr[0] > p->Cadr[1]) return(errsok?-1:err(prt,"adr1 > adr2"));
|
|
if(setdot) Dot = p->Cadr[1];
|
|
return(0);
|
|
}
|
|
|
|
|
|
getcomd(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register int r;
|
|
register char c;
|
|
|
|
p->Cnumadr = -1;
|
|
p->Csep = ' ';
|
|
switch(c = peekc()) {
|
|
case ',':
|
|
case ';': p->Cop = getc();
|
|
return(0);
|
|
}
|
|
|
|
if((r=getadrs(p,prt)) < 0) return(r);
|
|
|
|
c=peekc();
|
|
if(c == '\n') p->Cop = '\n';
|
|
else p->Cop = getc();
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
getadrs(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register int r;
|
|
register char c;
|
|
|
|
if((r=getadr(p,prt)) < 0) return(r);
|
|
|
|
switch(c=peekc()) {
|
|
case ';': Dot = p->Cadr[0];
|
|
case ',': getc();
|
|
p->Csep = c;
|
|
return(getadr(p,prt));
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
getadr(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register int r;
|
|
register char c,d;
|
|
|
|
r = 0;
|
|
while(peekc() == ' ') getc(); /* Ignore leading spaces */
|
|
switch(c = peekc()) {
|
|
case '\n':
|
|
case ',':
|
|
case ';': return(0);
|
|
|
|
case '\'': getc();
|
|
r = getmark(p,prt);
|
|
break;
|
|
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9': r = getnumb(p,prt);
|
|
break;
|
|
|
|
case '.': getc();
|
|
case '+':
|
|
case '-': p->Cadr[++p->Cnumadr] = Dot;
|
|
break;
|
|
|
|
case '$': getc();
|
|
p->Cadr[++p->Cnumadr] = Dollar;
|
|
break;
|
|
|
|
case '^': getc();
|
|
p->Cadr[++p->Cnumadr] = Dot - 1;
|
|
break;
|
|
|
|
case '/':
|
|
case '?':
|
|
case '>':
|
|
case '<': getc();
|
|
r = getrex(p,prt,c);
|
|
break;
|
|
|
|
default: return(0);
|
|
}
|
|
|
|
if(r == 0) r = getrel(p,prt);
|
|
return(r);
|
|
}
|
|
|
|
|
|
getnumb(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register int i;
|
|
|
|
if((i=rdnumb(prt)) < 0) return(-1);
|
|
p->Cadr[++p->Cnumadr] = i;
|
|
return(0);
|
|
}
|
|
|
|
|
|
rdnumb(prt)
|
|
int prt;
|
|
{
|
|
char num[20], *n;
|
|
int i;
|
|
|
|
n = num;
|
|
while((*n=peekc()) >= '0' && *n <= '9') {
|
|
n++;
|
|
getc();
|
|
}
|
|
|
|
*n = '\0';
|
|
if((i=patoi(num)) >= 0) return(i);
|
|
return(err(prt,"bad num"));
|
|
}
|
|
|
|
|
|
getrel(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register int op, n;
|
|
register char c;
|
|
int j;
|
|
|
|
n = 0;
|
|
op = 1;
|
|
while((c=peekc())=='+' || c=='-') {
|
|
if(c=='+') n++;
|
|
else n--;
|
|
getc();
|
|
}
|
|
j = n;
|
|
if(n < 0) op = -1;
|
|
if(c=='\n') p->Cadr[p->Cnumadr] += n;
|
|
else {
|
|
if((n=rdnumb(0)) > 0 && p->Cnumadr >= 0) {
|
|
p->Cadr[p->Cnumadr] += op*n;
|
|
getrel(p,prt);
|
|
}
|
|
else {
|
|
if(c=='-') p->Cadr[p->Cnumadr] += j;
|
|
else p->Cadr[p->Cnumadr] += j;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
getmark(p,prt)
|
|
struct Comd *p;
|
|
int prt;
|
|
{
|
|
register char c;
|
|
|
|
if((c=peekc()) < 'a' || c > 'z') return(err(prt,"bad mark"));
|
|
getc();
|
|
|
|
if(!mark[c]) return(err(prt,"undefined mark"));
|
|
p->Cadr[++p->Cnumadr] = mark[c];
|
|
return(0);
|
|
}
|
|
|
|
|
|
getrex(p,prt,c)
|
|
struct Comd *p;
|
|
int prt;
|
|
char c;
|
|
{
|
|
register int down, wrap, start;
|
|
|
|
if(peekc() == c) getc();
|
|
else if(getstr(prt,currex,c,0,1)) return(-1);
|
|
|
|
switch(c) {
|
|
case '/': down = 1; wrap = 1; break;
|
|
case '?': down = 0; wrap = 1; break;
|
|
case '>': down = 1; wrap = 0; break;
|
|
case '<': down = 0; wrap = 0; break;
|
|
}
|
|
|
|
if(p->Csep == ';') start = p->Cadr[0];
|
|
else start = Dot;
|
|
|
|
if((p->Cadr[++p->Cnumadr]=hunt(prt,currex,start,down,wrap,0)) < 0)
|
|
return(-1);
|
|
return(0);
|
|
}
|
|
|
|
|
|
hunt(prt,rex,start,down,wrap,errsok)
|
|
int prt, errsok;
|
|
char rex[];
|
|
int start, down, wrap;
|
|
{
|
|
register int i, end1, incr;
|
|
int start1, start2;
|
|
char line[BFSBUF];
|
|
|
|
if(down) {
|
|
start1 = start + 1;
|
|
end1 = Dollar;
|
|
start2 = 1;
|
|
incr = 1;
|
|
}
|
|
else {
|
|
start1 = start - 1;
|
|
end1 = 1;
|
|
start2 = Dollar;
|
|
incr = -1;
|
|
}
|
|
|
|
rebuf = compile(rex, (char *)0,(char *)0);
|
|
if(regerrno)
|
|
regerr(regerrno);
|
|
else
|
|
if(rebuf)
|
|
free(rebuf);
|
|
|
|
for(i=start1; i != end1+incr; i += incr) {
|
|
bigread(i,line);
|
|
if(step(line,rebuf)) {
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
if(!wrap) return(errsok?-1:err(prt,"not found"));
|
|
|
|
for(i=start2; i != start1; i += incr) {
|
|
bigread(i,line);
|
|
if(step(line,rebuf)) {
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return(errsok?-1:err(prt,"not found"));
|
|
}
|
|
|
|
|
|
jump(prt,label)
|
|
int prt;
|
|
char label[];
|
|
{
|
|
register char c, *l;
|
|
char line[256];
|
|
|
|
if(infildes == 0 && tty) return(err(prt,"jump on tty"));
|
|
if(infildes == 100) intptr = internal;
|
|
else lseek(infildes,0L,0);
|
|
|
|
sprintf(strtmp, "^: *%s$", label);
|
|
rebuf = compile(strtmp, (char *)0, (char *)0);
|
|
if(regerrno) {
|
|
regerr(regerrno);
|
|
return -1;
|
|
}
|
|
|
|
for(l=line; readc(infildes,l); l++) {
|
|
if(*l == '\n') {
|
|
*l = '\0';
|
|
if(step(line, rebuf)) {
|
|
charbuf = '\n';
|
|
return(peeked = 0);
|
|
}
|
|
l = line - 1;
|
|
}
|
|
}
|
|
|
|
return(err(prt,"label not found"));
|
|
}
|
|
|
|
|
|
getstr(prt,buf,brk,ignr,nonl)
|
|
int prt, nonl;
|
|
char buf[], brk, ignr;
|
|
{
|
|
register char *b, c, prevc;
|
|
|
|
prevc = 0;
|
|
for(b=buf; c=peekc(); prevc=c) {
|
|
if(c == '\n') {
|
|
if(prevc == '\\' && (!flag3)) *(b-1) = getc();
|
|
else if(prevc == '\\' && flag3) {
|
|
*b++ = getc();
|
|
}
|
|
else if(nonl) break;
|
|
else return(*b='\0');
|
|
}
|
|
else {
|
|
getc();
|
|
if(c == brk) {
|
|
if(prevc == '\\') *(b-1) = c;
|
|
else return(*b='\0');
|
|
}
|
|
else if(b != buf || c != ignr) *b++ = c;
|
|
}
|
|
}
|
|
return(err(prt,"syntax"));
|
|
}
|
|
|
|
|
|
regerr(c)
|
|
int c;
|
|
{
|
|
if(prompt) {
|
|
switch(c) {
|
|
case 11: printf("Range endpoint too large.\n");
|
|
break;
|
|
case 16: printf("Bad number.\n");
|
|
break;
|
|
case 25: printf("``\\digit'' out of range.\n");
|
|
break;
|
|
case 41: printf("No remembered search string.\n");
|
|
break;
|
|
case 42: printf("() imbalance.\n");
|
|
break;
|
|
case 43: printf("Too many (.\n");
|
|
break;
|
|
case 44: printf("More than 2 numbers given in { }.\n");
|
|
break;
|
|
case 45: printf("} expected after \\.\n");
|
|
break;
|
|
case 46: printf("First number exceeds second in { }.\n");
|
|
break;
|
|
case 49: printf("[] imbalance.\n");
|
|
break;
|
|
case 50: printf("Regular expression overflow.\n");
|
|
break;
|
|
case 67: printf("Illegal byte sequence.\n");
|
|
break;
|
|
default: printf("RE error.\n");
|
|
break;
|
|
}
|
|
}else {
|
|
printf("?\n");
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
err(prt,msg)
|
|
int prt;
|
|
char msg[];
|
|
{
|
|
if(prt) (prompt? printf("%s\n",msg): printf("?\n"));
|
|
if(infildes != 0) {
|
|
infildes = pop(fstack);
|
|
charbuf = '\n';
|
|
peeked = 0;
|
|
flag3 = 0;
|
|
flag2 = 0;
|
|
flag = 0;
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
|
|
readc(f,c)
|
|
int f;
|
|
char *c;
|
|
{
|
|
if(f == 100) {
|
|
if(!(*c = *intptr++)) {
|
|
intptr--;
|
|
charbuf = '\n';
|
|
return(0);
|
|
}
|
|
}
|
|
else if(read(f,c,1) != 1) {
|
|
close(f);
|
|
charbuf = '\n';
|
|
return(0);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
percent(line)
|
|
char line[256];
|
|
{
|
|
register char *lp, *var;
|
|
char *front, *per, c[2], *olp, p[2], fr[256], *copy();
|
|
int i,j,a,b;
|
|
|
|
per = p;
|
|
var = c;
|
|
front = fr;
|
|
j = 0;
|
|
while(!j) {
|
|
j = 1;
|
|
olp = line;
|
|
intptr = internal;
|
|
while(step(olp,perbuf)) {
|
|
while(loc1 < loc2) *front++ = *loc1++;
|
|
*(--front) = '\0';
|
|
front = fr;
|
|
*per++ = '%';
|
|
*per = '\0';
|
|
per = p;
|
|
*var = *loc2;
|
|
if((i = 1 + strlen(front)) >= 2 && fr[i-2] == '\\') {
|
|
cat(front,"");
|
|
--intptr;
|
|
cat(per,"");
|
|
}
|
|
else {
|
|
if(!(*var >= '0' && *var <= '9')) return(err(1,"usage: %digit"));
|
|
cat(front,"");
|
|
cat(varray[*var-'0'],"");
|
|
j =0;
|
|
loc2++; /* Compensate for removing --lp above */
|
|
}
|
|
olp = loc2;
|
|
}
|
|
cat(olp,"");
|
|
*intptr = '\0';
|
|
if(!j) {
|
|
intptr = internal;
|
|
lp = line;
|
|
copy(intptr,lp);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cat(arg1,arg2)
|
|
char arg1[],arg2[];
|
|
{
|
|
register char *arg;
|
|
arg = arg1;
|
|
while(*arg) *intptr++ = *arg++;
|
|
if(*arg2) {
|
|
arg = arg2;
|
|
while(*arg) *intptr++ = *arg++;
|
|
}
|
|
}
|
|
|
|
|
|
newfile(prt,f)
|
|
int prt;
|
|
char f[];
|
|
{
|
|
register int fd;
|
|
|
|
if(!*f) {
|
|
if(flag != 0) {
|
|
oldfd = infildes;
|
|
intptr = comdlist;
|
|
}
|
|
else intptr = internal;
|
|
fd = 100;
|
|
}
|
|
else if((fd=open(f,0)) < 0) {
|
|
sprintf(strtmp, "cannot open %s", f);
|
|
return err(prt, strtmp);
|
|
}
|
|
|
|
push(fstack,infildes);
|
|
if(flag4) oldfd = fd;
|
|
infildes = fd;
|
|
return(peeked=0);
|
|
}
|
|
|
|
|
|
push(s,d)
|
|
int s[], d;
|
|
{
|
|
s[++s[0]] = d;
|
|
}
|
|
|
|
|
|
pop(s)
|
|
int s[];
|
|
{
|
|
return(s[s[0]--]);
|
|
}
|
|
|
|
|
|
peekc()
|
|
{
|
|
register char c;
|
|
|
|
c = getc();
|
|
peeked = 1;
|
|
|
|
return(c);
|
|
}
|
|
|
|
|
|
eat()
|
|
{
|
|
if(charbuf != '\n') while(getc() != '\n');
|
|
peeked = 0;
|
|
}
|
|
|
|
|
|
more()
|
|
{
|
|
if(getc() != '\n') return(err(1,"syntax"));
|
|
return(0);
|
|
}
|
|
|
|
|
|
quit()
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
|
|
out(ln)
|
|
char *ln;
|
|
{
|
|
register char *rp, *wp, prev;
|
|
register int w, width;
|
|
char *oldrp;
|
|
char linea[256+5];
|
|
wchar_t cl;
|
|
int i = 0;
|
|
char *untab();
|
|
int lim, p;
|
|
|
|
if(crunch > 0) {
|
|
|
|
ln = untab(ln);
|
|
rp = wp = ln - 1;
|
|
prev = ' ';
|
|
|
|
while(*++rp) {
|
|
if(prev != ' ' || *rp != ' ') *++wp = *rp;
|
|
prev = *rp;
|
|
}
|
|
*++wp = '\n';
|
|
lim = wp - ln;
|
|
*++wp = '\0';
|
|
|
|
if(*ln == '\n') return;
|
|
}
|
|
else ln[lim=strlen(ln)] = '\n';
|
|
|
|
if(MB_CUR_MAX <= 1) {
|
|
if(lim > trunc) ln[lim=trunc] = '\n';
|
|
}
|
|
else {
|
|
if ((trunc < (BFSBUF -1)) || (lim > trunc)) {
|
|
w = 0;
|
|
oldrp = rp = ln;
|
|
while (1) {
|
|
if((p = mbtowc(&cl, rp, MB_LEN_MAX)) == 0) {
|
|
break;
|
|
}
|
|
if (p == -1) {
|
|
width = p = 1;
|
|
} else {
|
|
width = scrwidth(cl);
|
|
if (width == 0)
|
|
width = 1;
|
|
}
|
|
if ((w += width) > trunc)
|
|
break;
|
|
rp += p;
|
|
}
|
|
*rp = '\n';
|
|
lim = rp - oldrp;
|
|
}
|
|
}
|
|
|
|
outcnt += write(outfildes,ln,lim+1);
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
untab(l)
|
|
char l[];
|
|
{
|
|
static char line[BFSBUF];
|
|
register char *q, *s;
|
|
|
|
s = l;
|
|
q = line;
|
|
do {
|
|
if(*s == '\t')
|
|
do *q++ = ' '; while((q-line)%8);
|
|
else *q++ = *s;
|
|
} while(*s++);
|
|
return(line);
|
|
}
|
|
/*
|
|
Function to convert ascii string to integer. Converts
|
|
positive numbers only. Returns -1 if non-numeric
|
|
character encountered.
|
|
*/
|
|
|
|
patoi(b)
|
|
char *b;
|
|
{
|
|
register int i;
|
|
register char *a;
|
|
|
|
a = b;
|
|
i = 0;
|
|
while(*a >= '0' && *a <= '9') i = 10 * i + *a++ - '0';
|
|
|
|
if(*a) return(-1);
|
|
return(i);
|
|
}
|
|
|
|
/*
|
|
Copy first string to second; no overflow checking.
|
|
Returns pointer to null in new string.
|
|
*/
|
|
|
|
char *
|
|
copy(a,b)
|
|
register char *a, *b;
|
|
{
|
|
while(*b++ = *a++);
|
|
return(--b);
|
|
}
|
|
/*
|
|
Compares 2 strings. Returns 1 if equal, 0 if not.
|
|
*/
|
|
|
|
equal(a,b)
|
|
char *a, *b;
|
|
{
|
|
register char *x, *y;
|
|
|
|
x = a;
|
|
y = b;
|
|
while (*x == *y++) if (*x++ == 0) return(1);
|
|
return(0);
|
|
}
|