/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984 AT&T */ /* All Rights Reserved */ #include #include #include "sed.h" #define NWFILES 11 /* 10 plus one for standard output */ FILE *fin; FILE *fcode[NWFILES]; char *lastre; char sseof; union reptr *ptrend; int eflag; extern int nbra; char linebuf[LBSIZE+1]; int gflag; int nlno; char *fname[NWFILES]; int nfiles; union reptr ptrspace[PTRSIZE]; union reptr *rep; char *cp; char respace[RESIZE]; struct label ltab[LABSIZE]; struct label *lab; struct label *labend; int depth; int eargc; char **eargv; union reptr **cmpend[DEPTH]; #define CCEOF 22 struct label *labtab = ltab; char ETMES[] = "Extra text at end of command: %s"; char SMMES[] = "Space missing before filename: %s"; char TMMES[] = "Too much command text: %s"; char LTL[] = "Label too long: %s"; char AD0MES[] = "No addresses allowed: %s"; char AD1MES[] = "Only one address allowed: %s"; char TOOBIG[] = "Suffix too large - 512 max: %s"; extern int sed; /* IMPORTANT flag !!! */ extern char *comple(); extern char *malloc(); static void dechain(void); static void fcomp(void); int main(int argc, char *argv[]) { int flag_found = 0; sed = 1; eargc = argc; eargv = argv; aptr = abuf; lab = labtab + 1; /* 0 reserved for end-pointer */ rep = ptrspace; rep->r1.ad1 = respace; lcomend = &genbuf[71]; ptrend = &ptrspace[PTRSIZE]; labend = &labtab[LABSIZE]; lnum = 0; pending = 0; depth = 0; spend = linebuf; hspend = holdsp; /* Avoid "bus error" under "H" cmd. */ fcode[0] = stdout; fname[0] = ""; nfiles = 1; if(eargc == 1) exit(0); setlocale(LC_ALL, ""); /* get locale environment */ while (--eargc > 0 && (++eargv)[0][0] == '-') switch (eargv[0][1]) { case 'n': nflag++; continue; case 'f': flag_found = 1; if(eargc-- <= 0) exit(2); if((fin = fopen(*++eargv, "r")) == NULL) { (void) fprintf(stderr, "sed: "); perror(*eargv); exit(2); } fcomp(); (void) fclose(fin); continue; case 'e': flag_found = 1; eflag++; fcomp(); eflag = 0; continue; case 'g': gflag++; continue; default: (void) fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]); exit(2); } if(rep == ptrspace && !flag_found) { eargv--; eargc++; eflag++; fcomp(); eargv++; eargc--; eflag = 0; } if(depth) comperr("Too many {'s"); labtab->address = rep; dechain(); if(eargc <= 0) execute((char *)NULL); else while(--eargc >= 0) { execute(*eargv++); } (void) fclose(stdout); return (0); } static void fcomp(void) { char *p, *op, *tp; char *address(); union reptr *pt, *pt1; int i, ii; struct label *lpt; char fnamebuf[MAXPATHLEN]; op = lastre; if(rline(linebuf, &linebuf[LBSIZE+1]) < 0) return; if(*linebuf == '#') { if(linebuf[1] == 'n') nflag = 1; } else { cp = linebuf; goto comploop; } for(;;) { if(rline(linebuf, &linebuf[LBSIZE+1]) < 0) break; cp = linebuf; comploop: /* (void) fprintf(stderr, "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 == rep->r1.ad1) { if(op) rep->r1.ad1 = op; else comperr("First RE may not be null: %s"); } else if(p == 0) { p = rep->r1.ad1; rep->r1.ad1 = 0; } else { op = rep->r1.ad1; if(*cp == ',' || *cp == ';') { cp++; rep->r1.ad2 = p; p = address(rep->r1.ad2); if(p == 0) comperr("Illegal line number: %s"); if(p == rep->r1.ad2) rep->r1.ad2 = op; else op = rep->r1.ad2; } else rep->r1.ad2 = 0; } if(p > &respace[RESIZE-1]) comperr(TMMES); while(*cp == ' ' || *cp == '\t') cp++; swit: switch(*cp++) { default: comperr("Unrecognized command: %s"); 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) comperr("Too many commands: %s"); rep->r1.ad1 = p; if(*cp == '\0') continue; goto comploop; case '}': if(rep->r1.ad1) comperr(AD0MES); if(--depth < 0) comperr("Too many }'s"); *cmpend[depth] = rep; rep->r1.ad1 = p; continue; case '=': rep->r1.command = EQCOM; if(rep->r1.ad2) comperr(AD1MES); break; case ':': if(rep->r1.ad1) comperr(AD0MES); while(*cp++ == ' '); cp--; tp = lab->asc; while((*tp++ = *cp++)) if(tp >= &(lab->asc[9])) comperr(LTL); *--tp = '\0'; if(lpt = search(lab)) { if(lpt->address) comperr("Duplicate labels: %s"); } else { lab->chain = 0; lpt = lab; if(++lab >= labend) comperr("Too many labels: %s"); } lpt->address = rep; rep->r1.ad1 = p; continue; case 'a': rep->r1.command = ACOM; if(rep->r1.ad2) comperr(AD1MES); if(*cp == '\\') cp++; if(*cp++ != '\n') comperr(ETMES); rep->r1.re1 = p; if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL) comperr(TMMES); break; case 'c': rep->r1.command = CCOM; if(*cp == '\\') cp++; if(*cp++ != ('\n')) comperr(ETMES); rep->r1.re1 = p; if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL) comperr(TMMES); break; case 'i': rep->r1.command = ICOM; if(rep->r1.ad2) comperr(AD1MES); if(*cp == '\\') cp++; if(*cp++ != ('\n')) comperr(ETMES); rep->r1.re1 = p; if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL) comperr(TMMES); 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++)) if(tp >= &(lab->asc[9])) comperr(LTL); cp--; *--tp = '\0'; 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) comperr("Too many labels: %s"); } 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) comperr(AD1MES); if(*cp++ != ' ') comperr(SMMES); rep->r1.re1 = p; if ((p = text(rep->r1.re1, &respace[RESIZE-1])) == NULL) comperr(TMMES); 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) comperr(AD1MES); break; case 'l': rep->r1.command = LCOM; break; case 's': rep->r1.command = SCOM; sseof = *cp++; rep->r1.re1 = p; p = comple((char *) 0, rep->r1.re1, &respace[RESIZE-1], sseof); if(p == rep->r1.re1) { if(op) rep->r1.re1 = op; else comperr("First RE may not be null: %s"); } else op = rep->r1.re1; rep->r1.rhs = p; p = compsub(rep->r1.rhs); if(*cp == 'g') { cp++; rep->r1.gfl = 999; } else if(gflag) rep->r1.gfl = 999; if(*cp >= '1' && *cp <= '9') {i = *cp - '0'; cp++; while(1) {ii = *cp; if(ii < '0' || ii > '9') break; i = i*10 + ii - '0'; if(i > 512) comperr(TOOBIG); cp++; } rep->r1.gfl = i; } if(*cp == 'p') { cp++; rep->r1.pfl = 1; } if(*cp == 'P') { cp++; rep->r1.pfl = 2; } if(*cp == 'w') { cp++; if(*cp++ != ' ') comperr(SMMES); if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL) comperr("File name too long: %s"); for(i = nfiles - 1; i >= 0; i--) if(strcmp(fnamebuf,fname[i]) == 0) { rep->r1.fcode = fcode[i]; goto done; } if(nfiles >= NWFILES) comperr("Too many files in w commands: %s"); i = strlen(fnamebuf) + 1; if ((fname[nfiles] = malloc((unsigned)i)) == NULL) { (void) fprintf(stderr, "sed: Out of memory\n"); exit(2); } (void) strcpy(fname[nfiles], fnamebuf); if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) { (void) fprintf(stderr, "sed: Cannot open "); perror(fname[nfiles]); exit(2); } fcode[nfiles++] = rep->r1.fcode; } break; case 'w': rep->r1.command = WCOM; if(*cp++ != ' ') comperr(SMMES); if (text(fnamebuf, &fnamebuf[MAXPATHLEN]) == NULL) comperr("File name too long: %s"); for(i = nfiles - 1; i >= 0; i--) if(strcmp(fnamebuf, fname[i]) == 0) { rep->r1.fcode = fcode[i]; goto done; } if(nfiles >= NWFILES) comperr("Too many files in w commands: %s"); i = strlen(fnamebuf) + 1; if ((fname[nfiles] = malloc((unsigned)i)) == NULL) { (void) fprintf(stderr, "sed: Out of memory\n"); exit(2); } (void) strcpy(fname[nfiles], fnamebuf); if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) { (void) fprintf(stderr, "sed: Cannot create "); perror(fname[nfiles]); exit(2); } fcode[nfiles++] = rep->r1.fcode; break; case 'x': rep->r1.command = XCOM; break; case 'y': rep->r1.command = YCOM; sseof = *cp++; rep->r1.re1 = p; p = ycomp(rep->r1.re1); break; } done: if(++rep >= ptrend) comperr("Too many commands, last: %s"); rep->r1.ad1 = p; if(*cp++ != '\0') { if(cp[-1] == ';') goto comploop; comperr(ETMES); } } rep->r1.command = 0; lastre = op; } char *compsub(rhsbuf) char *rhsbuf; { char *p, *q; p = rhsbuf; q = cp; for(;;) { if(p > &respace[RESIZE-1]) comperr(TMMES); if((*p = *q++) == '\\') { p++; if(p > &respace[RESIZE-1]) comperr(TMMES); *p = *q++; if(*p > nbra + '0' && *p <= '9') comperr("``\\digit'' out of range: %s"); p++; continue; } if(*p == sseof) { *p++ = '\0'; cp = q; return(p); } if(*p++ == '\0') comperr("Ending delimiter missing on substitution: %s"); } } int rline(lbuf, lbend) char *lbuf; char *lbend; { char *p, *q; int t; static char *saveq; p = lbuf; if(eflag) { if(eflag > 0) { eflag = -1; if(--eargc <= 0) exit(2); q = *++eargv; while((t = *q++) != '\0') { if(t == '\n') { saveq = q; goto out1; } if (p < lbend) *p++ = t; if(t == '\\') { if((t = *q++) == '\0') { saveq = 0; return(-1); } if (p < lbend) *p++ = t; } } saveq = 0; out1: if (p == lbend) comperr("Command line too long"); *p = '\0'; return(1); } if((q = saveq) == 0) return(-1); while((t = *q++) != '\0') { if(t == '\n') { saveq = q; goto out2; } if(p < lbend) *p++ = t; if(t == '\\') { if((t = *q++) == '\0') { saveq = 0; return(-1); } if (p < lbend) *p++ = t; } } saveq = 0; out2: if (p == lbend) comperr("Command line too long"); *p = '\0'; return(1); } while((t = getc(fin)) != EOF) { if(t == '\n') { if (p == lbend) comperr("Command line too long"); *p = '\0'; return(1); } if (p < lbend) *p++ = t; if(t == '\\') { if((t = getc(fin)) == EOF) break; if(p < lbend) *p++ = t; } } if(ferror(fin)) { perror("sed: Error reading pattern file"); exit(2); } return(-1); } char *address(expbuf) char *expbuf; { char *rcp; long long lno; if(*cp == '$') { if (expbuf > &respace[RESIZE-2]) comperr(TMMES); cp++; *expbuf++ = CEND; *expbuf++ = CCEOF; return(expbuf); } if (*cp == '/' || *cp == '\\' ) { if ( *cp == '\\' ) cp++; sseof = *cp++; return(comple((char *) 0, expbuf, &respace[RESIZE-1], sseof)); } rcp = cp; lno = 0; while(*rcp >= '0' && *rcp <= '9') lno = lno*10 + *rcp++ - '0'; if(rcp > cp) { if (expbuf > &respace[RESIZE-3]) comperr(TMMES); *expbuf++ = CLNUM; *expbuf++ = nlno; tlno[nlno++] = lno; if(nlno >= NLINES) comperr("Too many line numbers: %s"); *expbuf++ = CCEOF; cp = rcp; return(expbuf); } return(0); } char *text(textbuf, tbend) char *textbuf; char *tbend; { char *p, *q; p = textbuf; q = cp; #ifndef S5EMUL /* * Strip off indentation from text to be inserted. */ while(*q == '\t' || *q == ' ') q++; #endif for(;;) { if(p > tbend) return(NULL); /* overflowed the buffer */ if((*p = *q++) == '\\') *p = *q++; if(*p == '\0') { cp = --q; return(++p); } #ifndef S5EMUL /* * Strip off indentation from text to be inserted. */ if(*p == '\n') { while(*q == '\t' || *q == ' ') q++; } #endif p++; } } struct label *search(ptr) struct label *ptr; { struct label *rp; rp = labtab; while(rp < ptr) { if(strcmp(rp->asc, ptr->asc) == 0) return(rp); rp++; } return(0); } static void dechain(void) { struct label *lptr; union reptr *rptr, *trptr; for(lptr = labtab; lptr < lab; lptr++) { if(lptr->address == 0) { (void) 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; } } } char *ycomp(expbuf) char *expbuf; { char c; char *ep, *tsp; int i; char *sp; ep = expbuf; if(ep + 0377 > &respace[RESIZE-1]) comperr(TMMES); sp = cp; for(tsp = cp; (c = *tsp) != sseof; tsp++) { if(c == '\\') tsp++; if(c == '\0' || c == '\n') comperr("Ending delimiter missing on string: %s"); } tsp++; while((c = *sp++) != sseof) { c &= 0377; if(c == '\\' && *sp == 'n') { sp++; c = '\n'; } if((ep[c] = *tsp++) == '\\' && *tsp == 'n') { ep[c] = '\n'; tsp++; } if(ep[c] == sseof || ep[c] == '\0') comperr("Transform strings not the same size: %s"); } if(*tsp != sseof) { if(*tsp == '\0') comperr("Ending delimiter missing on string: %s"); else comperr("Transform strings not the same size: %s"); } cp = ++tsp; for(i = 0; i < 0400; i++) if(ep[i] == 0) ep[i] = i; return(ep + 0400); } void comperr(char *msg) { (void) fprintf(stderr, "sed: "); (void) fprintf(stderr, msg, linebuf); (void) putc('\n', stderr); exit(2); }