/*
* 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 */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.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);
}
int
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;
}
return (0);
}
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;
}