xref: /plan9-contrib/sys/src/cmd/sed.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * sed -- stream  editor
33e12c5d1SDavid du Colombier  *
43e12c5d1SDavid du Colombier  *
53e12c5d1SDavid du Colombier  */
63e12c5d1SDavid du Colombier #include <u.h>
73e12c5d1SDavid du Colombier #include <libc.h>
83e12c5d1SDavid du Colombier #include <bio.h>
93e12c5d1SDavid du Colombier #include <regexp.h>
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier enum {
123e12c5d1SDavid du Colombier 	DEPTH		= 20,		/* max nesting depth of {} */
133e12c5d1SDavid du Colombier 	MAXCMDS		= 512,		/* max sed commands */
143e12c5d1SDavid du Colombier 	ADDSIZE		= 10000,	/* size of add & read buffer */
153e12c5d1SDavid du Colombier 	MAXADDS		= 20,		/* max pending adds and reads */
163e12c5d1SDavid du Colombier 	LBSIZE		= 8192,		/* input line size */
173e12c5d1SDavid du Colombier 	LABSIZE		= 50,		/* max label name size */
183e12c5d1SDavid du Colombier 	MAXSUB		= 10,		/* max number of sub reg exp */
193e12c5d1SDavid du Colombier 	MAXFILES	= 120,		/* max output files */
203e12c5d1SDavid du Colombier };
213e12c5d1SDavid du Colombier 	/* An address is a line #, a R.E., "$", a reference to the last
223e12c5d1SDavid du Colombier 	 * R.E., or nothing.
233e12c5d1SDavid du Colombier 	 */
243e12c5d1SDavid du Colombier typedef struct	{
253e12c5d1SDavid du Colombier 	enum {
263e12c5d1SDavid du Colombier 		A_NONE,
273e12c5d1SDavid du Colombier 		A_DOL,
283e12c5d1SDavid du Colombier 		A_LINE,
293e12c5d1SDavid du Colombier 		A_RE,
303e12c5d1SDavid du Colombier 		A_LAST,
313e12c5d1SDavid du Colombier 	}type;
323e12c5d1SDavid du Colombier 	union {
333e12c5d1SDavid du Colombier 		long line;		/* Line # */
343e12c5d1SDavid du Colombier 		Reprog *rp;		/* Compiled R.E. */
353e12c5d1SDavid du Colombier 	};
363e12c5d1SDavid du Colombier } Addr;
373e12c5d1SDavid du Colombier 
383e12c5d1SDavid du Colombier typedef struct	SEDCOM {
393e12c5d1SDavid du Colombier 	Addr	ad1;			/* optional start address */
403e12c5d1SDavid du Colombier 	Addr	ad2;			/* optional end address */
413e12c5d1SDavid du Colombier 	union {
423e12c5d1SDavid du Colombier 		Reprog	*re1;		/* compiled R.E. */
433e12c5d1SDavid du Colombier 		Rune	*text;		/* added text or file name */
443e12c5d1SDavid du Colombier 		struct	SEDCOM	*lb1;	/* destination command of branch */
453e12c5d1SDavid du Colombier 	};
463e12c5d1SDavid du Colombier 	Rune	*rhs;			/* Right-hand side of substitution */
473e12c5d1SDavid du Colombier 	Biobuf*	fcode;			/* File ID for read and write */
483e12c5d1SDavid du Colombier 	char	command;		/* command code -see below */
493e12c5d1SDavid du Colombier 	char	gfl;			/* 'Global' flag for substitutions */
503e12c5d1SDavid du Colombier 	char	pfl;			/* 'print' flag for substitutions */
513e12c5d1SDavid du Colombier 	char	active;			/* 1 => data between start and end */
523e12c5d1SDavid du Colombier 	char	negfl;			/* negation flag */
533e12c5d1SDavid du Colombier } SedCom;
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier 	/* Command Codes for field SedCom.command */
563e12c5d1SDavid du Colombier #define ACOM	01
573e12c5d1SDavid du Colombier #define BCOM	020
583e12c5d1SDavid du Colombier #define CCOM	02
593e12c5d1SDavid du Colombier #define	CDCOM	025
603e12c5d1SDavid du Colombier #define	CNCOM	022
613e12c5d1SDavid du Colombier #define COCOM	017
623e12c5d1SDavid du Colombier #define	CPCOM	023
633e12c5d1SDavid du Colombier #define DCOM	03
643e12c5d1SDavid du Colombier #define ECOM	015
653e12c5d1SDavid du Colombier #define EQCOM	013
663e12c5d1SDavid du Colombier #define FCOM	016
673e12c5d1SDavid du Colombier #define GCOM	027
683e12c5d1SDavid du Colombier #define CGCOM	030
693e12c5d1SDavid du Colombier #define HCOM	031
703e12c5d1SDavid du Colombier #define CHCOM	032
713e12c5d1SDavid du Colombier #define ICOM	04
723e12c5d1SDavid du Colombier #define LCOM	05
733e12c5d1SDavid du Colombier #define NCOM	012
743e12c5d1SDavid du Colombier #define PCOM	010
753e12c5d1SDavid du Colombier #define QCOM	011
763e12c5d1SDavid du Colombier #define RCOM	06
773e12c5d1SDavid du Colombier #define SCOM	07
783e12c5d1SDavid du Colombier #define TCOM	021
793e12c5d1SDavid du Colombier #define WCOM	014
803e12c5d1SDavid du Colombier #define	CWCOM	024
813e12c5d1SDavid du Colombier #define	YCOM	026
823e12c5d1SDavid du Colombier #define XCOM	033
833e12c5d1SDavid du Colombier 
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier typedef struct label {			/* Label symbol table */
863e12c5d1SDavid du Colombier 	Rune	asc[9];			/* Label name */
873e12c5d1SDavid du Colombier 	SedCom	*chain;
883e12c5d1SDavid du Colombier 	SedCom	*address;		/* Command associated with label */
893e12c5d1SDavid du Colombier } Label;
903e12c5d1SDavid du Colombier 
913e12c5d1SDavid du Colombier typedef	struct	FILE_CACHE {		/* Data file control block */
923e12c5d1SDavid du Colombier 	struct FILE_CACHE *next;	/* Forward Link */
933e12c5d1SDavid du Colombier 	char 		  *name;	/* Name of file */
943e12c5d1SDavid du Colombier } FileCache;
953e12c5d1SDavid du Colombier 
963e12c5d1SDavid du Colombier SedCom pspace[MAXCMDS];			/* Command storage */
973e12c5d1SDavid du Colombier SedCom *pend = pspace+MAXCMDS;		/* End of command storage */
983e12c5d1SDavid du Colombier SedCom *rep = pspace;			/* Current fill point */
993e12c5d1SDavid du Colombier 
1003e12c5d1SDavid du Colombier Reprog	*lastre = 0;			/* Last regular expression */
1013e12c5d1SDavid du Colombier Resub	subexp[MAXSUB];			/* sub-patterns of pattern match*/
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier Rune	addspace[ADDSIZE];		/* Buffer for a, c, & i commands */
1043e12c5d1SDavid du Colombier Rune	*addend = addspace+ADDSIZE;
1053e12c5d1SDavid du Colombier 
1063e12c5d1SDavid du Colombier SedCom	*abuf[MAXADDS];			/* Queue of pending adds & reads */
1073e12c5d1SDavid du Colombier SedCom	**aptr = abuf;
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier struct {				/* Sed program input control block */
1103e12c5d1SDavid du Colombier 	enum PTYPE 			/* Either on command line or in file */
1113e12c5d1SDavid du Colombier 		{ P_ARG,
1123e12c5d1SDavid du Colombier 		  P_FILE
1133e12c5d1SDavid du Colombier 		} type;
1143e12c5d1SDavid du Colombier 	union PCTL {			/* Pointer to data */
1153e12c5d1SDavid du Colombier 		Biobuf	*bp;
1163e12c5d1SDavid du Colombier 		char	*curr;
1173e12c5d1SDavid du Colombier 	};
1183e12c5d1SDavid du Colombier } prog;
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier Rune	genbuf[LBSIZE];			/* Miscellaneous buffer */
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier FileCache	*fhead = 0;		/* Head of File Cache Chain */
1233e12c5d1SDavid du Colombier FileCache	*ftail = 0;		/* Tail of File Cache Chain */
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier Rune	*loc1;				/* Start of pattern match */
1263e12c5d1SDavid du Colombier Rune	*loc2;				/* End of pattern match */
1273e12c5d1SDavid du Colombier Rune	seof;				/* Pattern delimiter char */
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier Rune	linebuf[LBSIZE+1];		/* Input data buffer */
1303e12c5d1SDavid du Colombier Rune	*lbend = linebuf+LBSIZE;	/* End of buffer */
1313e12c5d1SDavid du Colombier Rune	*spend = linebuf;			/* End of input data */
1323e12c5d1SDavid du Colombier Rune	*cp;				/* Current scan point in linebuf */
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier Rune	holdsp[LBSIZE+1];		/* Hold buffer */
1353e12c5d1SDavid du Colombier Rune	*hend = holdsp+LBSIZE;		/* End of hold buffer */
1363e12c5d1SDavid du Colombier Rune	*hspend = holdsp;		/* End of hold data */
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier int	nflag;				/* Command line flags */
1393e12c5d1SDavid du Colombier int	gflag;
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier int	dolflag;			/* Set when at true EOF */
1423e12c5d1SDavid du Colombier int	sflag;				/* Set when substitution done */
1433e12c5d1SDavid du Colombier int	jflag;				/* Set when jump required */
1443e12c5d1SDavid du Colombier int	delflag;			/* Delete current line when set */
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier long	lnum = 0;			/* Input line count */
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier char	fname[MAXFILES][40];		/* File name cache */
1493e12c5d1SDavid du Colombier Biobuf	*fcode[MAXFILES];		/* File ID cache */
1503e12c5d1SDavid du Colombier int	nfiles = 0;			/* Cache fill point */
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier Biobuf	fout;				/* Output stream */
1533e12c5d1SDavid du Colombier Biobuf	stdin;				/* Default input */
1543e12c5d1SDavid du Colombier Biobuf*	f = 0;				/* Input data */
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier Label	ltab[LABSIZE];			/* Label name symbol table */
1573e12c5d1SDavid du Colombier Label	*labend = ltab+LABSIZE;		/* End of label table */
1583e12c5d1SDavid du Colombier Label	*lab = ltab+1;			/* Current Fill point */
1593e12c5d1SDavid du Colombier 
1603e12c5d1SDavid du Colombier int	depth = 0;			/* {} stack pointer */
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier Rune	bad;				/* Dummy err ptr reference */
1633e12c5d1SDavid du Colombier Rune	*badp = &bad;
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier char	CGMES[]	 = 	"Command garbled: %S";
1673e12c5d1SDavid du Colombier char	TMMES[]	 = 	"Too much text: %S";
1683e12c5d1SDavid du Colombier char	LTL[]	 = 	"Label too long: %S";
1693e12c5d1SDavid du Colombier char	AD0MES[] =	"No addresses allowed: %S";
1703e12c5d1SDavid du Colombier char	AD1MES[] =	"Only one address allowed: %S";
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier void	address(Addr *);
1733e12c5d1SDavid du Colombier void	arout(void);
1743e12c5d1SDavid du Colombier int	cmp(char *, char *);
1753e12c5d1SDavid du Colombier int	rcmp(Rune *, Rune *);
1763e12c5d1SDavid du Colombier void	command(SedCom *);
1773e12c5d1SDavid du Colombier Reprog	*compile(void);
1783e12c5d1SDavid du Colombier Rune	*compsub(Rune *, Rune *);
1793e12c5d1SDavid du Colombier void	dechain(void);
1803e12c5d1SDavid du Colombier void	dosub(Rune *);
1813e12c5d1SDavid du Colombier int	ecmp(Rune *, Rune *, int);
1823e12c5d1SDavid du Colombier void	enroll(char *);
1833e12c5d1SDavid du Colombier void	errexit(void);
1843e12c5d1SDavid du Colombier int	executable(SedCom *);
1853e12c5d1SDavid du Colombier void	execute(void);
1863e12c5d1SDavid du Colombier void	fcomp(void);
1873e12c5d1SDavid du Colombier long	getrune(void);
1883e12c5d1SDavid du Colombier Rune	*gline(Rune *);
1893e12c5d1SDavid du Colombier int	match(Reprog *, Rune *);
1903e12c5d1SDavid du Colombier void	newfile(enum PTYPE, char *);
1913e12c5d1SDavid du Colombier int 	opendata(void);
1923e12c5d1SDavid du Colombier Biobuf	*open_file(char *);
1933e12c5d1SDavid du Colombier Rune	*place(Rune *, Rune *, Rune *);
1943e12c5d1SDavid du Colombier void	quit(char *, char *);
1953e12c5d1SDavid du Colombier int	rline(Rune *, Rune *);
1963e12c5d1SDavid du Colombier Label	*search(Label *);
1973e12c5d1SDavid du Colombier int	substitute(SedCom *);
1983e12c5d1SDavid du Colombier char	*text(char *);
1993e12c5d1SDavid du Colombier Rune	*stext(Rune *, Rune *);
2003e12c5d1SDavid du Colombier int	ycomp(SedCom *);
2013e12c5d1SDavid du Colombier char *	trans(int c);
2023e12c5d1SDavid du Colombier void	putline(Biobuf *bp, Rune *buf, int n);
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier void
2053e12c5d1SDavid du Colombier main(int argc, char **argv)
2063e12c5d1SDavid du Colombier {
2073e12c5d1SDavid du Colombier 	int	compfl;
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	lnum = 0;
2103e12c5d1SDavid du Colombier 	Binit(&fout, 1, OWRITE);
2113e12c5d1SDavid du Colombier 	fcode[nfiles++] = &fout;
2123e12c5d1SDavid du Colombier 	compfl = 0;
2133e12c5d1SDavid du Colombier 
2143e12c5d1SDavid du Colombier 	if(argc == 1)
2153e12c5d1SDavid du Colombier 		exits(0);
2163e12c5d1SDavid du Colombier 	ARGBEGIN{
2173e12c5d1SDavid du Colombier 		case 'n':
2183e12c5d1SDavid du Colombier 			nflag++;
2193e12c5d1SDavid du Colombier 			continue;
2203e12c5d1SDavid du Colombier 		case 'f':
2213e12c5d1SDavid du Colombier 			if(argc <= 1)
2223e12c5d1SDavid du Colombier 				quit("no pattern-file", 0);
2233e12c5d1SDavid du Colombier 			newfile(P_FILE, ARGF());
2243e12c5d1SDavid du Colombier 			fcomp();
2253e12c5d1SDavid du Colombier 			compfl = 1;
2263e12c5d1SDavid du Colombier 			continue;
2273e12c5d1SDavid du Colombier 		case 'e':
2283e12c5d1SDavid du Colombier 			if (argc <= 1)
2293e12c5d1SDavid du Colombier 				quit("missing pattern", 0);
2303e12c5d1SDavid du Colombier 			newfile(P_ARG, ARGF());
2313e12c5d1SDavid du Colombier 			fcomp();
2323e12c5d1SDavid du Colombier 			compfl = 1;
2333e12c5d1SDavid du Colombier 			continue;
2343e12c5d1SDavid du Colombier 		case 'g':
2353e12c5d1SDavid du Colombier 			gflag++;
2363e12c5d1SDavid du Colombier 			continue;
2373e12c5d1SDavid du Colombier 		default:
2383e12c5d1SDavid du Colombier 			fprint(2, "sed: Unknown flag: %c\n", ARGC());
2393e12c5d1SDavid du Colombier 			continue;
2403e12c5d1SDavid du Colombier 	} ARGEND
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier 	if(compfl == 0) {
2433e12c5d1SDavid du Colombier 		if (--argc < 0)
2443e12c5d1SDavid du Colombier 			quit("missing pattern", 0);
2453e12c5d1SDavid du Colombier 		newfile(P_ARG, *argv++);
2463e12c5d1SDavid du Colombier 		fcomp();
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier 	if(depth)
2503e12c5d1SDavid du Colombier 		quit("Too many {'s", 0);
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier 	ltab[0].address = rep;
2533e12c5d1SDavid du Colombier 
2543e12c5d1SDavid du Colombier 	dechain();
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier 	if(argc <= 0)
2573e12c5d1SDavid du Colombier 		enroll(0);		/* Add stdin to cache */
2583e12c5d1SDavid du Colombier 	else while(--argc >= 0) {
2593e12c5d1SDavid du Colombier 		enroll(*argv++);
2603e12c5d1SDavid du Colombier 	}
2613e12c5d1SDavid du Colombier 	execute();
2623e12c5d1SDavid du Colombier 	exits(0);
2633e12c5d1SDavid du Colombier }
2643e12c5d1SDavid du Colombier void
2653e12c5d1SDavid du Colombier fcomp(void)
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier 	Rune	*tp;
2683e12c5d1SDavid du Colombier 	SedCom	*pt, *pt1;
2693e12c5d1SDavid du Colombier 	int	i;
2703e12c5d1SDavid du Colombier 	Label	*lpt;
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	static Rune	*p = addspace;
2733e12c5d1SDavid du Colombier 	static SedCom	**cmpend[DEPTH];	/* stack of {} operations */
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	while (rline(linebuf, lbend) >= 0) {
2763e12c5d1SDavid du Colombier 		cp = linebuf;
2773e12c5d1SDavid du Colombier comploop:
278*219b2ee8SDavid du Colombier 		while(*cp == ' ' || *cp == '\t')
279*219b2ee8SDavid du Colombier 			cp++;
280*219b2ee8SDavid du Colombier 		if(*cp == '\0' || *cp == '#')
281*219b2ee8SDavid du Colombier 			continue;
2823e12c5d1SDavid du Colombier 		if(*cp == ';') {
2833e12c5d1SDavid du Colombier 			cp++;
2843e12c5d1SDavid du Colombier 			goto comploop;
2853e12c5d1SDavid du Colombier 		}
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier 		address(&rep->ad1);
2883e12c5d1SDavid du Colombier 		if (rep->ad1.type != A_NONE) {
2893e12c5d1SDavid du Colombier 			if (rep->ad1.type == A_LAST) {
2903e12c5d1SDavid du Colombier 				if (!lastre)
2913e12c5d1SDavid du Colombier 					quit("First RE may not be null", 0);
2923e12c5d1SDavid du Colombier 				rep->ad1.type = A_RE;
2933e12c5d1SDavid du Colombier 				rep->ad1.rp = lastre;
2943e12c5d1SDavid du Colombier 			}
2953e12c5d1SDavid du Colombier 			if(*cp == ',' || *cp == ';') {
2963e12c5d1SDavid du Colombier 				cp++;
2973e12c5d1SDavid du Colombier 				address(&rep->ad2);
2983e12c5d1SDavid du Colombier 				if (rep->ad2.type == A_LAST) {
2993e12c5d1SDavid du Colombier 					rep->ad1.type = A_RE;
3003e12c5d1SDavid du Colombier 					rep->ad2.rp = lastre;
3013e12c5d1SDavid du Colombier 				}
3023e12c5d1SDavid du Colombier 			} else
3033e12c5d1SDavid du Colombier 				rep->ad2.type = A_NONE;
3043e12c5d1SDavid du Colombier 		}
305*219b2ee8SDavid du Colombier 		while(*cp == ' ' || *cp == '\t')
306*219b2ee8SDavid du Colombier 			cp++;
3073e12c5d1SDavid du Colombier 
3083e12c5d1SDavid du Colombier swit:
3093e12c5d1SDavid du Colombier 		switch(*cp++) {
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 			default:
3123e12c5d1SDavid du Colombier 				quit("Unrecognized command: %S", (char *)linebuf);
3133e12c5d1SDavid du Colombier 
3143e12c5d1SDavid du Colombier 			case '!':
3153e12c5d1SDavid du Colombier 				rep->negfl = 1;
3163e12c5d1SDavid du Colombier 				goto swit;
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier 			case '{':
3193e12c5d1SDavid du Colombier 				rep->command = BCOM;
3203e12c5d1SDavid du Colombier 				rep->negfl = !(rep->negfl);
3213e12c5d1SDavid du Colombier 				cmpend[depth++] = &rep->lb1;
3223e12c5d1SDavid du Colombier 				if(++rep >= pend)
3233e12c5d1SDavid du Colombier 					quit("Too many commands: %S", (char *) linebuf);
3243e12c5d1SDavid du Colombier 				if(*cp == '\0')	continue;
3253e12c5d1SDavid du Colombier 				goto comploop;
3263e12c5d1SDavid du Colombier 
3273e12c5d1SDavid du Colombier 			case '}':
3283e12c5d1SDavid du Colombier 				if(rep->ad1.type != A_NONE)
3293e12c5d1SDavid du Colombier 					quit(AD0MES, (char *) linebuf);
3303e12c5d1SDavid du Colombier 				if(--depth < 0)
3313e12c5d1SDavid du Colombier 					quit("Too many }'s", 0);
3323e12c5d1SDavid du Colombier 				*cmpend[depth] = rep;
3333e12c5d1SDavid du Colombier 				if(*cp == 0)	continue;
3343e12c5d1SDavid du Colombier 				goto comploop;
3353e12c5d1SDavid du Colombier 
3363e12c5d1SDavid du Colombier 			case '=':
3373e12c5d1SDavid du Colombier 				rep->command = EQCOM;
3383e12c5d1SDavid du Colombier 				if(rep->ad2.type != A_NONE)
3393e12c5d1SDavid du Colombier 					quit(AD1MES, (char *) linebuf);
3403e12c5d1SDavid du Colombier 				break;
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier 			case ':':
3433e12c5d1SDavid du Colombier 				if(rep->ad1.type != A_NONE)
3443e12c5d1SDavid du Colombier 					quit(AD0MES, (char *) linebuf);
3453e12c5d1SDavid du Colombier 
346*219b2ee8SDavid du Colombier 				while(*cp == ' ')
347*219b2ee8SDavid du Colombier 					cp++;
3483e12c5d1SDavid du Colombier 				tp = lab->asc;
349*219b2ee8SDavid du Colombier 				while (*cp && *cp != ';' && *cp != ' ' && *cp != '\t' && *cp != '#') {
350*219b2ee8SDavid du Colombier 					*tp++ = *cp++;
3513e12c5d1SDavid du Colombier 					if(tp >= &(lab->asc[8]))
3523e12c5d1SDavid du Colombier 						quit(LTL, (char *) linebuf);
353*219b2ee8SDavid du Colombier 				}
354*219b2ee8SDavid du Colombier 				*tp = '\0';
3553e12c5d1SDavid du Colombier 
3563e12c5d1SDavid du Colombier 				if(lpt = search(lab)) {
3573e12c5d1SDavid du Colombier 					if(lpt->address)
3583e12c5d1SDavid du Colombier 						quit("Duplicate labels: %S", (char *) linebuf);
3593e12c5d1SDavid du Colombier 				} else {
3603e12c5d1SDavid du Colombier 					lab->chain = 0;
3613e12c5d1SDavid du Colombier 					lpt = lab;
3623e12c5d1SDavid du Colombier 					if(++lab >= labend)
3633e12c5d1SDavid du Colombier 						quit("Too many labels: %S", (char *) linebuf);
3643e12c5d1SDavid du Colombier 				}
3653e12c5d1SDavid du Colombier 				lpt->address = rep;
366*219b2ee8SDavid du Colombier 				if (*cp == '#')
3673e12c5d1SDavid du Colombier 					continue;
368*219b2ee8SDavid du Colombier 				rep--;			/* reuse this slot */
369*219b2ee8SDavid du Colombier 				break;
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier 			case 'a':
3723e12c5d1SDavid du Colombier 				rep->command = ACOM;
3733e12c5d1SDavid du Colombier 				if(rep->ad2.type != A_NONE)
3743e12c5d1SDavid du Colombier 					quit(AD1MES, (char *) linebuf);
3753e12c5d1SDavid du Colombier 				if(*cp == '\\')	cp++;
3763e12c5d1SDavid du Colombier 				if(*cp++ != '\n')
3773e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
3783e12c5d1SDavid du Colombier 				rep->text = p;
3793e12c5d1SDavid du Colombier 				p = stext(p, addend);
3803e12c5d1SDavid du Colombier 				break;
3813e12c5d1SDavid du Colombier 			case 'c':
3823e12c5d1SDavid du Colombier 				rep->command = CCOM;
3833e12c5d1SDavid du Colombier 				if(*cp == '\\')	cp++;
3843e12c5d1SDavid du Colombier 				if(*cp++ != '\n')
3853e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
3863e12c5d1SDavid du Colombier 				rep->text = p;
3873e12c5d1SDavid du Colombier 				p = stext(p, addend);
3883e12c5d1SDavid du Colombier 				break;
3893e12c5d1SDavid du Colombier 			case 'i':
3903e12c5d1SDavid du Colombier 				rep->command = ICOM;
3913e12c5d1SDavid du Colombier 				if(rep->ad2.type != A_NONE)
3923e12c5d1SDavid du Colombier 					quit(AD1MES, (char *) linebuf);
3933e12c5d1SDavid du Colombier 				if(*cp == '\\')	cp++;
3943e12c5d1SDavid du Colombier 				if(*cp++ != '\n')
3953e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
3963e12c5d1SDavid du Colombier 				rep->text = p;
3973e12c5d1SDavid du Colombier 				p = stext(p, addend);
3983e12c5d1SDavid du Colombier 				break;
3993e12c5d1SDavid du Colombier 
4003e12c5d1SDavid du Colombier 			case 'g':
4013e12c5d1SDavid du Colombier 				rep->command = GCOM;
4023e12c5d1SDavid du Colombier 				break;
4033e12c5d1SDavid du Colombier 
4043e12c5d1SDavid du Colombier 			case 'G':
4053e12c5d1SDavid du Colombier 				rep->command = CGCOM;
4063e12c5d1SDavid du Colombier 				break;
4073e12c5d1SDavid du Colombier 
4083e12c5d1SDavid du Colombier 			case 'h':
4093e12c5d1SDavid du Colombier 				rep->command = HCOM;
4103e12c5d1SDavid du Colombier 				break;
4113e12c5d1SDavid du Colombier 
4123e12c5d1SDavid du Colombier 			case 'H':
4133e12c5d1SDavid du Colombier 				rep->command = CHCOM;
4143e12c5d1SDavid du Colombier 				break;
4153e12c5d1SDavid du Colombier 
4163e12c5d1SDavid du Colombier 			case 't':
4173e12c5d1SDavid du Colombier 				rep->command = TCOM;
4183e12c5d1SDavid du Colombier 				goto jtcommon;
4193e12c5d1SDavid du Colombier 
4203e12c5d1SDavid du Colombier 			case 'b':
4213e12c5d1SDavid du Colombier 				rep->command = BCOM;
4223e12c5d1SDavid du Colombier jtcommon:
4233e12c5d1SDavid du Colombier 				while(*cp == ' ')cp++;
4243e12c5d1SDavid du Colombier 				if(*cp == '\0') {
4253e12c5d1SDavid du Colombier 					if(pt = ltab[0].chain) {
4263e12c5d1SDavid du Colombier 						while(pt1 = pt->lb1)
4273e12c5d1SDavid du Colombier 							pt = pt1;
4283e12c5d1SDavid du Colombier 						pt->lb1 = rep;
4293e12c5d1SDavid du Colombier 					} else
4303e12c5d1SDavid du Colombier 						ltab[0].chain = rep;
4313e12c5d1SDavid du Colombier 					break;
4323e12c5d1SDavid du Colombier 				}
4333e12c5d1SDavid du Colombier 				tp = lab->asc;
4343e12c5d1SDavid du Colombier 				while((*tp++ = *cp++))
4353e12c5d1SDavid du Colombier 					if(tp >= &(lab->asc[8]))
4363e12c5d1SDavid du Colombier 						quit(LTL, (char *) linebuf);
4373e12c5d1SDavid du Colombier 				cp--;
4383e12c5d1SDavid du Colombier 				tp[-1] = '\0';
4393e12c5d1SDavid du Colombier 
4403e12c5d1SDavid du Colombier 				if(lpt = search(lab)) {
4413e12c5d1SDavid du Colombier 					if(lpt->address) {
4423e12c5d1SDavid du Colombier 						rep->lb1 = lpt->address;
4433e12c5d1SDavid du Colombier 					} else {
4443e12c5d1SDavid du Colombier 						pt = lpt->chain;
4453e12c5d1SDavid du Colombier 						while(pt1 = pt->lb1)
4463e12c5d1SDavid du Colombier 							pt = pt1;
4473e12c5d1SDavid du Colombier 						pt->lb1 = rep;
4483e12c5d1SDavid du Colombier 					}
4493e12c5d1SDavid du Colombier 				} else {
4503e12c5d1SDavid du Colombier 					lab->chain = rep;
4513e12c5d1SDavid du Colombier 					lab->address = 0;
4523e12c5d1SDavid du Colombier 					if(++lab >= labend)
4533e12c5d1SDavid du Colombier 						quit("Too many labels: %S",
4543e12c5d1SDavid du Colombier 							(char *) linebuf);
4553e12c5d1SDavid du Colombier 				}
4563e12c5d1SDavid du Colombier 				break;
4573e12c5d1SDavid du Colombier 
4583e12c5d1SDavid du Colombier 			case 'n':
4593e12c5d1SDavid du Colombier 				rep->command = NCOM;
4603e12c5d1SDavid du Colombier 				break;
4613e12c5d1SDavid du Colombier 
4623e12c5d1SDavid du Colombier 			case 'N':
4633e12c5d1SDavid du Colombier 				rep->command = CNCOM;
4643e12c5d1SDavid du Colombier 				break;
4653e12c5d1SDavid du Colombier 
4663e12c5d1SDavid du Colombier 			case 'p':
4673e12c5d1SDavid du Colombier 				rep->command = PCOM;
4683e12c5d1SDavid du Colombier 				break;
4693e12c5d1SDavid du Colombier 
4703e12c5d1SDavid du Colombier 			case 'P':
4713e12c5d1SDavid du Colombier 				rep->command = CPCOM;
4723e12c5d1SDavid du Colombier 				break;
4733e12c5d1SDavid du Colombier 
4743e12c5d1SDavid du Colombier 			case 'r':
4753e12c5d1SDavid du Colombier 				rep->command = RCOM;
4763e12c5d1SDavid du Colombier 				if(rep->ad2.type != A_NONE)
4773e12c5d1SDavid du Colombier 					quit(AD1MES, (char *) linebuf);
4783e12c5d1SDavid du Colombier 				if(*cp++ != ' ')
4793e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
4803e12c5d1SDavid du Colombier 				rep->text = p;
4813e12c5d1SDavid du Colombier 				p = stext(p, addend);
4823e12c5d1SDavid du Colombier 				break;
4833e12c5d1SDavid du Colombier 
4843e12c5d1SDavid du Colombier 			case 'd':
4853e12c5d1SDavid du Colombier 				rep->command = DCOM;
4863e12c5d1SDavid du Colombier 				break;
4873e12c5d1SDavid du Colombier 
4883e12c5d1SDavid du Colombier 			case 'D':
4893e12c5d1SDavid du Colombier 				rep->command = CDCOM;
4903e12c5d1SDavid du Colombier 				rep->lb1 = pspace;
4913e12c5d1SDavid du Colombier 				break;
4923e12c5d1SDavid du Colombier 
4933e12c5d1SDavid du Colombier 			case 'q':
4943e12c5d1SDavid du Colombier 				rep->command = QCOM;
4953e12c5d1SDavid du Colombier 				if(rep->ad2.type != A_NONE)
4963e12c5d1SDavid du Colombier 					quit(AD1MES, (char *) linebuf);
4973e12c5d1SDavid du Colombier 				break;
4983e12c5d1SDavid du Colombier 
4993e12c5d1SDavid du Colombier 			case 'l':
5003e12c5d1SDavid du Colombier 				rep->command = LCOM;
5013e12c5d1SDavid du Colombier 				break;
5023e12c5d1SDavid du Colombier 
5033e12c5d1SDavid du Colombier 			case 's':
5043e12c5d1SDavid du Colombier 				rep->command = SCOM;
5053e12c5d1SDavid du Colombier 				seof = *cp++;
5063e12c5d1SDavid du Colombier 				if ((rep->re1 = compile()) == 0) {
5073e12c5d1SDavid du Colombier 					if(!lastre)
5083e12c5d1SDavid du Colombier 						quit("First RE may not be null.", 0);
5093e12c5d1SDavid du Colombier 					rep->re1 = lastre;
5103e12c5d1SDavid du Colombier 				}
5113e12c5d1SDavid du Colombier 				rep->rhs = p;
5123e12c5d1SDavid du Colombier 				if((p = compsub(p, addend)) == 0)
5133e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
5143e12c5d1SDavid du Colombier 				if(*cp == 'g') {
5153e12c5d1SDavid du Colombier 					cp++;
5163e12c5d1SDavid du Colombier 					rep->gfl++;
5173e12c5d1SDavid du Colombier 				} else if(gflag)
5183e12c5d1SDavid du Colombier 					rep->gfl++;
5193e12c5d1SDavid du Colombier 
5203e12c5d1SDavid du Colombier 				if(*cp == 'p') {
5213e12c5d1SDavid du Colombier 					cp++;
5223e12c5d1SDavid du Colombier 					rep->pfl = 1;
5233e12c5d1SDavid du Colombier 				}
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier 				if(*cp == 'P') {
5263e12c5d1SDavid du Colombier 					cp++;
5273e12c5d1SDavid du Colombier 					rep->pfl = 2;
5283e12c5d1SDavid du Colombier 				}
5293e12c5d1SDavid du Colombier 
5303e12c5d1SDavid du Colombier 				if(*cp == 'w') {
5313e12c5d1SDavid du Colombier 					cp++;
5323e12c5d1SDavid du Colombier 					if(*cp++ !=  ' ')
5333e12c5d1SDavid du Colombier 						quit(CGMES, (char *) linebuf);
5343e12c5d1SDavid du Colombier 					text(fname[nfiles]);
5353e12c5d1SDavid du Colombier 					for(i = nfiles - 1; i >= 0; i--)
5363e12c5d1SDavid du Colombier 						if(cmp(fname[nfiles],fname[i]) == 0) {
5373e12c5d1SDavid du Colombier 							rep->fcode = fcode[i];
5383e12c5d1SDavid du Colombier 							goto done;
5393e12c5d1SDavid du Colombier 						}
5403e12c5d1SDavid du Colombier 					if(nfiles >= MAXFILES)
5413e12c5d1SDavid du Colombier 						quit("Too many files in w commands 1", 0);
5423e12c5d1SDavid du Colombier 					rep->fcode = open_file(fname[nfiles]);
5433e12c5d1SDavid du Colombier 				}
5443e12c5d1SDavid du Colombier 				break;
5453e12c5d1SDavid du Colombier 
5463e12c5d1SDavid du Colombier 			case 'w':
5473e12c5d1SDavid du Colombier 				rep->command = WCOM;
5483e12c5d1SDavid du Colombier 				if(*cp++ != ' ')
5493e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
5503e12c5d1SDavid du Colombier 				text(fname[nfiles]);
5513e12c5d1SDavid du Colombier 				for(i = nfiles - 1; i >= 0; i--)
5523e12c5d1SDavid du Colombier 					if(cmp(fname[nfiles], fname[i]) == 0) {
5533e12c5d1SDavid du Colombier 						rep->fcode = fcode[i];
5543e12c5d1SDavid du Colombier 						goto done;
5553e12c5d1SDavid du Colombier 					}
5563e12c5d1SDavid du Colombier 				if(nfiles >= MAXFILES){
5573e12c5d1SDavid du Colombier 					fprint(2, "sed: Too many files in w commands 2 \n");
5583e12c5d1SDavid du Colombier 					fprint(2, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES);
5593e12c5d1SDavid du Colombier 					errexit();
5603e12c5d1SDavid du Colombier 				}
5613e12c5d1SDavid du Colombier 				rep->fcode = open_file(fname[nfiles]);
5623e12c5d1SDavid du Colombier 				break;
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 			case 'x':
5653e12c5d1SDavid du Colombier 				rep->command = XCOM;
5663e12c5d1SDavid du Colombier 				break;
5673e12c5d1SDavid du Colombier 
5683e12c5d1SDavid du Colombier 			case 'y':
5693e12c5d1SDavid du Colombier 				rep->command = YCOM;
5703e12c5d1SDavid du Colombier 				seof = *cp++;
5713e12c5d1SDavid du Colombier 				if (ycomp(rep) == 0)
5723e12c5d1SDavid du Colombier 					quit(CGMES, (char *) linebuf);
5733e12c5d1SDavid du Colombier 				break;
5743e12c5d1SDavid du Colombier 
5753e12c5d1SDavid du Colombier 		}
5763e12c5d1SDavid du Colombier done:
5773e12c5d1SDavid du Colombier 		if(++rep >= pend)
5783e12c5d1SDavid du Colombier 			quit("Too many commands, last: %S", (char *) linebuf);
5793e12c5d1SDavid du Colombier 
5803e12c5d1SDavid du Colombier 		if(*cp++ != '\0') {
5813e12c5d1SDavid du Colombier 			if(cp[-1] == ';')
5823e12c5d1SDavid du Colombier 				goto comploop;
5833e12c5d1SDavid du Colombier 			quit(CGMES, (char *) linebuf);
5843e12c5d1SDavid du Colombier 		}
5853e12c5d1SDavid du Colombier 
5863e12c5d1SDavid du Colombier 	}
5873e12c5d1SDavid du Colombier }
5883e12c5d1SDavid du Colombier 
5893e12c5d1SDavid du Colombier Biobuf *
5903e12c5d1SDavid du Colombier open_file(char *name)
5913e12c5d1SDavid du Colombier {
5923e12c5d1SDavid du Colombier 	Biobuf *bp;
5933e12c5d1SDavid du Colombier 	int fd;
5943e12c5d1SDavid du Colombier 
5953e12c5d1SDavid du Colombier 	if ((bp = malloc(sizeof(Biobuf))) == 0)
5963e12c5d1SDavid du Colombier 		quit("Out of memory", 0);
5973e12c5d1SDavid du Colombier 	if ((fd = open(name, OWRITE)) < 0 &&
5983e12c5d1SDavid du Colombier 		(fd = create(name, OWRITE, 0666)) < 0)
5993e12c5d1SDavid du Colombier 			quit("Cannot create %s", name);
6003e12c5d1SDavid du Colombier 	Binit(bp, fd, OWRITE);
6013e12c5d1SDavid du Colombier 	Bseek(bp, 0, 2);
6023e12c5d1SDavid du Colombier 	fcode[nfiles++] = bp;
6033e12c5d1SDavid du Colombier 	return bp;
6043e12c5d1SDavid du Colombier }
6053e12c5d1SDavid du Colombier 
6063e12c5d1SDavid du Colombier Rune	*
6073e12c5d1SDavid du Colombier compsub(Rune *rhs, Rune *end)
6083e12c5d1SDavid du Colombier {
6093e12c5d1SDavid du Colombier 	Rune	r;
6103e12c5d1SDavid du Colombier 
6113e12c5d1SDavid du Colombier 	while ((r = *cp++) != '\0') {
6123e12c5d1SDavid du Colombier 		if(r == '\\') {
6133e12c5d1SDavid du Colombier 			if (rhs < end)
6143e12c5d1SDavid du Colombier 				*rhs++ = 0xFFFF;
6153e12c5d1SDavid du Colombier 			else
6163e12c5d1SDavid du Colombier 				return 0;
6173e12c5d1SDavid du Colombier 			r = *cp++;
6183e12c5d1SDavid du Colombier 			if(r == 'n')
6193e12c5d1SDavid du Colombier 				r = '\n';
6203e12c5d1SDavid du Colombier 		} else {
6213e12c5d1SDavid du Colombier 			if(r == seof) {
6223e12c5d1SDavid du Colombier 				if (rhs < end)
6233e12c5d1SDavid du Colombier 					*rhs++ = '\0';
6243e12c5d1SDavid du Colombier 				else
6253e12c5d1SDavid du Colombier 					return 0;
6263e12c5d1SDavid du Colombier 				return rhs;
6273e12c5d1SDavid du Colombier 			}
6283e12c5d1SDavid du Colombier 		}
6293e12c5d1SDavid du Colombier 		if (rhs < end)
6303e12c5d1SDavid du Colombier 			*rhs++ = r;
6313e12c5d1SDavid du Colombier 		else
6323e12c5d1SDavid du Colombier 			return 0;
6333e12c5d1SDavid du Colombier 
6343e12c5d1SDavid du Colombier 	}
6353e12c5d1SDavid du Colombier 	return 0;
6363e12c5d1SDavid du Colombier }
6373e12c5d1SDavid du Colombier 
6383e12c5d1SDavid du Colombier Reprog *
6393e12c5d1SDavid du Colombier compile(void)
6403e12c5d1SDavid du Colombier {
6413e12c5d1SDavid du Colombier 	Rune c;
6423e12c5d1SDavid du Colombier 	char *ep;
6433e12c5d1SDavid du Colombier 	char expbuf[512];
6443e12c5d1SDavid du Colombier 
6453e12c5d1SDavid du Colombier 	if((c = *cp++) == seof)		/* '//' */
6463e12c5d1SDavid du Colombier 		return 0;
6473e12c5d1SDavid du Colombier 	ep = expbuf;
6483e12c5d1SDavid du Colombier 	do {
6493e12c5d1SDavid du Colombier 		if (c == 0 || c == '\n')
6503e12c5d1SDavid du Colombier 			quit(TMMES, (char *) linebuf);
6513e12c5d1SDavid du Colombier 		if (c == '\\') {
6523e12c5d1SDavid du Colombier 			if (ep >= expbuf+sizeof(expbuf))
6533e12c5d1SDavid du Colombier 				quit(TMMES, (char *) linebuf);
6543e12c5d1SDavid du Colombier 			ep += runetochar(ep, &c);
6553e12c5d1SDavid du Colombier 			if ((c = *cp++) == 'n')
6563e12c5d1SDavid du Colombier 				c = '\n';
6573e12c5d1SDavid du Colombier 		}
6583e12c5d1SDavid du Colombier 		if (ep >= expbuf+sizeof(expbuf))
6593e12c5d1SDavid du Colombier 			quit(TMMES, (char *) linebuf);
6603e12c5d1SDavid du Colombier 		ep += runetochar(ep, &c);
6613e12c5d1SDavid du Colombier 	} while ((c = *cp++) != seof);
6623e12c5d1SDavid du Colombier 	*ep = 0;
6633e12c5d1SDavid du Colombier 	return lastre = regcomp(expbuf);
6643e12c5d1SDavid du Colombier }
6653e12c5d1SDavid du Colombier 
6663e12c5d1SDavid du Colombier void
6673e12c5d1SDavid du Colombier regerror(char *s)
6683e12c5d1SDavid du Colombier {
6693e12c5d1SDavid du Colombier 	USED(s);
6703e12c5d1SDavid du Colombier 	quit(CGMES, (char *) linebuf);
6713e12c5d1SDavid du Colombier }
6723e12c5d1SDavid du Colombier 
6733e12c5d1SDavid du Colombier void
6743e12c5d1SDavid du Colombier newfile(enum PTYPE type, char *name)
6753e12c5d1SDavid du Colombier {
6763e12c5d1SDavid du Colombier 	if (type == P_ARG)
6773e12c5d1SDavid du Colombier 		prog.curr = name;
6783e12c5d1SDavid du Colombier 	else if ((prog.bp = Bopen(name, OREAD)) == 0)
6793e12c5d1SDavid du Colombier 		quit("Cannot open pattern-file: %s\n", name);
6803e12c5d1SDavid du Colombier 	prog.type = type;
6813e12c5d1SDavid du Colombier }
6823e12c5d1SDavid du Colombier 
6833e12c5d1SDavid du Colombier int
6843e12c5d1SDavid du Colombier rline(Rune *buf, Rune *end)
6853e12c5d1SDavid du Colombier {
6863e12c5d1SDavid du Colombier 	long c;
6873e12c5d1SDavid du Colombier 	Rune r;
6883e12c5d1SDavid du Colombier 
6893e12c5d1SDavid du Colombier 	while ((c = getrune()) >= 0) {
6903e12c5d1SDavid du Colombier 		r = c;
6913e12c5d1SDavid du Colombier 		if (r == '\\') {
6923e12c5d1SDavid du Colombier 			if (buf <= end)
6933e12c5d1SDavid du Colombier 				*buf++ = r;
6943e12c5d1SDavid du Colombier 			if ((c = getrune()) < 0)
6953e12c5d1SDavid du Colombier 				break;
6963e12c5d1SDavid du Colombier 			r = c;
6973e12c5d1SDavid du Colombier 		} else if (r == '\n') {
6983e12c5d1SDavid du Colombier 			*buf = '\0';
6993e12c5d1SDavid du Colombier 			return(1);
7003e12c5d1SDavid du Colombier 		}
7013e12c5d1SDavid du Colombier 		if (buf <= end)
7023e12c5d1SDavid du Colombier 			*buf++ = r;
7033e12c5d1SDavid du Colombier 	}
7043e12c5d1SDavid du Colombier 	*buf = '\0';
7053e12c5d1SDavid du Colombier 	return(-1);
7063e12c5d1SDavid du Colombier }
7073e12c5d1SDavid du Colombier 
7083e12c5d1SDavid du Colombier long
7093e12c5d1SDavid du Colombier getrune(void)
7103e12c5d1SDavid du Colombier {
7113e12c5d1SDavid du Colombier 	char *p;
7123e12c5d1SDavid du Colombier 	long c;
7133e12c5d1SDavid du Colombier 	Rune r;
7143e12c5d1SDavid du Colombier 
7153e12c5d1SDavid du Colombier 	if (prog.type == P_ARG) {
7163e12c5d1SDavid du Colombier 		if ((p = prog.curr) != 0) {
7173e12c5d1SDavid du Colombier 			if (*p) {
7183e12c5d1SDavid du Colombier 				prog.curr += chartorune(&r, p);
7193e12c5d1SDavid du Colombier 				c = r;
7203e12c5d1SDavid du Colombier 			} else {
7213e12c5d1SDavid du Colombier 				c = '\n';	/* fake an end-of-line */
7223e12c5d1SDavid du Colombier 				prog.curr = 0;
7233e12c5d1SDavid du Colombier 			}
7243e12c5d1SDavid du Colombier 		} else
7253e12c5d1SDavid du Colombier 			c = -1;
7263e12c5d1SDavid du Colombier 	} else if ((c = Bgetrune(prog.bp)) < 0)
727*219b2ee8SDavid du Colombier 			Bterm(prog.bp);
7283e12c5d1SDavid du Colombier 	return c;
7293e12c5d1SDavid du Colombier }
7303e12c5d1SDavid du Colombier 
7313e12c5d1SDavid du Colombier void
7323e12c5d1SDavid du Colombier address(Addr *ap)
7333e12c5d1SDavid du Colombier {
7343e12c5d1SDavid du Colombier 	int c;
7353e12c5d1SDavid du Colombier 	long	lno;
7363e12c5d1SDavid du Colombier 
7373e12c5d1SDavid du Colombier 	if((c = *cp++) == '$')
7383e12c5d1SDavid du Colombier 		ap->type = A_DOL;
7393e12c5d1SDavid du Colombier 	else if(c == '/') {
7403e12c5d1SDavid du Colombier 		seof = c;
7413e12c5d1SDavid du Colombier 		if (ap->rp = compile())
7423e12c5d1SDavid du Colombier 			ap->type = A_RE;
7433e12c5d1SDavid du Colombier 		else
7443e12c5d1SDavid du Colombier 			ap->type = A_LAST;
7453e12c5d1SDavid du Colombier 	}
7463e12c5d1SDavid du Colombier 	else if (c >= '0' && c <= '9') {
7473e12c5d1SDavid du Colombier 		lno = c-'0';
7483e12c5d1SDavid du Colombier 		while ((c = *cp) >= '0' && c <= '9')
7493e12c5d1SDavid du Colombier 			lno = lno*10 + *cp++-'0';
7503e12c5d1SDavid du Colombier 		if(!lno)
7513e12c5d1SDavid du Colombier 			quit("line number 0 is illegal",0);
7523e12c5d1SDavid du Colombier 		ap->type = A_LINE;
7533e12c5d1SDavid du Colombier 		ap->line = lno;
7543e12c5d1SDavid du Colombier 	}
7553e12c5d1SDavid du Colombier 	else {
7563e12c5d1SDavid du Colombier 		cp--;
7573e12c5d1SDavid du Colombier 		ap->type = A_NONE;
7583e12c5d1SDavid du Colombier 	}
7593e12c5d1SDavid du Colombier }
7603e12c5d1SDavid du Colombier 
7613e12c5d1SDavid du Colombier cmp(char *a, char *b)		/* compare characters */
7623e12c5d1SDavid du Colombier {
7633e12c5d1SDavid du Colombier 	while(*a == *b++)
7643e12c5d1SDavid du Colombier 		if (*a == '\0')
7653e12c5d1SDavid du Colombier 			return(0);
7663e12c5d1SDavid du Colombier 		else a++;
7673e12c5d1SDavid du Colombier 	return(1);
7683e12c5d1SDavid du Colombier }
7693e12c5d1SDavid du Colombier rcmp(Rune *a, Rune *b)		/* compare runes */
7703e12c5d1SDavid du Colombier {
7713e12c5d1SDavid du Colombier 	while(*a == *b++)
7723e12c5d1SDavid du Colombier 		if (*a == '\0')
7733e12c5d1SDavid du Colombier 			return(0);
7743e12c5d1SDavid du Colombier 		else a++;
7753e12c5d1SDavid du Colombier 	return(1);
7763e12c5d1SDavid du Colombier }
7773e12c5d1SDavid du Colombier 
7783e12c5d1SDavid du Colombier char *
7793e12c5d1SDavid du Colombier text(char *p)		/* extract character string */
7803e12c5d1SDavid du Colombier {
7813e12c5d1SDavid du Colombier 	Rune	r;
7823e12c5d1SDavid du Colombier 
7833e12c5d1SDavid du Colombier 	while(*cp == '\t' || *cp == ' ')
7843e12c5d1SDavid du Colombier 			cp++;
7853e12c5d1SDavid du Colombier 	while (*cp) {
7863e12c5d1SDavid du Colombier 		if ((r = *cp++) == '\\')
7873e12c5d1SDavid du Colombier 			if ((r = *cp++) == 0)
7883e12c5d1SDavid du Colombier 				break;;
7893e12c5d1SDavid du Colombier 		if (r == '\n')
7903e12c5d1SDavid du Colombier 			while (*cp == '\t' || *cp == ' ')
7913e12c5d1SDavid du Colombier 					cp++;
7923e12c5d1SDavid du Colombier 		p += runetochar(p, &r);
7933e12c5d1SDavid du Colombier 	}
7943e12c5d1SDavid du Colombier 	*p++ = '\0';
7953e12c5d1SDavid du Colombier 	return p;
7963e12c5d1SDavid du Colombier }
7973e12c5d1SDavid du Colombier 
7983e12c5d1SDavid du Colombier Rune *
7993e12c5d1SDavid du Colombier stext(Rune *p, Rune *end)		/* extract rune string */
8003e12c5d1SDavid du Colombier {
8013e12c5d1SDavid du Colombier 	while(*cp == '\t' || *cp == ' ')
8023e12c5d1SDavid du Colombier 		cp++;
8033e12c5d1SDavid du Colombier 	while (*cp) {
8043e12c5d1SDavid du Colombier 		if (*cp == '\\')
8053e12c5d1SDavid du Colombier 			if (*++cp == 0)
8063e12c5d1SDavid du Colombier 				break;
8073e12c5d1SDavid du Colombier 		if (p >= end-1)
8083e12c5d1SDavid du Colombier 			quit(TMMES, (char *) linebuf);
8093e12c5d1SDavid du Colombier 		if ((*p++ = *cp++) == '\n')
8103e12c5d1SDavid du Colombier 			while(*cp == '\t' || *cp == ' ')
8113e12c5d1SDavid du Colombier 					cp++;
8123e12c5d1SDavid du Colombier 	}
8133e12c5d1SDavid du Colombier 	*p++ = 0;
8143e12c5d1SDavid du Colombier 	return p;
8153e12c5d1SDavid du Colombier }
8163e12c5d1SDavid du Colombier 
8173e12c5d1SDavid du Colombier 
8183e12c5d1SDavid du Colombier Label *
8193e12c5d1SDavid du Colombier search (Label *ptr)
8203e12c5d1SDavid du Colombier {
8213e12c5d1SDavid du Colombier 	Label	*rp;
8223e12c5d1SDavid du Colombier 
8233e12c5d1SDavid du Colombier 	for (rp = ltab; rp < ptr; rp++)
8243e12c5d1SDavid du Colombier 		if(rcmp(rp->asc, ptr->asc) == 0)
8253e12c5d1SDavid du Colombier 			return(rp);
8263e12c5d1SDavid du Colombier 	return(0);
8273e12c5d1SDavid du Colombier }
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier void
8303e12c5d1SDavid du Colombier dechain(void)
8313e12c5d1SDavid du Colombier {
8323e12c5d1SDavid du Colombier 	Label	*lptr;
8333e12c5d1SDavid du Colombier 	SedCom	*rptr, *trptr;
8343e12c5d1SDavid du Colombier 
8353e12c5d1SDavid du Colombier 	for(lptr = ltab; lptr < lab; lptr++) {
8363e12c5d1SDavid du Colombier 
8373e12c5d1SDavid du Colombier 		if(lptr->address == 0)
8383e12c5d1SDavid du Colombier 			quit("Undefined label: %S", (char *) lptr->asc);
8393e12c5d1SDavid du Colombier 
8403e12c5d1SDavid du Colombier 		if(lptr->chain) {
8413e12c5d1SDavid du Colombier 			rptr = lptr->chain;
8423e12c5d1SDavid du Colombier 			while(trptr = rptr->lb1) {
8433e12c5d1SDavid du Colombier 				rptr->lb1 = lptr->address;
8443e12c5d1SDavid du Colombier 				rptr = trptr;
8453e12c5d1SDavid du Colombier 			}
8463e12c5d1SDavid du Colombier 			rptr->lb1 = lptr->address;
8473e12c5d1SDavid du Colombier 		}
8483e12c5d1SDavid du Colombier 	}
8493e12c5d1SDavid du Colombier }
8503e12c5d1SDavid du Colombier 
8513e12c5d1SDavid du Colombier int
8523e12c5d1SDavid du Colombier ycomp(SedCom *r)
8533e12c5d1SDavid du Colombier {
8543e12c5d1SDavid du Colombier 	int 	i;
8553e12c5d1SDavid du Colombier 	Rune	*rp;
8563e12c5d1SDavid du Colombier 	Rune	c, *tsp, highc;
8573e12c5d1SDavid du Colombier 	Rune	*sp;
8583e12c5d1SDavid du Colombier 
8593e12c5d1SDavid du Colombier 	highc = 0;
8603e12c5d1SDavid du Colombier 	for(tsp = cp; *tsp != seof; tsp++) {
8613e12c5d1SDavid du Colombier 		if(*tsp == '\\')
8623e12c5d1SDavid du Colombier 			tsp++;
8633e12c5d1SDavid du Colombier 		if(*tsp == '\n' || *tsp == '\0')
8643e12c5d1SDavid du Colombier 			return(0);
8653e12c5d1SDavid du Colombier 		if (*tsp > highc) highc = *tsp;
8663e12c5d1SDavid du Colombier 	}
8673e12c5d1SDavid du Colombier 	tsp++;
8683e12c5d1SDavid du Colombier 	if ((rp = r->text = (Rune *) malloc(sizeof(Rune)*(highc+2))) == 0)
8693e12c5d1SDavid du Colombier 		quit("Out of memory", 0);
8703e12c5d1SDavid du Colombier 	*rp++ = highc;				/* save upper bound */
8713e12c5d1SDavid du Colombier 	for (i = 0; i <= highc; i++)
8723e12c5d1SDavid du Colombier 		rp[i] = i;
8733e12c5d1SDavid du Colombier 	sp = cp;
8743e12c5d1SDavid du Colombier 	while((c = *sp++) != seof) {
8753e12c5d1SDavid du Colombier 		if(c == '\\' && *sp == 'n') {
8763e12c5d1SDavid du Colombier 			sp++;
8773e12c5d1SDavid du Colombier 			c = '\n';
8783e12c5d1SDavid du Colombier 		}
8793e12c5d1SDavid du Colombier 		if((rp[c] = *tsp++) == '\\' && *tsp == 'n') {
8803e12c5d1SDavid du Colombier 			rp[c] = '\n';
8813e12c5d1SDavid du Colombier 			tsp++;
8823e12c5d1SDavid du Colombier 		}
8833e12c5d1SDavid du Colombier 		if(rp[c] == seof || rp[c] == '\0') {
8843e12c5d1SDavid du Colombier 			free(r->re1);
8853e12c5d1SDavid du Colombier 			r->re1 = 0;
8863e12c5d1SDavid du Colombier 			return(0);
8873e12c5d1SDavid du Colombier 		}
8883e12c5d1SDavid du Colombier 	}
8893e12c5d1SDavid du Colombier 	if(*tsp != seof) {
8903e12c5d1SDavid du Colombier 		free(r->re1);
8913e12c5d1SDavid du Colombier 		r->re1 = 0;
8923e12c5d1SDavid du Colombier 		return(0);
8933e12c5d1SDavid du Colombier 	}
8943e12c5d1SDavid du Colombier 	cp = tsp+1;
8953e12c5d1SDavid du Colombier 	return(1);
8963e12c5d1SDavid du Colombier }
8973e12c5d1SDavid du Colombier 
8983e12c5d1SDavid du Colombier void
8993e12c5d1SDavid du Colombier execute(void)
9003e12c5d1SDavid du Colombier {
9013e12c5d1SDavid du Colombier 	SedCom	*ipc;
9023e12c5d1SDavid du Colombier 
9033e12c5d1SDavid du Colombier 	while (spend = gline(linebuf)){
9043e12c5d1SDavid du Colombier 		for(ipc = pspace; ipc->command; ) {
9053e12c5d1SDavid du Colombier 			if (!executable(ipc)) {
9063e12c5d1SDavid du Colombier 				ipc++;
9073e12c5d1SDavid du Colombier 				continue;
9083e12c5d1SDavid du Colombier 			}
9093e12c5d1SDavid du Colombier 			command(ipc);
910*219b2ee8SDavid du Colombier 
911*219b2ee8SDavid du Colombier 			if(ipc->ad2.type == A_RE && match(ipc->ad2.rp, linebuf))
912*219b2ee8SDavid du Colombier 				ipc->active = 0;
913*219b2ee8SDavid du Colombier 
9143e12c5d1SDavid du Colombier 			if(delflag)
9153e12c5d1SDavid du Colombier 				break;
9163e12c5d1SDavid du Colombier 
9173e12c5d1SDavid du Colombier 			if(jflag) {
9183e12c5d1SDavid du Colombier 				jflag = 0;
9193e12c5d1SDavid du Colombier 				if((ipc = ipc->lb1) == 0)
9203e12c5d1SDavid du Colombier 					break;
9213e12c5d1SDavid du Colombier 			} else
9223e12c5d1SDavid du Colombier 				ipc++;
9233e12c5d1SDavid du Colombier 
9243e12c5d1SDavid du Colombier 		}
9253e12c5d1SDavid du Colombier 		if(!nflag && !delflag)
9263e12c5d1SDavid du Colombier 			putline(&fout, linebuf, spend-linebuf);
9273e12c5d1SDavid du Colombier 		if(aptr > abuf) {
9283e12c5d1SDavid du Colombier 			arout();
9293e12c5d1SDavid du Colombier 		}
9303e12c5d1SDavid du Colombier 		delflag = 0;
9313e12c5d1SDavid du Colombier 	}
9323e12c5d1SDavid du Colombier }
9333e12c5d1SDavid du Colombier 	/* determine if a statement should be applied to an input line */
9343e12c5d1SDavid du Colombier int
9353e12c5d1SDavid du Colombier executable(SedCom *ipc)
9363e12c5d1SDavid du Colombier {
9373e12c5d1SDavid du Colombier 	if (ipc->active) {	/* Addr1 satisfied - accept until Addr2 */
9383e12c5d1SDavid du Colombier 		if (ipc->active == 1)		/* Second line */
9393e12c5d1SDavid du Colombier 			ipc->active = 2;
9403e12c5d1SDavid du Colombier 		switch(ipc->ad2.type) {
9413e12c5d1SDavid du Colombier 			case A_NONE:	/* No second addr; use first */
9423e12c5d1SDavid du Colombier 				ipc->active = 0;
9433e12c5d1SDavid du Colombier 				break;
9443e12c5d1SDavid du Colombier 			case A_DOL:	/* Accept everything */
9453e12c5d1SDavid du Colombier 				return !ipc->negfl;
9463e12c5d1SDavid du Colombier 			case A_LINE:	/* Line at end of range? */
9473e12c5d1SDavid du Colombier 				if (lnum <= ipc->ad2.line) {
9483e12c5d1SDavid du Colombier 					if (ipc->ad2.line == lnum)
9493e12c5d1SDavid du Colombier 						ipc->active = 0;
9503e12c5d1SDavid du Colombier 					return !ipc->negfl;
9513e12c5d1SDavid du Colombier 				}
9523e12c5d1SDavid du Colombier 				ipc->active = 0;	/* out of range */
9533e12c5d1SDavid du Colombier 				return ipc->negfl;
9543e12c5d1SDavid du Colombier 			case A_RE:	/* Check for matching R.E. */
9553e12c5d1SDavid du Colombier 				if (match(ipc->ad2.rp, linebuf))
9563e12c5d1SDavid du Colombier 					ipc->active = 0;
9573e12c5d1SDavid du Colombier 				return !ipc->negfl;
9583e12c5d1SDavid du Colombier 			default:		/* internal error */
9593e12c5d1SDavid du Colombier 				quit("Internal error", 0);
9603e12c5d1SDavid du Colombier 		}
9613e12c5d1SDavid du Colombier 	}
9623e12c5d1SDavid du Colombier 	switch (ipc->ad1.type) {	/* Check first address */
9633e12c5d1SDavid du Colombier 		case A_NONE:			/* Everything matches */
9643e12c5d1SDavid du Colombier 			return !ipc->negfl;
9653e12c5d1SDavid du Colombier 		case A_DOL:			/* Only last line */
9663e12c5d1SDavid du Colombier 			if (dolflag)
9673e12c5d1SDavid du Colombier 				return !ipc->negfl;
9683e12c5d1SDavid du Colombier 			break;
9693e12c5d1SDavid du Colombier 		case A_LINE:			/* Check line number */
9703e12c5d1SDavid du Colombier 			if (ipc->ad1.line == lnum) {
9713e12c5d1SDavid du Colombier 				ipc->active = 1;	/* In range */
9723e12c5d1SDavid du Colombier 				return !ipc->negfl;
9733e12c5d1SDavid du Colombier 			}
9743e12c5d1SDavid du Colombier 			break;
9753e12c5d1SDavid du Colombier 		case A_RE:			/* Check R.E. */
9763e12c5d1SDavid du Colombier 			if (match(ipc->ad1.rp, linebuf)) {
9773e12c5d1SDavid du Colombier 				ipc->active = 1;	/* In range */
9783e12c5d1SDavid du Colombier 				return !ipc->negfl;
9793e12c5d1SDavid du Colombier 			}
9803e12c5d1SDavid du Colombier 			break;
9813e12c5d1SDavid du Colombier 		default:
9823e12c5d1SDavid du Colombier 			quit("Internal error", 0);
9833e12c5d1SDavid du Colombier 	}
9843e12c5d1SDavid du Colombier 	return ipc->negfl;
9853e12c5d1SDavid du Colombier }
9863e12c5d1SDavid du Colombier match(Reprog *pattern, Rune *buf)
9873e12c5d1SDavid du Colombier {
9883e12c5d1SDavid du Colombier 	if (!pattern)
9893e12c5d1SDavid du Colombier 		return 0;
9903e12c5d1SDavid du Colombier 	subexp[0].rsp = buf;
9913e12c5d1SDavid du Colombier 	subexp[0].ep = 0;
9923e12c5d1SDavid du Colombier 	if (rregexec(pattern, linebuf, subexp, MAXSUB)) {
9933e12c5d1SDavid du Colombier 		loc1 = subexp[0].rsp;
9943e12c5d1SDavid du Colombier 		loc2 = subexp[0].rep;
9953e12c5d1SDavid du Colombier 		return 1;
9963e12c5d1SDavid du Colombier 	}
9973e12c5d1SDavid du Colombier 	loc1 = loc2 = 0;
9983e12c5d1SDavid du Colombier 	return 0;
9993e12c5d1SDavid du Colombier }
10003e12c5d1SDavid du Colombier substitute(SedCom *ipc)
10013e12c5d1SDavid du Colombier {
10023e12c5d1SDavid du Colombier 	if(match(ipc->re1, linebuf)) {
10033e12c5d1SDavid du Colombier 		sflag = 1;
10043e12c5d1SDavid du Colombier 		dosub(ipc->rhs);
10053e12c5d1SDavid du Colombier 		if(!ipc->gfl)
10063e12c5d1SDavid du Colombier 			return 1;
10073e12c5d1SDavid du Colombier 		while (match(ipc->re1, loc2)) {
10083e12c5d1SDavid du Colombier 			if (loc2-loc1 == 0){	/* NULL R.E. match */
10093e12c5d1SDavid du Colombier 				if (*loc2++ == 0)
10103e12c5d1SDavid du Colombier 					break;
10113e12c5d1SDavid du Colombier 			} else {
10123e12c5d1SDavid du Colombier 				dosub(ipc->rhs);
10133e12c5d1SDavid du Colombier 				if(*loc2 == 0)
10143e12c5d1SDavid du Colombier 					break;
10153e12c5d1SDavid du Colombier 			}
10163e12c5d1SDavid du Colombier 		}
10173e12c5d1SDavid du Colombier 		return 1;
10183e12c5d1SDavid du Colombier 	}
10193e12c5d1SDavid du Colombier 	return 0;
10203e12c5d1SDavid du Colombier }
10213e12c5d1SDavid du Colombier 
10223e12c5d1SDavid du Colombier void
10233e12c5d1SDavid du Colombier dosub(Rune *rhsbuf)
10243e12c5d1SDavid du Colombier {
10253e12c5d1SDavid du Colombier 	Rune *lp, *sp;
10263e12c5d1SDavid du Colombier 	Rune *rp;
10273e12c5d1SDavid du Colombier 	int c, n;
10283e12c5d1SDavid du Colombier 
10293e12c5d1SDavid du Colombier 	lp = linebuf;
10303e12c5d1SDavid du Colombier 	sp = genbuf;
10313e12c5d1SDavid du Colombier 	rp = rhsbuf;
10323e12c5d1SDavid du Colombier 	while (lp < loc1)
10333e12c5d1SDavid du Colombier 		*sp++ = *lp++;
10343e12c5d1SDavid du Colombier 	while(c = *rp++) {
10353e12c5d1SDavid du Colombier 		if (c == '&') {
10363e12c5d1SDavid du Colombier 			sp = place(sp, loc1, loc2);
10373e12c5d1SDavid du Colombier 			continue;
10383e12c5d1SDavid du Colombier 		}
10393e12c5d1SDavid du Colombier 		if (c == 0xFFFF && (c = *rp++) >= '1' && c <= MAXSUB+'0') {
10403e12c5d1SDavid du Colombier 			n = c-'0';
10413e12c5d1SDavid du Colombier 			if (subexp[n].rsp && subexp[n].rep) {
10423e12c5d1SDavid du Colombier 				sp = place(sp, subexp[n].rsp, subexp[n].rep);
10433e12c5d1SDavid du Colombier 				continue;
10443e12c5d1SDavid du Colombier 			}
10453e12c5d1SDavid du Colombier 			else {
10463e12c5d1SDavid du Colombier 				fprint(2, "sed: Invalid back reference \\%d\n",n);
10473e12c5d1SDavid du Colombier 				errexit();
10483e12c5d1SDavid du Colombier 			}
10493e12c5d1SDavid du Colombier 		}
10503e12c5d1SDavid du Colombier 		*sp++ = c;
10513e12c5d1SDavid du Colombier 		if (sp >= &genbuf[LBSIZE])
10523e12c5d1SDavid du Colombier 			fprint(2, "sed: Output line too long.\n");
10533e12c5d1SDavid du Colombier 	}
10543e12c5d1SDavid du Colombier 	lp = loc2;
10553e12c5d1SDavid du Colombier 	loc2 = sp - genbuf + linebuf;
10563e12c5d1SDavid du Colombier 	while (*sp++ = *lp++)
10573e12c5d1SDavid du Colombier 		if (sp >= &genbuf[LBSIZE])
10583e12c5d1SDavid du Colombier 			fprint(2, "sed: Output line too long.\n");
10593e12c5d1SDavid du Colombier 	lp = linebuf;
10603e12c5d1SDavid du Colombier 	sp = genbuf;
10613e12c5d1SDavid du Colombier 	while (*lp++ = *sp++)
10623e12c5d1SDavid du Colombier 		;
10633e12c5d1SDavid du Colombier 	spend = lp-1;
10643e12c5d1SDavid du Colombier }
10653e12c5d1SDavid du Colombier 
10663e12c5d1SDavid du Colombier Rune *
10673e12c5d1SDavid du Colombier place(Rune *sp, Rune *l1, Rune *l2)
10683e12c5d1SDavid du Colombier {
10693e12c5d1SDavid du Colombier 	while (l1 < l2) {
10703e12c5d1SDavid du Colombier 		*sp++ = *l1++;
10713e12c5d1SDavid du Colombier 		if (sp >= &genbuf[LBSIZE])
10723e12c5d1SDavid du Colombier 			fprint(2, "sed: Output line too long.\n");
10733e12c5d1SDavid du Colombier 	}
10743e12c5d1SDavid du Colombier 	return(sp);
10753e12c5d1SDavid du Colombier }
10763e12c5d1SDavid du Colombier 
10773e12c5d1SDavid du Colombier char *
10783e12c5d1SDavid du Colombier trans(int c)
10793e12c5d1SDavid du Colombier {
10803e12c5d1SDavid du Colombier 	static char buf[] = "\\x0000";
10813e12c5d1SDavid du Colombier 	static char hex[] = "0123456789abcdef";
10823e12c5d1SDavid du Colombier 
10833e12c5d1SDavid du Colombier 	switch(c) {
10843e12c5d1SDavid du Colombier 		case '\b':
10853e12c5d1SDavid du Colombier 			return "\\b";
10863e12c5d1SDavid du Colombier 		case '\n':
10873e12c5d1SDavid du Colombier 			return "\\n";
10883e12c5d1SDavid du Colombier 		case '\r':
10893e12c5d1SDavid du Colombier 			return "\\r";
10903e12c5d1SDavid du Colombier 		case '\t':
10913e12c5d1SDavid du Colombier 			return "\\t";
10923e12c5d1SDavid du Colombier 		case '\\':
10933e12c5d1SDavid du Colombier 			return "\\\\";
10943e12c5d1SDavid du Colombier 	}
10953e12c5d1SDavid du Colombier 	buf[2] = hex[(c>>12)&0xF];
10963e12c5d1SDavid du Colombier 	buf[3] = hex[(c>>8)&0xF];
10973e12c5d1SDavid du Colombier 	buf[4] = hex[(c>>4)&0xF];
10983e12c5d1SDavid du Colombier 	buf[5] = hex[c&0xF];
10993e12c5d1SDavid du Colombier 	return buf;
11003e12c5d1SDavid du Colombier }
11013e12c5d1SDavid du Colombier 
11023e12c5d1SDavid du Colombier void
11033e12c5d1SDavid du Colombier command(SedCom *ipc)
11043e12c5d1SDavid du Colombier {
11053e12c5d1SDavid du Colombier 	int	i, c;
11063e12c5d1SDavid du Colombier 	Rune	*p1, *p2;
11073e12c5d1SDavid du Colombier 	char	*ucp;
11083e12c5d1SDavid du Colombier 	Rune	*rp;
11093e12c5d1SDavid du Colombier 	Rune	*execp;
11103e12c5d1SDavid du Colombier 
11113e12c5d1SDavid du Colombier 	switch(ipc->command) {
11123e12c5d1SDavid du Colombier 
11133e12c5d1SDavid du Colombier 		case ACOM:
11143e12c5d1SDavid du Colombier 			*aptr++ = ipc;
11153e12c5d1SDavid du Colombier 			if(aptr >= abuf+MAXADDS) {
11163e12c5d1SDavid du Colombier 				quit("sed: Too many appends after line %ld\n",
11173e12c5d1SDavid du Colombier 					(char *) lnum);
11183e12c5d1SDavid du Colombier 			}
11193e12c5d1SDavid du Colombier 			*aptr = 0;
11203e12c5d1SDavid du Colombier 			break;
11213e12c5d1SDavid du Colombier 		case CCOM:
11223e12c5d1SDavid du Colombier 			delflag = 1;
11233e12c5d1SDavid du Colombier 			if(ipc->active == 1) {
11243e12c5d1SDavid du Colombier 				for(rp = ipc->text; *rp; rp++)
11253e12c5d1SDavid du Colombier 					Bputrune(&fout, *rp);
11263e12c5d1SDavid du Colombier 				Bputc(&fout, '\n');
11273e12c5d1SDavid du Colombier 			}
11283e12c5d1SDavid du Colombier 			break;
11293e12c5d1SDavid du Colombier 		case DCOM:
11303e12c5d1SDavid du Colombier 			delflag++;
11313e12c5d1SDavid du Colombier 			break;
11323e12c5d1SDavid du Colombier 		case CDCOM:
11333e12c5d1SDavid du Colombier 			p1 = p2 = linebuf;
11343e12c5d1SDavid du Colombier 			while(*p1 != '\n') {
11353e12c5d1SDavid du Colombier 				if(*p1++ == 0) {
11363e12c5d1SDavid du Colombier 					delflag++;
11373e12c5d1SDavid du Colombier 					return;
11383e12c5d1SDavid du Colombier 				}
11393e12c5d1SDavid du Colombier 			}
11403e12c5d1SDavid du Colombier 			p1++;
11413e12c5d1SDavid du Colombier 			while(*p2++ = *p1++)
11423e12c5d1SDavid du Colombier 				;
11433e12c5d1SDavid du Colombier 			spend = p2-1;
11443e12c5d1SDavid du Colombier 			jflag++;
11453e12c5d1SDavid du Colombier 			break;
11463e12c5d1SDavid du Colombier 		case EQCOM:
11473e12c5d1SDavid du Colombier 			Bprint(&fout, "%ld\n", lnum);
11483e12c5d1SDavid du Colombier 			break;
11493e12c5d1SDavid du Colombier 		case GCOM:
11503e12c5d1SDavid du Colombier 			p1 = linebuf;
11513e12c5d1SDavid du Colombier 			p2 = holdsp;
11523e12c5d1SDavid du Colombier 			while(*p1++ = *p2++)
11533e12c5d1SDavid du Colombier 				;
11543e12c5d1SDavid du Colombier 			spend = p1-1;
11553e12c5d1SDavid du Colombier 			break;
11563e12c5d1SDavid du Colombier 		case CGCOM:
11573e12c5d1SDavid du Colombier 			*spend++ = '\n';
11583e12c5d1SDavid du Colombier 			p1 = spend;
11593e12c5d1SDavid du Colombier 			p2 = holdsp;
11603e12c5d1SDavid du Colombier 			while(*p1++ = *p2++)
11613e12c5d1SDavid du Colombier 				if(p1 >= lbend)
11623e12c5d1SDavid du Colombier 					break;
11633e12c5d1SDavid du Colombier 			spend = p1-1;
11643e12c5d1SDavid du Colombier 			break;
11653e12c5d1SDavid du Colombier 		case HCOM:
11663e12c5d1SDavid du Colombier 			p1 = holdsp;
11673e12c5d1SDavid du Colombier 			p2 = linebuf;
11683e12c5d1SDavid du Colombier 			while(*p1++ = *p2++);
11693e12c5d1SDavid du Colombier 			hspend = p1-1;
11703e12c5d1SDavid du Colombier 			break;
11713e12c5d1SDavid du Colombier 		case CHCOM:
11723e12c5d1SDavid du Colombier 			*hspend++ = '\n';
11733e12c5d1SDavid du Colombier 			p1 = hspend;
11743e12c5d1SDavid du Colombier 			p2 = linebuf;
11753e12c5d1SDavid du Colombier 			while(*p1++ = *p2++)
11763e12c5d1SDavid du Colombier 				if(p1 >= hend)
11773e12c5d1SDavid du Colombier 					break;
11783e12c5d1SDavid du Colombier 			hspend = p1-1;
11793e12c5d1SDavid du Colombier 			break;
11803e12c5d1SDavid du Colombier 		case ICOM:
11813e12c5d1SDavid du Colombier 			for(rp = ipc->text; *rp; rp++)
11823e12c5d1SDavid du Colombier 				Bputrune(&fout, *rp);
11833e12c5d1SDavid du Colombier 			Bputc(&fout, '\n');
11843e12c5d1SDavid du Colombier 			break;
11853e12c5d1SDavid du Colombier 		case BCOM:
11863e12c5d1SDavid du Colombier 			jflag = 1;
11873e12c5d1SDavid du Colombier 			break;
11883e12c5d1SDavid du Colombier 		case LCOM:
11893e12c5d1SDavid du Colombier 			c = 0;
11903e12c5d1SDavid du Colombier 			for (i = 0, rp = linebuf; *rp; rp++) {
11913e12c5d1SDavid du Colombier 				c = *rp;
11923e12c5d1SDavid du Colombier 				if(c >= 0x20 && c < 0x7F && c != '\\') {
11933e12c5d1SDavid du Colombier 					Bputc(&fout, c);
11943e12c5d1SDavid du Colombier 					if(i++ > 71) {
11953e12c5d1SDavid du Colombier 						Bprint(&fout, "\\\n");
11963e12c5d1SDavid du Colombier 						i = 0;
11973e12c5d1SDavid du Colombier 					}
11983e12c5d1SDavid du Colombier 				} else {
11993e12c5d1SDavid du Colombier 					for (ucp = trans(*rp); *ucp; ucp++){
12003e12c5d1SDavid du Colombier 						c = *ucp;
12013e12c5d1SDavid du Colombier 						Bputc(&fout, c);
12023e12c5d1SDavid du Colombier 						if(i++ > 71) {
12033e12c5d1SDavid du Colombier 							Bprint(&fout, "\\\n");
12043e12c5d1SDavid du Colombier 							i = 0;
12053e12c5d1SDavid du Colombier 						}
12063e12c5d1SDavid du Colombier 					}
12073e12c5d1SDavid du Colombier 				}
12083e12c5d1SDavid du Colombier 			}
12093e12c5d1SDavid du Colombier 			if(c == ' ')
12103e12c5d1SDavid du Colombier 				Bprint(&fout, "\\n");
12113e12c5d1SDavid du Colombier 			Bputc(&fout, '\n');
12123e12c5d1SDavid du Colombier 			break;
12133e12c5d1SDavid du Colombier 		case NCOM:
12143e12c5d1SDavid du Colombier 			if(!nflag)
12153e12c5d1SDavid du Colombier 				putline(&fout, linebuf, spend-linebuf);
12163e12c5d1SDavid du Colombier 
12173e12c5d1SDavid du Colombier 			if(aptr > abuf)
12183e12c5d1SDavid du Colombier 				arout();
12193e12c5d1SDavid du Colombier 			if((execp = gline(linebuf)) == 0) {
12203e12c5d1SDavid du Colombier 				delflag = 1;
12213e12c5d1SDavid du Colombier 				break;
12223e12c5d1SDavid du Colombier 			}
12233e12c5d1SDavid du Colombier 			spend = execp;
12243e12c5d1SDavid du Colombier 			break;
12253e12c5d1SDavid du Colombier 		case CNCOM:
12263e12c5d1SDavid du Colombier 			if(aptr > abuf)
12273e12c5d1SDavid du Colombier 				arout();
12283e12c5d1SDavid du Colombier 			*spend++ = '\n';
12293e12c5d1SDavid du Colombier 			if((execp = gline(spend)) == 0) {
12303e12c5d1SDavid du Colombier 				delflag = 1;
12313e12c5d1SDavid du Colombier 				break;
12323e12c5d1SDavid du Colombier 			}
12333e12c5d1SDavid du Colombier 			spend = execp;
12343e12c5d1SDavid du Colombier 			break;
12353e12c5d1SDavid du Colombier 		case PCOM:
12363e12c5d1SDavid du Colombier 			putline(&fout, linebuf, spend-linebuf);
12373e12c5d1SDavid du Colombier 			break;
12383e12c5d1SDavid du Colombier 		case CPCOM:
12393e12c5d1SDavid du Colombier 	cpcom:
12403e12c5d1SDavid du Colombier 			for(rp = linebuf; *rp && *rp != '\n'; rp++)
12413e12c5d1SDavid du Colombier 				Bputc(&fout, *rp);
12423e12c5d1SDavid du Colombier 			Bputc(&fout, '\n');
12433e12c5d1SDavid du Colombier 			break;
12443e12c5d1SDavid du Colombier 		case QCOM:
12453e12c5d1SDavid du Colombier 			if(!nflag)
12463e12c5d1SDavid du Colombier 				putline(&fout, linebuf, spend-linebuf);
12473e12c5d1SDavid du Colombier 			if(aptr > abuf)
12483e12c5d1SDavid du Colombier 				arout();
12493e12c5d1SDavid du Colombier 			exits(0);
12503e12c5d1SDavid du Colombier 		case RCOM:
12513e12c5d1SDavid du Colombier 			*aptr++ = ipc;
12523e12c5d1SDavid du Colombier 			if(aptr >= &abuf[MAXADDS])
12533e12c5d1SDavid du Colombier 				quit("sed: Too many reads after line %ld\n",
12543e12c5d1SDavid du Colombier 					(char *) lnum);
12553e12c5d1SDavid du Colombier 			*aptr = 0;
12563e12c5d1SDavid du Colombier 			break;
12573e12c5d1SDavid du Colombier 		case SCOM:
12583e12c5d1SDavid du Colombier 			i = substitute(ipc);
12593e12c5d1SDavid du Colombier 			if(i && ipc->pfl)
12603e12c5d1SDavid du Colombier 				if(ipc->pfl == 1)
12613e12c5d1SDavid du Colombier 					putline(&fout, linebuf, spend-linebuf);
12623e12c5d1SDavid du Colombier 				else
12633e12c5d1SDavid du Colombier 					goto cpcom;
12643e12c5d1SDavid du Colombier 			if(i && ipc->fcode)
12653e12c5d1SDavid du Colombier 				goto wcom;
12663e12c5d1SDavid du Colombier 			break;
12673e12c5d1SDavid du Colombier 
12683e12c5d1SDavid du Colombier 		case TCOM:
12693e12c5d1SDavid du Colombier 			if(sflag == 0)	break;
12703e12c5d1SDavid du Colombier 			sflag = 0;
12713e12c5d1SDavid du Colombier 			jflag = 1;
12723e12c5d1SDavid du Colombier 			break;
12733e12c5d1SDavid du Colombier 
12743e12c5d1SDavid du Colombier 		wcom:
12753e12c5d1SDavid du Colombier 		case WCOM:
12763e12c5d1SDavid du Colombier 			putline(ipc->fcode,linebuf, spend-linebuf);
12773e12c5d1SDavid du Colombier 			break;
12783e12c5d1SDavid du Colombier 		case XCOM:
12793e12c5d1SDavid du Colombier 			p1 = linebuf;
12803e12c5d1SDavid du Colombier 			p2 = genbuf;
12813e12c5d1SDavid du Colombier 			while(*p2++ = *p1++);
12823e12c5d1SDavid du Colombier 			p1 = holdsp;
12833e12c5d1SDavid du Colombier 			p2 = linebuf;
12843e12c5d1SDavid du Colombier 			while(*p2++ = *p1++);
12853e12c5d1SDavid du Colombier 			spend = p2 - 1;
12863e12c5d1SDavid du Colombier 			p1 = genbuf;
12873e12c5d1SDavid du Colombier 			p2 = holdsp;
12883e12c5d1SDavid du Colombier 			while(*p2++ = *p1++);
12893e12c5d1SDavid du Colombier 			hspend = p2 - 1;
12903e12c5d1SDavid du Colombier 			break;
12913e12c5d1SDavid du Colombier 		case YCOM:
12923e12c5d1SDavid du Colombier 			p1 = linebuf;
12933e12c5d1SDavid du Colombier 			p2 = ipc->text;
12943e12c5d1SDavid du Colombier 			for (i = *p2++;	*p1; p1++){
12953e12c5d1SDavid du Colombier 				if (*p1 <= i) *p1 = p2[*p1];
12963e12c5d1SDavid du Colombier 			}
12973e12c5d1SDavid du Colombier 			break;
12983e12c5d1SDavid du Colombier 	}
12993e12c5d1SDavid du Colombier 
13003e12c5d1SDavid du Colombier }
13013e12c5d1SDavid du Colombier 
13023e12c5d1SDavid du Colombier void
13033e12c5d1SDavid du Colombier putline(Biobuf *bp, Rune *buf, int n)
13043e12c5d1SDavid du Colombier {
13053e12c5d1SDavid du Colombier 	while (n--)
13063e12c5d1SDavid du Colombier 		Bputrune(bp, *buf++);
13073e12c5d1SDavid du Colombier 	Bputc(bp, '\n');
13083e12c5d1SDavid du Colombier }
13093e12c5d1SDavid du Colombier ecmp(Rune *a, Rune *b, int count)
13103e12c5d1SDavid du Colombier {
13113e12c5d1SDavid du Colombier 	while(count--)
13123e12c5d1SDavid du Colombier 		if(*a++ != *b++)	return(0);
13133e12c5d1SDavid du Colombier 	return(1);
13143e12c5d1SDavid du Colombier }
13153e12c5d1SDavid du Colombier 
13163e12c5d1SDavid du Colombier void
13173e12c5d1SDavid du Colombier arout(void)
13183e12c5d1SDavid du Colombier {
13193e12c5d1SDavid du Colombier 	Rune	*p1;
13203e12c5d1SDavid du Colombier 	Biobuf	*fi;
13213e12c5d1SDavid du Colombier 	int	c;
13223e12c5d1SDavid du Colombier 	char	*s;
13233e12c5d1SDavid du Colombier 	char	buf[128];
13243e12c5d1SDavid du Colombier 
13253e12c5d1SDavid du Colombier 	for (aptr = abuf; *aptr; aptr++) {
13263e12c5d1SDavid du Colombier 		if((*aptr)->command == ACOM) {
13273e12c5d1SDavid du Colombier 			for(p1 = (*aptr)->text; *p1; p1++ )
13283e12c5d1SDavid du Colombier 				Bputrune(&fout, *p1);
13293e12c5d1SDavid du Colombier 			Bputc(&fout, '\n');
13303e12c5d1SDavid du Colombier 		} else {
13313e12c5d1SDavid du Colombier 			for(s = buf, p1= (*aptr)->text; *p1; p1++)
13323e12c5d1SDavid du Colombier 					s += runetochar(s, p1);
13333e12c5d1SDavid du Colombier 			*s = '\0';
13343e12c5d1SDavid du Colombier 			if((fi = Bopen(buf, OREAD)) == 0)
13353e12c5d1SDavid du Colombier 				continue;
13363e12c5d1SDavid du Colombier 			while((c = Bgetc(fi)) >= 0)
13373e12c5d1SDavid du Colombier 				Bputc(&fout, c);
1338*219b2ee8SDavid du Colombier 			Bterm(fi);
13393e12c5d1SDavid du Colombier 		}
13403e12c5d1SDavid du Colombier 	}
13413e12c5d1SDavid du Colombier 	aptr = abuf;
13423e12c5d1SDavid du Colombier 	*aptr = 0;
13433e12c5d1SDavid du Colombier }
13443e12c5d1SDavid du Colombier 
13453e12c5d1SDavid du Colombier void
13463e12c5d1SDavid du Colombier errexit(void)
13473e12c5d1SDavid du Colombier {
13483e12c5d1SDavid du Colombier 	exits("error");
13493e12c5d1SDavid du Colombier }
13503e12c5d1SDavid du Colombier 
13513e12c5d1SDavid du Colombier void
13523e12c5d1SDavid du Colombier quit (char *msg, char *arg)
13533e12c5d1SDavid du Colombier {
13543e12c5d1SDavid du Colombier 	fprint(2, "sed: ");
13553e12c5d1SDavid du Colombier 	fprint(2, msg, arg);
13563e12c5d1SDavid du Colombier 	fprint(2, "\n");
13573e12c5d1SDavid du Colombier 	errexit();
13583e12c5d1SDavid du Colombier }
13593e12c5d1SDavid du Colombier 
13603e12c5d1SDavid du Colombier Rune *
13613e12c5d1SDavid du Colombier gline(Rune *addr)
13623e12c5d1SDavid du Colombier {
13633e12c5d1SDavid du Colombier 	long	c;
13643e12c5d1SDavid du Colombier 	Rune *p;
13653e12c5d1SDavid du Colombier 
13663e12c5d1SDavid du Colombier 	static long peekc = 0;
13673e12c5d1SDavid du Colombier 
13683e12c5d1SDavid du Colombier 	if (f == 0 && opendata() < 0)
13693e12c5d1SDavid du Colombier 		return 0;
13703e12c5d1SDavid du Colombier 	sflag = 0;
13713e12c5d1SDavid du Colombier 	lnum++;
13723e12c5d1SDavid du Colombier /*	Bflush(&fout);********* dumped 4/30/92 - bobf****/
13733e12c5d1SDavid du Colombier 	do {
13743e12c5d1SDavid du Colombier 		p = addr;
1375*219b2ee8SDavid du Colombier 		for (c = (peekc ? peekc : Bgetrune(f)); c >= 0; c = Bgetrune(f)) {
13763e12c5d1SDavid du Colombier 			if (c == '\n') {
13773e12c5d1SDavid du Colombier 				if ((peekc = Bgetrune(f)) < 0) {
1378*219b2ee8SDavid du Colombier 					Bterm(f);
13793e12c5d1SDavid du Colombier 					if (fhead == 0)
13803e12c5d1SDavid du Colombier 						dolflag = 1;
13813e12c5d1SDavid du Colombier 				}
13823e12c5d1SDavid du Colombier 				*p = '\0';
13833e12c5d1SDavid du Colombier 				return p;
13843e12c5d1SDavid du Colombier 			}
13853e12c5d1SDavid du Colombier 			if (c && p < lbend)
13863e12c5d1SDavid du Colombier 				*p++ = c;
13873e12c5d1SDavid du Colombier 		}
13883e12c5d1SDavid du Colombier 		peekc = 0;
13893e12c5d1SDavid du Colombier 	} while (opendata() > 0);	/* Switch to next stream */
13903e12c5d1SDavid du Colombier 	return 0;
13913e12c5d1SDavid du Colombier }
13923e12c5d1SDavid du Colombier 
13933e12c5d1SDavid du Colombier 	/* Data file input section - the intent is to transparently
13943e12c5d1SDavid du Colombier 	 *	catenate all data input streams.
13953e12c5d1SDavid du Colombier 	 */
13963e12c5d1SDavid du Colombier void
13973e12c5d1SDavid du Colombier enroll(char *filename)		/* Add a file to the input file cache */
13983e12c5d1SDavid du Colombier {
13993e12c5d1SDavid du Colombier 	FileCache *fp;
14003e12c5d1SDavid du Colombier 
14013e12c5d1SDavid du Colombier 	if ((fp = (FileCache *) malloc(sizeof (FileCache))) == 0)
14023e12c5d1SDavid du Colombier 		quit("Out of memory", 0);
14033e12c5d1SDavid du Colombier 	if (ftail == 0)
14043e12c5d1SDavid du Colombier 		fhead = fp;
14053e12c5d1SDavid du Colombier 	else
14063e12c5d1SDavid du Colombier 		ftail->next = fp;
14073e12c5d1SDavid du Colombier 	ftail = fp;
14083e12c5d1SDavid du Colombier 	fp->next = 0;
14093e12c5d1SDavid du Colombier 	fp->name = filename;	/* 0 => stdin */
14103e12c5d1SDavid du Colombier }
14113e12c5d1SDavid du Colombier 
14123e12c5d1SDavid du Colombier int
14133e12c5d1SDavid du Colombier opendata(void)
14143e12c5d1SDavid du Colombier {
14153e12c5d1SDavid du Colombier 	if (fhead == 0)
14163e12c5d1SDavid du Colombier 		return -1;
14173e12c5d1SDavid du Colombier 	if (fhead->name) {
14183e12c5d1SDavid du Colombier 		if ((f = Bopen(fhead->name, OREAD)) == 0)
14193e12c5d1SDavid du Colombier 			quit("Can't open %s", fhead->name);
14203e12c5d1SDavid du Colombier 	} else {
14213e12c5d1SDavid du Colombier 		Binit(&stdin, 0, OREAD);
14223e12c5d1SDavid du Colombier 		f = &stdin;
14233e12c5d1SDavid du Colombier 	}
14243e12c5d1SDavid du Colombier 	fhead = fhead->next;
14253e12c5d1SDavid du Colombier 	return 1;
14263e12c5d1SDavid du Colombier }
1427