| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License, Version 1.0 only |
| * (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 2005 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| /* Copyright (c) 1984 AT&T */ |
| /* All Rights Reserved */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include "sed.h" |
| #include <regexp.h> |
| |
| union reptr *abuf[ABUFSIZE+1]; |
| union reptr **aptr; |
| char ibuf[BUFSIZ]; |
| char *cbp; |
| char *ebp; |
| char genbuf[LBSIZE+1]; |
| char *lcomend; |
| int dolflag; |
| int sflag; |
| int jflag; |
| int delflag; |
| long long lnum; |
| char holdsp[LBSIZE+1]; |
| char *spend; |
| char *hspend; |
| int nflag; |
| long long tlno[NLINES]; |
| int f; |
| char *ifname; |
| int numpass; |
| union reptr *pending; |
| char *trans[040] = { |
| "\\01", |
| "\\02", |
| "\\03", |
| "\\04", |
| "\\05", |
| "\\06", |
| "\\07", |
| "-<", |
| "->", |
| "\n", |
| "\\13", |
| "\\14", |
| "\\15", |
| "\\16", |
| "\\17", |
| "\\20", |
| "\\21", |
| "\\22", |
| "\\23", |
| "\\24", |
| "\\25", |
| "\\26", |
| "\\27", |
| "\\30", |
| "\\31", |
| "\\32", |
| "\\33", |
| "\\34", |
| "\\35", |
| "\\36", |
| "\\37" |
| }; |
| char rub[] = {"\\177"}; |
| |
| extern char TMMES[]; |
| |
| static int match(char *expbuf, int gf); |
| static int substitute(union reptr *ipc); |
| static void dosub(char *rhsbuf, int n); |
| static void command(union reptr *ipc); |
| static void arout(void); |
| |
| void |
| execute(char *file) |
| { |
| char *p1, *p2; |
| union reptr *ipc; |
| int c; |
| char *execp; |
| |
| if (file) { |
| if ((f = open(file, 0)) < 0) { |
| (void) fprintf(stderr, "sed: "); |
| perror(file); |
| } |
| ifname = file; |
| } else { |
| f = 0; |
| ifname = "standard input"; |
| } |
| |
| ebp = ibuf; |
| cbp = ibuf; |
| |
| if(pending) { |
| ipc = pending; |
| pending = 0; |
| goto yes; |
| } |
| |
| for(;;) { |
| if((execp = gline(linebuf)) == 0) { |
| (void) close(f); |
| return; |
| } |
| spend = execp; |
| |
| for(ipc = ptrspace; ipc->r1.command; ) { |
| |
| p1 = ipc->r1.ad1; |
| p2 = ipc->r1.ad2; |
| |
| if(p1) { |
| |
| if(ipc->r1.inar) { |
| if(*p2 == CEND) { |
| p1 = 0; |
| } else if(*p2 == CLNUM) { |
| c = (unsigned char)p2[1]; |
| if(lnum > tlno[c]) { |
| ipc->r1.inar = 0; |
| if(ipc->r1.negfl) |
| goto yes; |
| ipc++; |
| continue; |
| } |
| if(lnum == tlno[c]) { |
| ipc->r1.inar = 0; |
| } |
| } else if(match(p2, 0)) { |
| ipc->r1.inar = 0; |
| } |
| } else if(*p1 == CEND) { |
| if(!dolflag) { |
| if(ipc->r1.negfl) |
| goto yes; |
| ipc++; |
| continue; |
| } |
| |
| } else if(*p1 == CLNUM) { |
| c = (unsigned char)p1[1]; |
| if(lnum != tlno[c]) { |
| if(ipc->r1.negfl) |
| goto yes; |
| ipc++; |
| continue; |
| } |
| if(p2) |
| ipc->r1.inar = 1; |
| } else if(match(p1, 0)) { |
| if(p2) |
| ipc->r1.inar = 1; |
| } else { |
| if(ipc->r1.negfl) |
| goto yes; |
| ipc++; |
| continue; |
| } |
| } |
| |
| if(ipc->r1.negfl) { |
| ipc++; |
| continue; |
| } |
| yes: |
| command(ipc); |
| |
| if(delflag) |
| break; |
| |
| if(jflag) { |
| jflag = 0; |
| if((ipc = ipc->r2.lb1) == 0) { |
| ipc = ptrspace; |
| break; |
| } |
| } else |
| ipc++; |
| |
| } |
| if(!nflag && !delflag) { |
| for(p1 = linebuf; p1 < spend; p1++) |
| (void) putc(*p1, stdout); |
| (void) putc('\n', stdout); |
| } |
| |
| if(aptr > abuf) { |
| arout(); |
| } |
| |
| delflag = 0; |
| |
| } |
| } |
| |
| static int |
| match(char *expbuf, int gf) |
| { |
| char *p1; |
| |
| if(gf) { |
| if(*expbuf) return(0); |
| locs = p1 = loc2; |
| } else { |
| p1 = linebuf; |
| locs = 0; |
| } |
| |
| circf = *expbuf++; |
| return(step(p1, expbuf)); |
| } |
| |
| static int |
| substitute(union reptr *ipc) |
| { |
| if(match(ipc->r1.re1, 0) == 0) return(0); |
| |
| numpass = 0; |
| sflag = 0; /* Flags if any substitution was made */ |
| dosub(ipc->r1.rhs, ipc->r1.gfl); |
| |
| if(ipc->r1.gfl) { |
| while(*loc2) { |
| if(match(ipc->r1.re1, 1) == 0) break; |
| dosub(ipc->r1.rhs, ipc->r1.gfl); |
| } |
| } |
| return(sflag); |
| } |
| |
| static void |
| dosub(char *rhsbuf, int n) |
| { |
| char *lp, *sp, *rp; |
| int c; |
| |
| if(n > 0 && n < 999) |
| {numpass++; |
| if(n != numpass) return; |
| } |
| sflag = 1; |
| lp = linebuf; |
| sp = genbuf; |
| rp = rhsbuf; |
| while (lp < loc1) |
| *sp++ = *lp++; |
| while(c = *rp++) { |
| if (c == '&') |
| sp = place(sp, loc1, loc2); |
| else if (c == '\\') { |
| c = *rp++; |
| if (c >= '1' && c < NBRA+'1') |
| sp = place(sp, braslist[c-'1'], braelist[c-'1']); |
| else |
| *sp++ = c; |
| } else |
| *sp++ = c; |
| if (sp == &genbuf[LBSIZE+1]) { |
| (void) fprintf(stderr, "Output line too long.\n"); |
| *--sp = '\0'; |
| goto out; |
| } |
| } |
| lp = loc2; |
| loc2 = sp - genbuf + linebuf; |
| while(*sp++ = *lp++) |
| if (sp == &genbuf[LBSIZE+1]) { |
| (void) fprintf(stderr, "Output line too long.\n"); |
| *--sp = '\0'; |
| break; |
| } |
| out: |
| lp = linebuf; |
| sp = genbuf; |
| while (*lp++ = *sp++); |
| spend = lp-1; |
| } |
| |
| char *place(asp, al1, al2) |
| char *asp, *al1, *al2; |
| { |
| char *sp, *l1, *l2; |
| |
| sp = asp; |
| l1 = al1; |
| l2 = al2; |
| while (l1 < l2) { |
| *sp++ = *l1++; |
| if (sp == &genbuf[LBSIZE+1]) |
| break; |
| } |
| return(sp); |
| } |
| |
| static void |
| command(union reptr *ipc) |
| { |
| int i; |
| char *p1, *p2, *p3; |
| char *execp; |
| |
| |
| switch(ipc->r1.command) { |
| |
| case ACOM: |
| if(aptr >= &abuf[ABUFSIZE]) { |
| (void) fprintf(stderr, "Too many appends or reads after line %lld\n", |
| lnum); |
| } else { |
| *aptr++ = ipc; |
| *aptr = 0; |
| } |
| break; |
| |
| case CCOM: |
| delflag = 1; |
| if(!ipc->r1.inar || dolflag) { |
| for(p1 = ipc->r1.re1; *p1; ) |
| (void) putc(*p1++, stdout); |
| (void) putc('\n', stdout); |
| } |
| break; |
| case DCOM: |
| delflag++; |
| break; |
| case CDCOM: |
| p1 = p2 = linebuf; |
| |
| while(*p1 != '\n') { |
| if(*p1++ == 0) { |
| delflag++; |
| return; |
| } |
| } |
| |
| p1++; |
| while(*p2++ = *p1++); |
| spend = p2-1; |
| jflag++; |
| break; |
| |
| case EQCOM: |
| (void) fprintf(stdout, "%lld\n", lnum); |
| break; |
| |
| case GCOM: |
| p1 = linebuf; |
| p2 = holdsp; |
| while(*p1++ = *p2++); |
| spend = p1-1; |
| break; |
| |
| case CGCOM: |
| *spend++ = '\n'; |
| p1 = spend; |
| p2 = holdsp; |
| do { |
| if (p1 == &linebuf[LBSIZE+1]) { |
| (void) fprintf(stderr, "Output line too long.\n"); |
| *--p1 = '\0'; |
| } |
| } while(*p1++ = *p2++); |
| spend = p1-1; |
| break; |
| |
| case HCOM: |
| p1 = holdsp; |
| p2 = linebuf; |
| while(*p1++ = *p2++); |
| hspend = p1-1; |
| break; |
| |
| case CHCOM: |
| *hspend++ = '\n'; |
| p1 = hspend; |
| p2 = linebuf; |
| do { |
| if (p1 == &holdsp[LBSIZE+1]) { |
| (void) fprintf(stderr, "Hold space overflowed.\n"); |
| *--p1 = '\0'; |
| } |
| } while(*p1++ = *p2++); |
| hspend = p1-1; |
| break; |
| |
| case ICOM: |
| for(p1 = ipc->r1.re1; *p1; ) |
| (void) putc(*p1++, stdout); |
| (void) putc('\n', stdout); |
| break; |
| |
| case BCOM: |
| jflag = 1; |
| break; |
| |
| |
| case LCOM: |
| p1 = linebuf; |
| p2 = genbuf; |
| genbuf[72] = 0; |
| while(*p1) |
| if((unsigned char)*p1 >= 040) { |
| if(*p1 == 0177) { |
| p3 = rub; |
| while(*p2++ = *p3++) |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| p2--; |
| p1++; |
| continue; |
| } |
| if(!isprint(*p1 & 0377)) { |
| *p2++ = '\\'; |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| *p2++ = (*p1 >> 6) + '0'; |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| *p2++ = ((*p1 >> 3) & 07) + '0'; |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| *p2++ = (*p1++ & 07) + '0'; |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| } else { |
| *p2++ = *p1++; |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| } |
| } else { |
| p3 = trans[(unsigned char)*p1-1]; |
| while(*p2++ = *p3++) |
| if(p2 >= lcomend) { |
| *p2 = '\\'; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| p2 = genbuf; |
| } |
| p2--; |
| p1++; |
| } |
| *p2 = 0; |
| (void) fprintf(stdout, "%s\n", genbuf); |
| break; |
| |
| case NCOM: |
| if(!nflag) { |
| for(p1 = linebuf; p1 < spend; p1++) |
| (void) putc(*p1, stdout); |
| (void) putc('\n', stdout); |
| } |
| |
| if(aptr > abuf) |
| arout(); |
| if((execp = gline(linebuf)) == 0) { |
| pending = ipc; |
| delflag = 1; |
| break; |
| } |
| spend = execp; |
| |
| break; |
| case CNCOM: |
| if(aptr > abuf) |
| arout(); |
| *spend++ = '\n'; |
| if((execp = gline(spend)) == 0) { |
| pending = ipc; |
| delflag = 1; |
| break; |
| } |
| spend = execp; |
| break; |
| |
| case PCOM: |
| for(p1 = linebuf; p1 < spend; p1++) |
| (void) putc(*p1, stdout); |
| (void) putc('\n', stdout); |
| break; |
| case CPCOM: |
| cpcom: |
| for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; ) |
| (void) putc(*p1++, stdout); |
| (void) putc('\n', stdout); |
| break; |
| |
| case QCOM: |
| if(!nflag) { |
| for(p1 = linebuf; p1 < spend; p1++) |
| (void) putc(*p1, stdout); |
| (void) putc('\n', stdout); |
| } |
| if(aptr > abuf) arout(); |
| (void) fclose(stdout); |
| exit(0); |
| case RCOM: |
| if(aptr >= &abuf[ABUFSIZE]) { |
| (void) fprintf(stderr, "Too many appends or reads after line %lld\n", |
| lnum); |
| } else { |
| *aptr++ = ipc; |
| *aptr = 0; |
| } |
| break; |
| |
| case SCOM: |
| i = substitute(ipc); |
| if(ipc->r1.pfl && nflag && i) |
| if(ipc->r1.pfl == 1) { |
| for(p1 = linebuf; p1 < spend; p1++) |
| (void) putc(*p1, stdout); |
| (void) putc('\n', stdout); |
| } |
| else |
| goto cpcom; |
| if(i && ipc->r1.fcode) |
| goto wcom; |
| break; |
| |
| case TCOM: |
| if(sflag == 0) break; |
| sflag = 0; |
| jflag = 1; |
| break; |
| |
| wcom: |
| case WCOM: |
| (void) fprintf(ipc->r1.fcode, "%s\n", linebuf); |
| (void) fflush(ipc->r1.fcode); |
| break; |
| case XCOM: |
| p1 = linebuf; |
| p2 = genbuf; |
| while(*p2++ = *p1++); |
| p1 = holdsp; |
| p2 = linebuf; |
| while(*p2++ = *p1++); |
| spend = p2 - 1; |
| p1 = genbuf; |
| p2 = holdsp; |
| while(*p2++ = *p1++); |
| hspend = p2 - 1; |
| break; |
| |
| case YCOM: |
| p1 = linebuf; |
| p2 = ipc->r1.re1; |
| while(*p1 = p2[(unsigned char)*p1]) p1++; |
| break; |
| } |
| |
| } |
| |
| char *gline(addr) |
| char *addr; |
| { |
| char *p1, *p2; |
| int c; |
| sflag = 0; |
| p1 = addr; |
| p2 = cbp; |
| for (;;) { |
| if (p2 >= ebp) { |
| if(f < 0 || (c = read(f, ibuf, BUFSIZ)) == 0) { |
| return(0); |
| } |
| if(c < 0) { |
| (void) fprintf(stderr, "sed: error reading "); |
| perror(ifname); |
| exit(2); |
| } |
| p2 = ibuf; |
| ebp = ibuf+c; |
| } |
| if ((c = *p2++) == '\n') { |
| if(p2 >= ebp) { |
| if(f < 0 || (c = read(f, ibuf, BUFSIZ)) == 0) { |
| if(f >= 0) { |
| (void) close(f); |
| f = -1; |
| } |
| if(eargc == 0) |
| dolflag = 1; |
| } |
| if(c < 0) { |
| (void) fprintf(stderr, "sed: error reading "); |
| perror(ifname); |
| exit(2); |
| } |
| |
| p2 = ibuf; |
| ebp = ibuf + c; |
| } |
| break; |
| } |
| if(c) |
| if(p1 < &linebuf[LBSIZE]) |
| *p1++ = c; |
| } |
| lnum++; |
| *p1 = 0; |
| cbp = p2; |
| |
| return(p1); |
| } |
| |
| char *comple(x1, ep, x3, x4) |
| char *x1, *x3; |
| char x4; |
| char *ep; |
| { |
| char *p; |
| |
| p = compile(x1, ep + 1, x3, x4); |
| if(p == ep + 1) |
| return(ep); |
| *ep = circf; |
| return(p); |
| } |
| |
| void |
| regerr(int err) |
| { |
| switch(err) { |
| |
| case 11: |
| comperr("Range endpoint too large: %s"); |
| break; |
| |
| case 16: |
| comperr("Bad number: %s"); |
| break; |
| |
| case 25: |
| comperr("``\\digit'' out of range: %s"); |
| break; |
| |
| case 36: |
| comperr("Illegal or missing delimiter: %s"); |
| break; |
| |
| case 41: |
| comperr("No remembered search string: %s"); |
| break; |
| |
| case 42: |
| comperr("\\( \\) imbalance: %s"); |
| break; |
| |
| case 43: |
| comperr("Too many \\(: %s"); |
| break; |
| |
| case 44: |
| comperr("More than 2 numbers given in \\{ \\}: %s"); |
| break; |
| |
| case 45: |
| comperr("} expected after \\: %s"); |
| break; |
| |
| case 46: |
| comperr("First number exceeds second in \\{ \\}: %s"); |
| break; |
| |
| case 49: |
| comperr("[ ] imbalance: %s"); |
| break; |
| |
| case 50: |
| comperr(TMMES); |
| break; |
| |
| default: |
| (void) fprintf(stderr, "Unknown regexp error code %d: %s\n", |
| err, linebuf); |
| exit(2); |
| break; |
| } |
| } |
| |
| static void |
| arout(void) |
| { |
| char *p1; |
| FILE *fi; |
| char c; |
| int t; |
| |
| aptr = abuf - 1; |
| while(*++aptr) { |
| if((*aptr)->r1.command == ACOM) { |
| for(p1 = (*aptr)->r1.re1; *p1; ) |
| (void) putc(*p1++, stdout); |
| (void) putc('\n', stdout); |
| } else { |
| if((fi = fopen((*aptr)->r1.re1, "r")) == NULL) |
| continue; |
| while((t = getc(fi)) != EOF) { |
| c = t; |
| (void) putc(c, stdout); |
| } |
| (void) fclose(fi); |
| } |
| } |
| aptr = abuf; |
| *aptr = 0; |
| } |