ref: dc0f1ae1028206a548cc5fad15631d79c212e48a
dir: /sys/src/ape/cmd/sed/sed0.c/
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include "sed.h" struct label *labtab = ltab; char CGMES[] = "sed: Command garbled: %s\n"; char TMMES[] = "sed: Too much text: %s\n"; char LTL[] = "sed: Label too long: %s\n"; char AD0MES[] = "sed: No addresses allowed: %s\n"; char AD1MES[] = "sed: Only one address allowed: %s\n"; uchar bittab[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; void main(int argc, char **argv) { eargc = argc; eargv = (uchar**)argv; badp = &bad; aptr = abuf; hspend = holdsp; lab = labtab + 1; /* 0 reserved for end-pointer */ rep = ptrspace; rep->r1.ad1 = respace; lbend = &linebuf[LBSIZE]; hend = &holdsp[LBSIZE]; lcomend = &genbuf[64]; ptrend = &ptrspace[PTRSIZE]; reend = &respace[RESIZE]; labend = &labtab[LABSIZE]; lnum = 0; pending = 0; depth = 0; spend = linebuf; hspend = holdsp; fcode[0] = stdout; nfiles = 1; lastre = NULL; if(eargc == 1) exit(0); while (--eargc > 0 && (++eargv)[0][0] == '-') switch (eargv[0][1]) { case 'n': nflag++; continue; case 'f': if(eargc-- <= 0) exit(2); if((fin = fopen((char*)(*++eargv), "r")) == NULL) { fprintf(stderr, "sed: Cannot open pattern-file: %s\n", *eargv); exit(2); } fcomp(); fclose(fin); continue; case 'e': eflag++; fcomp(); eflag = 0; continue; case 'g': gflag++; continue; default: fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]); continue; } if(compfl == 0) { eargv--; eargc++; eflag++; fcomp(); eargv++; eargc--; eflag = 0; } if(depth) { fprintf(stderr, "sed: Too many {'s\n"); exit(2); } labtab->address = rep; dechain(); /* abort(); /*DEBUG*/ if(eargc <= 0) execute((uchar *)NULL); else while(--eargc >= 0) { execute(*eargv++); } fclose(stdout); exit(0); } void fcomp(void) { uchar *p, *op, *tp; uchar *address(uchar*); union reptr *pt, *pt1; int i; struct label *lpt; compfl = 1; op = lastre; if(rline(linebuf) < 0) { lastre = op; return; } if(*linebuf == '#') { if(linebuf[1] == 'n') nflag = 1; } else { cp = linebuf; goto comploop; } for(;;) { if(rline(linebuf) < 0) break; cp = linebuf; comploop: /* fprintf(stdout, "cp: %s\n", cp); /*DEBUG*/ while(*cp == ' ' || *cp == '\t') cp++; if(*cp == '\0' || *cp == '#') continue; if(*cp == ';') { cp++; goto comploop; } p = address(rep->r1.ad1); if(p == badp) { fprintf(stderr, CGMES, linebuf); exit(2); } if(p == 0) { p = rep->r1.ad1; rep->r1.ad1 = 0; } else { if(p == rep->r1.ad1) { if(op) rep->r1.ad1 = op; else { fprintf(stderr, "sed: First RE may not be null\n"); exit(2); } } if(*rep->r1.ad1 != CLNUM && *rep->r1.ad1 != CEND) op = rep->r1.ad1; if(*cp == ',' || *cp == ';') { cp++; if((rep->r1.ad2 = p) > reend) { fprintf(stderr, TMMES, linebuf); exit(2); } p = address(rep->r1.ad2); if(p == badp || p == 0) { fprintf(stderr, CGMES, linebuf); exit(2); } if(p == rep->r1.ad2) rep->r1.ad2 = op; else{ if(*rep->r1.ad2 != CLNUM && *rep->r1.ad2 != CEND) op = rep->r1.ad2; } } else rep->r1.ad2 = 0; } if(p > reend) { fprintf(stderr, "sed: Too much text: %s\n", linebuf); exit(2); } while(*cp == ' ' || *cp == '\t') cp++; swit: switch(*cp++) { default: /*fprintf(stderr, "cp = %d; *cp = %o\n", cp - linebuf, *cp);*/ fprintf(stderr, "sed: Unrecognized command: %s\n", linebuf); exit(2); case '!': rep->r1.negfl = 1; goto swit; case '{': rep->r1.command = BCOM; rep->r1.negfl = !(rep->r1.negfl); cmpend[depth++] = &rep->r2.lb1; if(++rep >= ptrend) { fprintf(stderr, "sed: Too many commands: %s\n", linebuf); exit(2); } rep->r1.ad1 = p; if(*cp == '\0') continue; goto comploop; case '}': if(rep->r1.ad1) { fprintf(stderr, AD0MES, linebuf); exit(2); } if(--depth < 0) { fprintf(stderr, "sed: Too many }'s\n"); exit(2); } *cmpend[depth] = rep; rep->r1.ad1 = p; if(*cp == 0) continue; goto comploop; case '=': rep->r1.command = EQCOM; if(rep->r1.ad2) { fprintf(stderr, AD1MES, linebuf); exit(2); } break; case ':': if(rep->r1.ad1) { fprintf(stderr, AD0MES, linebuf); exit(2); } while(*cp++ == ' '); cp--; tp = lab->asc; while((*tp = *cp++) && *tp != ';') if(++tp >= &(lab->asc[8])) { fprintf(stderr, LTL, linebuf); exit(2); } *tp = '\0'; if(*lab->asc == 0) { fprintf(stderr, CGMES, linebuf); exit(2); } if(lpt = search(lab)) { if(lpt->address) { fprintf(stderr, "sed: Duplicate labels: %s\n", linebuf); exit(2); } } else { lab->chain = 0; lpt = lab; if(++lab >= labend) { fprintf(stderr, "sed: Too many labels: %s\n", linebuf); exit(2); } } lpt->address = rep; rep->r1.ad1 = p; continue; case 'a': rep->r1.command = ACOM; if(rep->r1.ad2) { fprintf(stderr, AD1MES, linebuf); exit(2); } if(*cp == '\\') cp++; if(*cp++ != '\n') { fprintf(stderr, CGMES, linebuf); exit(2); } rep->r1.re1 = p; p = text(rep->r1.re1); break; case 'c': rep->r1.command = CCOM; if(*cp == '\\') cp++; if(*cp++ != ('\n')) { fprintf(stderr, CGMES, linebuf); exit(2); } rep->r1.re1 = p; p = text(rep->r1.re1); break; case 'i': rep->r1.command = ICOM; if(rep->r1.ad2) { fprintf(stderr, AD1MES, linebuf); exit(2); } if(*cp == '\\') cp++; if(*cp++ != ('\n')) { fprintf(stderr, CGMES, linebuf); exit(2); } rep->r1.re1 = p; p = text(rep->r1.re1); break; case 'g': rep->r1.command = GCOM; break; case 'G': rep->r1.command = CGCOM; break; case 'h': rep->r1.command = HCOM; break; case 'H': rep->r1.command = CHCOM; break; case 't': rep->r1.command = TCOM; goto jtcommon; case 'b': rep->r1.command = BCOM; jtcommon: while(*cp++ == ' '); cp--; if(*cp == '\0') { if(pt = labtab->chain) { while(pt1 = pt->r2.lb1) pt = pt1; pt->r2.lb1 = rep; } else labtab->chain = rep; break; } tp = lab->asc; while((*tp = *cp++) && *tp != ';') if(++tp >= &(lab->asc[8])) { fprintf(stderr, LTL, linebuf); exit(2); } cp--; *tp = '\0'; if(*lab->asc == 0) { fprintf(stderr, CGMES, linebuf); exit(2); } if(lpt = search(lab)) { if(lpt->address) { rep->r2.lb1 = lpt->address; } else { pt = lpt->chain; while(pt1 = pt->r2.lb1) pt = pt1; pt->r2.lb1 = rep; } } else { lab->chain = rep; lab->address = 0; if(++lab >= labend) { fprintf(stderr, "sed: Too many labels: %s\n", linebuf); exit(2); } } break; case 'n': rep->r1.command = NCOM; break; case 'N': rep->r1.command = CNCOM; break; case 'p': rep->r1.command = PCOM; break; case 'P': rep->r1.command = CPCOM; break; case 'r': rep->r1.command = RCOM; if(rep->r1.ad2) { fprintf(stderr, AD1MES, linebuf); exit(2); } if(*cp++ != ' ') { fprintf(stderr, CGMES, linebuf); exit(2); } rep->r1.re1 = p; p = text(rep->r1.re1); break; case 'd': rep->r1.command = DCOM; break; case 'D': rep->r1.command = CDCOM; rep->r2.lb1 = ptrspace; break; case 'q': rep->r1.command = QCOM; if(rep->r1.ad2) { fprintf(stderr, AD1MES, linebuf); exit(2); } break; case 'l': rep->r1.command = LCOM; break; case 's': rep->r1.command = SCOM; seof = *cp++; rep->r1.re1 = p; p = compile(rep->r1.re1); if(p == badp) { fprintf(stderr, CGMES, linebuf); exit(2); } if(p == rep->r1.re1) { if(op == NULL) { fprintf(stderr, "sed: First RE may not be null.\n"); exit(2); } rep->r1.re1 = op; } else { op = rep->r1.re1; } if((rep->r1.rhs = p) > reend) { fprintf(stderr, TMMES, linebuf); exit(2); } if((p = compsub(rep->r1.rhs)) == badp) { fprintf(stderr, CGMES, linebuf); exit(2); } if(*cp == 'g') { cp++; rep->r1.gfl++; } else if(gflag) rep->r1.gfl++; if(*cp == 'p') { cp++; rep->r1.pfl = 1; } if(*cp == 'P') { cp++; rep->r1.pfl = 2; } if(*cp == 'w') { cp++; if(*cp++ != ' ') { fprintf(stderr, CGMES, linebuf); exit(2); } if(nfiles >= MAXFILES) { fprintf(stderr, "sed: Too many files in w commands 1 \n"); exit(2); } text((uchar*)fname[nfiles]); for(i = nfiles - 1; i >= 0; i--) if(cmp((uchar*)fname[nfiles],(uchar*)fname[i]) == 0) { rep->r1.fcode = fcode[i]; goto done; } if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) { fprintf(stderr, "sed: Cannot open %s\n", fname[nfiles]); exit(2); } fcode[nfiles++] = rep->r1.fcode; } break; case 'w': rep->r1.command = WCOM; if(*cp++ != ' ') { fprintf(stderr, CGMES, linebuf); exit(2); } if(nfiles >= MAXFILES){ fprintf(stderr, "sed: Too many files in w commands 2 \n"); fprintf(stderr, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES); exit(2); } text((uchar*)fname[nfiles]); for(i = nfiles - 1; i >= 0; i--) if(cmp((uchar*)fname[nfiles], (uchar*)fname[i]) == 0) { rep->r1.fcode = fcode[i]; goto done; } if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) { fprintf(stderr, "sed: Cannot create %s\n", fname[nfiles]); exit(2); } fcode[nfiles++] = rep->r1.fcode; break; case 'x': rep->r1.command = XCOM; break; case 'y': rep->r1.command = YCOM; seof = *cp++; rep->r1.re1 = p; p = ycomp(rep->r1.re1); if(p == badp) { fprintf(stderr, CGMES, linebuf); exit(2); } if(p > reend) { fprintf(stderr, TMMES, linebuf); exit(2); } break; } done: if(++rep >= ptrend) { fprintf(stderr, "sed: Too many commands, last: %s\n", linebuf); exit(2); } rep->r1.ad1 = p; if(*cp++ != '\0') { if(cp[-1] == ';') goto comploop; fprintf(stderr, CGMES, linebuf); exit(2); } } } uchar * compsub(uchar *rhsbuf) { uchar *p, *q, *r; p = rhsbuf; q = cp; for(;;) { if((*p = *q++) == '\\') { *++p = *q++; if(*p >= '1' && *p <= '9' && *p > numbra + '0') return(badp); if(*p == 'n') *--p = '\n'; } else if(*p == seof) { *p++ = '\0'; cp = q; return(p); } if(*p++ == '\0') { return(badp); } } } uchar * compile(uchar *expbuf) { int c; uchar *ep, *sp; uchar neg; uchar *lastep, *cstart; int cclcnt; int closed; uchar bracket[NBRA], *bracketp; if(*cp == seof) { cp++; return(expbuf); } ep = expbuf; lastep = 0; bracketp = bracket; closed = numbra = 0; sp = cp; if (*sp == '^') { *ep++ = 1; sp++; } else { *ep++ = 0; } for (;;) { if (ep >= reend) { cp = sp; return(badp); } if((c = *sp++) == seof) { if(bracketp != bracket) { cp = sp; return(badp); } cp = sp; *ep++ = CEOF; return(ep); } if(c != '*') lastep = ep; switch (c) { case '\\': if((c = *sp++) == '(') { if(numbra >= NBRA) { cp = sp; return(badp); } *bracketp++ = numbra; *ep++ = CBRA; *ep++ = numbra++; continue; } if(c == ')') { if(bracketp <= bracket) { cp = sp; return(badp); } *ep++ = CKET; *ep++ = *--bracketp; closed++; continue; } if(c >= '1' && c <= '9') { if((c -= '1') >= closed) return(badp); *ep++ = CBACK; *ep++ = c; continue; } if(c == '\n') { cp = sp; return(badp); } if(c == 'n') { c = '\n'; } goto defchar; case '\0': case '\n': cp = sp; return(badp); case '.': *ep++ = CDOT; continue; case '*': if (lastep == 0) goto defchar; if(*lastep == CKET) { cp = sp; return(badp); } *lastep |= STAR; continue; case '$': if (*sp != seof) goto defchar; *ep++ = CDOL; continue; case '[': if(&ep[33] >= reend) { fprintf(stderr, "sed: RE too long: %s\n", linebuf); exit(2); } *ep++ = CCL; neg = 0; if((c = *sp++) == '^') { neg = 1; c = *sp++; } cstart = sp; do { if(c == '\0') { fprintf(stderr, CGMES, linebuf); exit(2); } if (c=='-' && sp>cstart && *sp!=']') { for (c = sp[-2]; c<*sp; c++) ep[c>>3] |= bittab[c&07]; } if(c == '\\') { switch(c = *sp++) { case 'n': c = '\n'; break; } } ep[c >> 3] |= bittab[c & 07]; } while((c = *sp++) != ']'); if(neg) for(cclcnt = 0; cclcnt < 32; cclcnt++) ep[cclcnt] ^= -1; ep[0] &= 0376; ep += 32; continue; defchar: default: *ep++ = CCHR; *ep++ = c; } } } int rline(uchar *lbuf) { uchar *p, *q; int t; static uchar *saveq; p = lbuf - 1; if(eflag) { if(eflag > 0) { eflag = -1; if(eargc-- <= 0) exit(2); q = *++eargv; while(*++p = *q++) { if(*p == '\\') { if((*++p = *q++) == '\0') { saveq = 0; return(-1); } else continue; } if(*p == '\n') { *p = '\0'; saveq = q; return(1); } } saveq = 0; return(1); } if((q = saveq) == 0) return(-1); while(*++p = *q++) { if(*p == '\\') { if((*++p = *q++) == '0') { saveq = 0; return(-1); } else continue; } if(*p == '\n') { *p = '\0'; saveq = q; return(1); } } saveq = 0; return(1); } while((t = getc(fin)) != EOF) { *++p = t; if(*p == '\\') { t = getc(fin); *++p = t; } else if(*p == '\n') { *p = '\0'; return(1); } } *++p = '\0'; return(-1); } uchar * address(uchar *expbuf) { uchar *rcp; long lno; if(*cp == '$') { cp++; *expbuf++ = CEND; *expbuf++ = CEOF; return(expbuf); } if(*cp == '/') { seof = '/'; cp++; return(compile(expbuf)); } rcp = cp; lno = 0; while(*rcp >= '0' && *rcp <= '9') lno = lno*10 + *rcp++ - '0'; if(rcp > cp) { if(!lno){ fprintf(stderr, "sed: line number 0 is illegal\n"); exit(2); } *expbuf++ = CLNUM; *expbuf++ = lno; *expbuf++ = lno >> 8; *expbuf++ = lno >> 16; *expbuf++ = lno >> 24; *expbuf++ = CEOF; cp = rcp; return(expbuf); } return(0); } int cmp(uchar *a, uchar *b) { uchar *ra, *rb; ra = a - 1; rb = b - 1; while(*++ra == *++rb) if(*ra == '\0') return(0); return(1); } uchar * text(uchar *textbuf) { uchar *p, *q; p = textbuf; q = cp; while(*q == '\t' || *q == ' ') q++; for(;;) { if((*p = *q++) == '\\') *p = *q++; if(*p == '\0') { cp = --q; return(++p); } if(*p == '\n') { while(*q == '\t' || *q == ' ') q++; } p++; } } struct label * search(struct label *ptr) { struct label *rp; rp = labtab; while(rp < ptr) { if(cmp(rp->asc, ptr->asc) == 0) return(rp); rp++; } return(0); } void dechain(void) { struct label *lptr; union reptr *rptr, *trptr; for(lptr = labtab; lptr < lab; lptr++) { if(lptr->address == 0) { fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc); exit(2); } if(lptr->chain) { rptr = lptr->chain; while(trptr = rptr->r2.lb1) { rptr->r2.lb1 = lptr->address; rptr = trptr; } rptr->r2.lb1 = lptr->address; } } } uchar * ycomp(uchar *expbuf) { uchar *ep, *tsp; int c; uchar *sp; ep = expbuf; sp = cp; for(tsp = cp; *tsp != seof; tsp++) { if(*tsp == '\\') tsp++; if(*tsp == '\n' || *tsp == '\0') return(badp); } tsp++; while((c = *sp++) != seof) { if(c == '\\' && *sp == 'n') { sp++; c = '\n'; } if((ep[c] = *tsp++) == '\\' && *tsp == 'n') { ep[c] = '\n'; tsp++; } if(ep[c] == seof || ep[c] == '\0') return(badp); } if(*tsp != seof) return(badp); cp = ++tsp; for(c = 0; c<0400; c++) if(ep[c] == 0) ep[c] = c; return(ep + 0400); }