forsyth20121205-174063a80cc13 years agoHistory
1459 lines · 26.2 KB · C
RawDownload
/* * sed -- stream editor */#include <lib9.h>#include <bio.h>#include <regexp.h> enum {	DEPTH		= 20,		/* max nesting depth of {} */	MAXCMDS		= 512,		/* max sed commands */	ADDSIZE		= 10000,	/* size of add & read buffer */	MAXADDS		= 20,		/* max pending adds and reads */	LBSIZE		= 8192,		/* input line size */	LABSIZE		= 50,		/* max number of labels */	MAXSUB		= 10,		/* max number of sub reg exp */	MAXFILES	= 120		/* max output files */}; /* * An address is a line #, a R.E., "$", a reference to the last * R.E., or nothing. */typedef struct {	enum {		A_NONE,		A_DOL,		A_LINE,		A_RE,		A_LAST	}type;/*	union { */		long	line;		/* Line # */		Reprog	*rp;		/* Compiled R.E. *//*	}; */} Addr; typedef struct	SEDCOM {	Addr	ad1;			/* optional start address */	Addr	ad2;			/* optional end address *//*	union { */		Reprog	*re1;		/* compiled R.E. */		Rune	*text;		/* added text or file name */		struct	SEDCOM	*lb1;	/* destination command of branch *//*	}; */	Rune	*rhs;			/* Right-hand side of substitution */	Biobuf*	fcode;			/* File ID for read and write */	char	command;		/* command code -see below */	char	gfl;			/* 'Global' flag for substitutions */	char	pfl;			/* 'print' flag for substitutions */	char	active;			/* 1 => data between start and end */	char	negfl;			/* negation flag */} SedCom; /* Command Codes for field SedCom.command */#define ACOM	01#define BCOM	020#define CCOM	02#define	CDCOM	025#define	CNCOM	022#define COCOM	017#define	CPCOM	023#define DCOM	03#define ECOM	015#define EQCOM	013#define FCOM	016#define GCOM	027#define CGCOM	030#define HCOM	031#define CHCOM	032#define ICOM	04#define LCOM	05#define NCOM	012#define PCOM	010#define QCOM	011#define RCOM	06#define SCOM	07#define TCOM	021#define WCOM	014#define	CWCOM	024#define	YCOM	026#define XCOM	033 typedef struct label {			/* Label symbol table */	Rune	uninm[9];		/* Label name */	SedCom	*chain;	SedCom	*address;		/* Command associated with label */} Label; typedef	struct	FILE_CACHE {		/* Data file control block */	struct FILE_CACHE *next;	/* Forward Link */	char	*name;			/* Name of file */} FileCache; SedCom pspace[MAXCMDS];			/* Command storage */SedCom *pend = pspace+MAXCMDS;		/* End of command storage */SedCom *rep = pspace;			/* Current fill point */ Reprog	*lastre = 0;			/* Last regular expression */Resub	subexp[MAXSUB];			/* sub-patterns of pattern match*/ Rune	addspace[ADDSIZE];		/* Buffer for a, c, & i commands */Rune	*addend = addspace+ADDSIZE; SedCom	*abuf[MAXADDS];			/* Queue of pending adds & reads */SedCom	**aptr = abuf; struct {				/* Sed program input control block */	enum PTYPE { 			/* Either on command line or in file */		P_ARG,		P_FILE	} type;/*	union PCTL { */			/* Pointer to data */		Biobuf	*bp;		char	*curr;/*	}; */} prog; Rune	genbuf[LBSIZE];			/* Miscellaneous buffer */ FileCache	*fhead = 0;		/* Head of File Cache Chain */FileCache	*ftail = 0;		/* Tail of File Cache Chain */ Rune	*loc1;				/* Start of pattern match */Rune	*loc2;				/* End of pattern match */Rune	seof;				/* Pattern delimiter char */ Rune	linebuf[LBSIZE+1];		/* Input data buffer */Rune	*lbend = linebuf+LBSIZE;	/* End of buffer */Rune	*spend = linebuf;		/* End of input data */Rune	*cp;				/* Current scan point in linebuf */ Rune	holdsp[LBSIZE+1];		/* Hold buffer */Rune	*hend = holdsp+LBSIZE;		/* End of hold buffer */Rune	*hspend = holdsp;		/* End of hold data */ int	nflag;				/* Command line flags */int	gflag; int	dolflag;			/* Set when at true EOF */int	sflag;				/* Set when substitution done */int	jflag;				/* Set when jump required */int	delflag;			/* Delete current line when set */ long	lnum = 0;			/* Input line count */ char	fname[MAXFILES][40];		/* File name cache */Biobuf	*fcode[MAXFILES];		/* File ID cache */int	nfiles = 0;			/* Cache fill point */ Biobuf	fout;				/* Output stream */Biobuf	bstdin;				/* Default input */Biobuf*	f = 0;				/* Input data */ Label	ltab[LABSIZE];			/* Label name symbol table */Label	*labend = ltab+LABSIZE;		/* End of label table */Label	*lab = ltab+1;			/* Current Fill point */ int	depth = 0;			/* {} stack pointer */ Rune	bad;				/* Dummy err ptr reference */Rune	*badp = &bad;  char	CGMES[]	 = 	"command garbled: %S";char	TMMES[]	 = 	"Too much text: %S";char	LTL[]	 = 	"Label too long: %S";char	AD0MES[] =	"No addresses allowed: %S";char	AD1MES[] =	"Only one address allowed: %S"; void	address(Addr *);void	arout(void);int	cmp(char *, char *);int	rcmp(Rune *, Rune *);void	command(SedCom *);Reprog	*compile(void);Rune	*compsub(Rune *, Rune *);void	dechain(void);void	dosub(Rune *);int	ecmp(Rune *, Rune *, int);void	enroll(char *);void	errexit(void);int	executable(SedCom *);void	execute(void);void	fcomp(void);long	getrune(void);Rune	*gline(Rune *);int	match(Reprog *, Rune *);void	newfile(enum PTYPE, char *);int 	opendata(void);Biobuf	*open_file(char *);Rune	*place(Rune *, Rune *, Rune *);void	quit(char *, ...);int	rline(Rune *, Rune *);Label	*search(Label *);int	substitute(SedCom *);char	*text(char *);Rune	*stext(Rune *, Rune *);int	ycomp(SedCom *);char *	trans(int c);void	putline(Biobuf *bp, Rune *buf, int n); voidmain(int argc, char **argv){	int compfl; 	lnum = 0;	Binit(&fout, 1, OWRITE);	fcode[nfiles++] = &fout;	compfl = 0; 	if(argc == 1)		exits(0);	ARGBEGIN{	case 'e':		if (argc <= 1)			quit("missing pattern");		newfile(P_ARG, ARGF());		fcomp();		compfl = 1;		continue;	case 'f':		if(argc <= 1)			quit("no pattern-file");		newfile(P_FILE, ARGF());		fcomp();		compfl = 1;		continue;	case 'g':		gflag++;		continue;	case 'n':		nflag++;		continue;	default:		fprint(2, "sed: Unknown flag: %c\n", ARGC());		continue;	} ARGEND 	if(compfl == 0) {		if (--argc < 0)			quit("missing pattern");		newfile(P_ARG, *argv++);		fcomp();	} 	if(depth)		quit("Too many {'s"); 	ltab[0].address = rep; 	dechain(); 	if(argc <= 0)		enroll(0);		/* Add stdin to cache */	else		while(--argc >= 0)			enroll(*argv++);	execute();	exits(0);} voidfcomp(void){	int	i;	Label	*lpt;	Rune	*tp;	SedCom	*pt, *pt1;	static Rune	*p = addspace;	static SedCom	**cmpend[DEPTH];	/* stack of {} operations */ 	while (rline(linebuf, lbend) >= 0) {		cp = linebuf;comploop:		while(*cp == ' ' || *cp == '\t')			cp++;		if(*cp == '\0' || *cp == '#')			continue;		if(*cp == ';') {			cp++;			goto comploop;		} 		address(&rep->ad1);		if (rep->ad1.type != A_NONE) {			if (rep->ad1.type == A_LAST) {				if (!lastre)					quit("First RE may not be null");				rep->ad1.type = A_RE;				rep->ad1.rp = lastre;			}			if(*cp == ',' || *cp == ';') {				cp++;				address(&rep->ad2);				if (rep->ad2.type == A_LAST) {					rep->ad2.type = A_RE;					rep->ad2.rp = lastre;				}			} else				rep->ad2.type = A_NONE;		}		while(*cp == ' ' || *cp == '\t')			cp++; swit:		switch(*cp++) {		default:			quit("Unrecognized command: %S", linebuf); 		case '!':			rep->negfl = 1;			goto swit; 		case '{':			rep->command = BCOM;			rep->negfl = !rep->negfl;			cmpend[depth++] = &rep->lb1;			if(++rep >= pend)				quit("Too many commands: %S", linebuf);			if(*cp == '\0')				continue;			goto comploop; 		case '}':			if(rep->ad1.type != A_NONE)				quit(AD0MES, linebuf);			if(--depth < 0)				quit("Too many }'s");			*cmpend[depth] = rep;			if(*cp == 0)				continue;			goto comploop; 		case '=':			rep->command = EQCOM;			if(rep->ad2.type != A_NONE)				quit(AD1MES, linebuf);			break; 		case ':':			if(rep->ad1.type != A_NONE)				quit(AD0MES, linebuf); 			while(*cp == ' ')				cp++;			tp = lab->uninm;			while (*cp && *cp != ';' && *cp != ' ' &&			    *cp != '\t' && *cp != '#') {				*tp++ = *cp++;				if(tp >= &lab->uninm[8])					quit(LTL, linebuf);			}			*tp = '\0'; 			if (*lab->uninm == '\0')		/* no label? */				quit(CGMES, linebuf);			if(lpt = search(lab)) {				if(lpt->address)					quit("Duplicate labels: %S", linebuf);			} else {				lab->chain = 0;				lpt = lab;				if(++lab >= labend)					quit("Too many labels: %S", linebuf);			}			lpt->address = rep;			if (*cp == '#')				continue;			rep--;			/* reuse this slot */			break; 		case 'a':			rep->command = ACOM;			if(rep->ad2.type != A_NONE)				quit(AD1MES, linebuf);			if(*cp == '\\')				cp++;			if(*cp++ != '\n')				quit(CGMES, linebuf);			rep->text = p;			p = stext(p, addend);			break;		case 'c':			rep->command = CCOM;			if(*cp == '\\')				cp++;			if(*cp++ != '\n')				quit(CGMES, linebuf);			rep->text = p;			p = stext(p, addend);			break;		case 'i':			rep->command = ICOM;			if(rep->ad2.type != A_NONE)				quit(AD1MES, linebuf);			if(*cp == '\\')				cp++;			if(*cp++ != '\n')				quit(CGMES, linebuf);			rep->text = p;			p = stext(p, addend);			break; 		case 'g':			rep->command = GCOM;			break; 		case 'G':			rep->command = CGCOM;			break; 		case 'h':			rep->command = HCOM;			break; 		case 'H':			rep->command = CHCOM;			break; 		case 't':			rep->command = TCOM;			goto jtcommon; 		case 'b':			rep->command = BCOM;jtcommon:			while(*cp == ' ')				cp++;			if(*cp == '\0' || *cp == ';') {				/* no label; jump to end */				if(pt = ltab[0].chain) {					while((pt1 = pt->lb1) != nil)						pt = pt1;					pt->lb1 = rep;				} else					ltab[0].chain = rep;				break;			} 			/* copy label into lab->uninm */			tp = lab->uninm;			while((*tp = *cp++) != '\0' && *tp != ';')				if(++tp >= &lab->uninm[8])					quit(LTL, linebuf);			cp--;			*tp = '\0'; 			if (*lab->uninm == '\0')				/* shouldn't get here */				quit(CGMES, linebuf);			if((lpt = search(lab)) != nil) {				if(lpt->address)					rep->lb1 = lpt->address;				else {					for(pt = lpt->chain; pt != nil &&					    (pt1 = pt->lb1) != nil; pt = pt1)						;					if (pt)						pt->lb1 = rep;				}			} else {			/* add new label */				lab->chain = rep;				lab->address = 0;				if(++lab >= labend)					quit("Too many labels: %S", linebuf);			}			break; 		case 'n':			rep->command = NCOM;			break; 		case 'N':			rep->command = CNCOM;			break; 		case 'p':			rep->command = PCOM;			break; 		case 'P':			rep->command = CPCOM;			break; 		case 'r':			rep->command = RCOM;			if(rep->ad2.type != A_NONE)				quit(AD1MES, linebuf);			if(*cp++ != ' ')				quit(CGMES, linebuf);			rep->text = p;			p = stext(p, addend);			break; 		case 'd':			rep->command = DCOM;			break; 		case 'D':

Lines 1–500 of 1459.