OpenSolaris_b135/ucbcmd/sed/sed0.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 <stdio.h>
#include <sys/param.h>
#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);
}