/* * Editor */ #include <ansi.h> #include <posix.h> #define NULL 0 #define FNSIZE 128 #define LBSIZE 4096 #define BLKSIZE 4096 #define NBLK 2047 #define ESIZE 256 #define GBSIZE 256 #define NBRA 10 #ifndef EOF #define EOF -1 #endif /* EOF */ #define KSIZE 9 #define CBRA 1 #define CCHR 2 #define CDOT 4 #define CCL 6 #define NCCL 8 #define CDOL 10 #define CEFIL 11 #define CKET 12 #define CBACK 14 #define CCIRC 15 #define STAR 01 char Q[] = ""; char T[] = "TMP"; char hex[] = "0123456789abcdef"; #define READ 0 #define WRITE 1 int peekc; int lastc; char savedfile[FNSIZE]; char file[FNSIZE]; short linebuf[LBSIZE]; short rhsbuf[LBSIZE/2]; short expbuf[ESIZE+4]; short genbuf[LBSIZE]; int *zero; int *dot; int *dol; int given; int *addr1; int *addr2; char iobuf[LBSIZE]; long count; char *nextip; short *linebp; int ninbuf; int io; int pflag; void (*oldhup)(int); void (*oldquit)(int); int vflag = 1; int oflag; int listf; int listn; int col; char *globp; int tfile = -1; int tline; char *tfname; short *loc1; short *loc2; unsigned char ibuff[BLKSIZE]; int iblock = -1; unsigned char obuff[BLKSIZE]; int oblock = -1; int ichanged; int nleft; char WRERR[] = "WRITE ERROR"; int names[26]; int anymarks; short *braslist[NBRA]; short *braelist[NBRA]; int nbra; int subnewa; int subolda; int fchange; int wrapp; int bpagesize = 20; unsigned nlall = 128; jmp_buf savej; int* address(void); int getchr(void); short* getline(int); unsigned char *getblock(int, int); short* place(short*, short*, short*); void commands(void); void quit(void); void printcom(void); void error(char*); void nonzero(void); void newline(void); void rdelete(int*, int*); void setnoaddr(void); void init(void); void putst(char*); void putshst(short*); void squeeze(int); void setwide(void); void putfile(void); void putd(void); void callunix(void); void dosub(void); void reverse(int*, int*); void compile(int); void putchr(int); int append(int(*)(void), int*); void add(int); void browse(void); void filename(int); void global(int); void join(void); void move(int); void exfile(void); void substitute(int); int getfile(void); int gettty(void); int compsub(void); int getsub(void); int getcopy(void); int getnum(void); int execute(int*); int putline(void); int advance(short*, short*); int cclass(short*, int, int); int backref(int, short*); void onintr(int); void onquit(int); void onhup(int); main(int argc, char *argv[]) { char *p1, *p2; void (*oldintr)(int); oldquit = signal(SIGQUIT, SIG_IGN); oldhup = signal(SIGHUP, SIG_IGN); oldintr = signal(SIGINT, SIG_IGN); if (signal(SIGTERM, SIG_IGN) == SIG_DFL) signal(SIGTERM, onquit); argv++; while (argc > 1 && **argv=='-') { switch((*argv)[1]) { case '\0': vflag = 0; break; case 'q': signal(SIGQUIT, SIG_DFL); vflag = 1; break; case 'o': oflag = 1; break; } argv++; argc--; } if (oflag) { p1 = "/dev/stdout"; p2 = savedfile; while (*p2++ = *p1++) ; globp = "a"; } else if (*argv) { p1 = *argv; p2 = savedfile; while (*p2++ = *p1++) if (p2 >= &savedfile[sizeof(savedfile)]) p2--; globp = "r"; } zero = (int*)malloc(nlall*sizeof(int)); tfname = tmpnam(0); init(); if (((int)oldintr & 01) == 0) signal(SIGINT, onintr); if (((int)oldhup & 01) == 0) signal(SIGHUP, onhup); setjmp(savej); commands(); quit(); } void commands(void) { int *a1, c, temp; char lastsep; 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(); if ((c = getchr()) < '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, O_RDONLY)) < 0) { lastc = '\n'; error(file); } setwide(); squeeze(0); ninbuf = 0; c = zero != dol; append(getfile, addr2); exfile(); 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); if ((temp = getchr()) != 'q' && temp != 'Q') { peekc = temp; temp = 0; } filename(c); if(!wrapp || ((io = open(file, O_WRONLY)) == -1) || ((lseek(io, 0L, SEEK_END)) == -1)) if ((io = creat(file, 0666)) == -1) error(file); wrapp = 0; if (dol > zero) putfile(); exfile(); 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 ('0'<=c && c<='9') { peekc = c; if (!opcnt) a = zero; a += sign*getnum(); } else switch (c) { case '$': a = dol; /* fall through */ case '.': if (opcnt) error(Q); break; case '\'': c = getchr(); if (opcnt || c<'a' || 'z'<c) error(Q); a = zero; do a++; while (a<=dol && names[c-'a']!=(*a&~01)); break; case '?': sign = -sign; /* fall through */ case '/': compile(c); b = a; for (;;) { a += sign; if (a<=zero) a = dol; if (a>dol) a = zero; if (execute(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; } getnum(void) { int r, c; r = 0; while ((c=getchr())>='0' && c<='9') 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; if ((c = getchr()) == '\n' || c == EOF) return; if (c=='p' || c=='l' || c=='n') { pflag++; if (c=='l') listf++; else if (c=='n') listn++; if (getchr()=='\n') return; } error(Q); } void filename(int comm) { char *p1, *p2; 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)-1] || c==' ' || c==EOF) error(Q); *p1++ = c; } while ((c = getchr()) != '\n'); *p1++ = 0; if (savedfile[0]==0 || comm=='e' || comm=='f') { p1 = savedfile; p2 = file; while (*p1++ = *p2++) ; } } void exfile(void) { close(io); io = -1; if (vflag) { putd(); putchr('\n'); } } void onintr(int sig) { #pragma ref sig signal(SIGINT, onintr); putchr('\n'); lastc = '\n'; error(Q); } void onhup(int sig) { #pragma ref sig signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); if (dol > zero) { addr1 = zero+1; addr2 = dol; io = creat("ed.hup", 0600); if (io > 0) putfile(); } fchange = 0; quit(); } void error(char *s) { int c; wrapp = 0; listf = 0; listn = 0; count = 0; lseek(0, 0, SEEK_END); pflag = 0; if (globp) lastc = '\n'; globp = 0; peekc = lastc; if(lastc) while ((c = getchr()) != '\n' && c != EOF) ; if (io > 0) { close(io); io = -1; } putchr('?'); putst(s); longjmp(savej, 1); } getchr(void) { unsigned char c; if (lastc = peekc) { peekc = 0; return lastc; } if (globp) { if ((lastc = *globp++) != 0) return lastc; globp = 0; return EOF; } if (read(0, (char *)&c, 1) <= 0) return lastc = EOF; lastc = c; return lastc; } gety(void) { int c; char *gf; short *p; p = linebuf; gf = globp; while ((c = getchr()) != '\n') { if (c==EOF) { if (gf) peekc = c; return c; } if (c == 0) continue; *p++ = c; if (p >= &linebuf[LBSIZE-2]) error(Q); } *p = 0; return 0; } gettty(void) { int rc; if (rc = gety()) return rc; if (linebuf[0]=='.' && linebuf[1]==0) return EOF; return 0; } getfile(void) { int c; char *fp; short *lp; lp = linebuf; fp = nextip; do { if (--ninbuf < 0) { if ((ninbuf = read(io, iobuf, LBSIZE)-1) < 0) if (lp>linebuf) { putst("'\\n' appended"); *iobuf = '\n'; } else return EOF; fp = iobuf; } c = *fp++; if (c == '\0') continue; if (lp >= &linebuf[LBSIZE]) { lastc = '\n'; error(Q); } *lp++ = c; count++; } while (c != '\n'); *--lp = 0; nextip = fp; return 0; } void putfile(void) { int *a1, n, nib; char *fp; short *lp; nib = BLKSIZE; fp = iobuf; a1 = addr1; do { lp = getline(*a1++); for (;;) { if (--nib < 0) { n = fp-iobuf; if(write(io, iobuf, n) != n) { putst(WRERR); error(Q); } nib = BLKSIZE-1; fp = iobuf; } count++; if ((*fp++ = *lp++) == 0) { fp[-1] = '\n'; break; } } } while (a1 <= addr2); n = fp-iobuf; if(write(io, iobuf, n) != n) { putst(WRERR); error(Q); } } append(int (*f)(void), int *a) { int *a1, *a2, *rdot, nline, tl; nline = 0; dot = a; while ((*f)() == 0) { if ((dol-zero)+1 >= nlall) { int *ozero = zero; nlall += 1024; if ((zero = (int *)realloc((char *)zero, nlall*sizeof(int)))==NULL) { error("MEM?"); onhup(0); } dot += zero - ozero; dol += zero - ozero; } 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 bformat, bnum; /* 0 */ forward = 1; if((peekc=getchr()) != '\n'){ if (peekc=='-' || peekc=='+') { if(peekc == '-') forward=0; getchr(); } if((n=getnum()) > 0) bpagesize = n; } newline(); if (pflag) { bformat = listf; bnum = listn; } else { listf = bformat; listn = bnum; } if (forward) { addr1 = addr2; if((addr2+=bpagesize) > dol) addr2 = dol; } else { if((addr1=addr2-bpagesize) <= zero) addr1 = zero+1; } printcom(); } void callunix(void) { pid_t pid, rpid; void (*savint)(int); int retcode; setnoaddr(); if ((pid = fork()) == 0) { signal(SIGHUP, oldhup); signal(SIGQUIT, oldquit); execl("/bin/sh", "sh", "-t", 0); exit(0100); } savint = signal(SIGINT, SIG_IGN); while ((rpid = wait(&retcode)) != pid && rpid != -1) ; signal(SIGINT, savint); if (vflag) { putst("!"); } } void quit(void) { if (vflag && fchange && dol!=zero) { fchange = 0; error(Q); } remove(tfname); exit(0); } void onquit(int sig) { #pragma ref 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; } short* getline(int tl) { unsigned char *bp; short *lp; int nl; lp = linebuf; bp = getblock(tl, READ); nl = nleft; tl &= ~((BLKSIZE/2)-1); while (*lp++ = *bp++) if (--nl == 0) { bp = getblock(tl+=(BLKSIZE/2), READ); nl = nleft; } return linebuf; } putline(void) { unsigned char *bp; short *lp; int nl, tl; fchange = 1; lp = linebuf; tl = tline; bp = getblock(tl, WRITE); nl = nleft; tl &= ~((BLKSIZE/2)-1); while (*bp = *lp++) { if (*bp++ == '\n') { *--bp = 0; linebp = lp; break; } if (--nl == 0) { bp = getblock(tl+=(BLKSIZE/2), WRITE); nl = nleft; } } nl = tline; tline += (((lp-linebuf)+03)>>1)&077776; return nl; } void blkio(int b, unsigned char *buf, int (*iofcn)(int, char *, unsigned)) { lseek(tfile, b*BLKSIZE, SEEK_SET); if ((*iofcn)(tfile, (char *)buf, BLKSIZE) != BLKSIZE) { error(T); } } unsigned char * getblock(int atl, int iof) { int bno, off; bno = (atl/(BLKSIZE/2)); off = (atl<<1) & (BLKSIZE-1) & ~03; if (bno >= NBLK) { lastc = '\n'; error(T); } nleft = BLKSIZE - off; if (bno==iblock) { ichanged |= iof; return ibuff+off; } if (bno==oblock) return obuff+off; if (iof==READ) { if (ichanged) blkio(iblock, ibuff, write); ichanged = 0; iblock = bno; blkio(bno, ibuff, read); return ibuff+off; } if (oblock>=0) blkio(oblock, obuff, write); oblock = bno; return 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; close(creat(tfname, 0600)); tfile = open(tfname, O_RDWR); dot = dol = zero; } void global(int k) { char *gp, globuf[GBSIZE]; int c, *a1; if (globp) error(Q); setwide(); squeeze(dol>zero); if ((c=getchr())=='\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 && execute(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) { short *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 (execute(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 (execute((int*)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); nl += zero-ozero; a1 += nl; addr2 += nl; } } } if (inglob==0) error(Q); } compsub(void) { int seof, c; short *p; if ((seof = getchr()) == '\n' || seof == ' ') error(Q); compile(seof); p = rhsbuf; for (;;) { c = getchr(); if (c=='\\') c = getchr() | 0x100; if (c=='\n') { if (globp && globp[0]) /* last '\n' does not count */ c |= 0x100; else { peekc = c; pflag++; break; } } if (c == seof) break; *p++ = c; if (p >= &rhsbuf[LBSIZE/2]) error(Q); } *p = 0; if ((peekc = getchr()) == 'g') { peekc = 0; newline(); return 1; } newline(); return 0; } getsub(void) { short *p1, *p2; p1 = linebuf; if ((p2 = linebp) == 0) return EOF; while (*p1++ = *p2++) ; linebp = 0; return 0; } void dosub(void) { short *lp, *sp, *rp; int c; lp = linebuf; sp = genbuf; rp = rhsbuf; while (lp < loc1) *sp++ = *lp++; while (c = *rp++) { if (c=='&') { sp = place(sp, loc1, loc2); continue; } else if (c&0x100 && (c &= 0xFF) >='1' && c < nbra+'1') { sp = place(sp, braslist[c-'1'], braelist[c-'1']); continue; } *sp++ = c&0xFF; 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++) ; } short* place(short *sp, short *l1, short *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; } } getcopy(void) { if (addr1 > addr2) return EOF; getline(*addr1++); return 0; } void compile(int eof) { int c, cclcnt; short *ep, *lastep, bracket[NBRA], *bracketp; ep = expbuf; bracketp = bracket; if ((c = getchr()) == '\n') { peekc = c; c = eof; } if (c == eof) { if (*ep==0) error(Q); return; } nbra = 0; if (c=='^') { c = getchr(); *ep++ = CCIRC; } peekc = c; lastep = 0; for (;;) { if (ep >= &expbuf[ESIZE]) goto cerror; c = getchr(); if (c == '\n') { peekc = c; c = eof; } if (c==eof) { if (bracketp != bracket) goto cerror; *ep = CEFIL; return; } if (c!='*') lastep = ep; switch (c) { case '\\': if ((c = getchr())=='(') { if (nbra >= NBRA) goto cerror; *bracketp++ = nbra; *ep++ = CBRA; *ep++ = nbra++; continue; } if (c == ')') { if (bracketp <= bracket) goto cerror; *ep++ = CKET; *ep++ = *--bracketp; continue; } if (c>='1' && c<'1'+NBRA) { *ep++ = CBACK; *ep++ = c-'1'; continue; } *ep++ = CCHR; if (c=='\n') goto cerror; *ep++ = c; continue; case '.': *ep++ = CDOT; continue; case '\n': goto cerror; case '*': if (lastep==0 || *lastep==CBRA || *lastep==CKET) goto defchar; *lastep |= STAR; continue; case '$': if ((peekc=getchr()) != eof && peekc!='\n') goto defchar; *ep++ = CDOL; continue; case '[': *ep++ = CCL; *ep++ = 0; cclcnt = 1; if ((c=getchr()) == '^') { c = getchr(); ep[-2] = NCCL; } do { if (c=='\n') goto cerror; if (c=='-' && ep[-1]!=0) { if ((c=getchr())==']') { *ep++ = '-'; cclcnt++; break; } while (ep[-1]<c) { *ep = ep[-1]+1; ep++; cclcnt++; if (ep>=&expbuf[ESIZE]) goto cerror; } } *ep++ = c; cclcnt++; if (ep >= &expbuf[ESIZE]) goto cerror; } while ((c = getchr()) != ']'); lastep[1] = cclcnt; continue; defchar: default: *ep++ = CCHR; *ep++ = c; } } cerror: expbuf[0] = 0; nbra = 0; error(Q); } execute(int *addr) { short *p1, *p2; int c; for (c=0; c<NBRA; c++) { braslist[c] = 0; braelist[c] = 0; } p2 = expbuf; if (addr == (int*)0) { if (*p2 == CCIRC) return 0; p1 = loc2; } else { if (addr == zero) return 0; p1 = getline(*addr); } if (*p2 == CCIRC) { loc1 = p1; return advance(p1, p2+1); } /* fast check for first character */ if (*p2 == CCHR) { c = p2[1]; do { if (*p1!=c) continue; if (advance(p1, p2)) { loc1 = p1; return 1; } } while (*p1++); return 0; } /* regular algorithm */ do { if (advance(p1, p2)) { loc1 = p1; return 1; } } while (*p1++); return 0; } advance(short *lp, short *ep) { short *curlp; int i; for (;;) switch (*ep++) { case CCHR: if (*ep++ == *lp++) continue; return 0; case CDOT: if (*lp++) continue; return 0; case CDOL: if (*lp==0) continue; return 0; case CEFIL: loc2 = lp; return 1; case CCL: if (cclass(ep, *lp++, 1)) { ep += *ep; continue; } return 0; case NCCL: if (cclass(ep, *lp++, 0)) { ep += *ep; continue; } return 0; case CBRA: braslist[*ep++] = lp; continue; case CKET: braelist[*ep++] = lp; continue; case CBACK: if (braelist[i = *ep++]==0) error(Q); if (backref(i, lp)) { lp += braelist[i] - braslist[i]; continue; } return 0; case CBACK|STAR: if (braelist[i = *ep++] == 0) error(Q); curlp = lp; while (backref(i, lp)) lp += braelist[i] - braslist[i]; while (lp >= curlp) { if (advance(lp, ep)) return 1; lp -= braelist[i] - braslist[i]; } continue; case CDOT|STAR: curlp = lp; while (*lp++) ; goto star; case CCHR|STAR: curlp = lp; while (*lp++ == *ep) ; ep++; goto star; case CCL|STAR: case NCCL|STAR: curlp = lp; while (cclass(ep, *lp++, ep[-1]==(CCL|STAR))) ; ep += *ep; goto star; star: do { lp--; if (advance(lp, ep)) return 1; } while (lp > curlp); return 0; default: error(Q); } } backref(int i, short *lp) { short *bp; bp = braslist[i]; while (*bp++ == *lp++) if (bp >= braelist[i]) return 1; return 0; } cclass(short *set, int c, int af) { int n; if (c==0) return 0; n = *set++; while (--n) if (*set++ == c) return af; return !af; } void putd(void) { int r; r = count%10; count /= 10; if (count) putd(); putchr(r + '0'); } void putst(char *sp) { col = 0; while (*sp) putchr(*sp++); putchr('\n'); } void putshst(short *sp) { col = 0; while (*sp) putchr(*sp++); putchr('\n'); } char line[70]; char *linp = line; void putchr(int ac) { char *lp; int c; lp = linp; c = ac; if (listf) { if (c=='\n') { if (linp!=line && linp[-1]==' ') { *lp++ = '\\'; *lp++ = 'n'; } } else { if (col > (72-4-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>>4]; c = hex[c&0xF]; col += 3; } } } *lp++ = c; if(c == '\n' || lp >= &line[64]) { linp = line; write(oflag?2:1, line, lp-line); return; } linp = lp; }