552 lines · 8.8 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 7.  Macros, strings, diversion, and position traps. * * 	macros can override builtins *	builtins can be renamed or removed! */ #include "a.h" enum{	MAXARG = 10,	MAXMSTACK = 40}; /* macro invocation frame */typedef struct Mac Mac;struct Mac{	int argc;	Rune *argv[MAXARG];}; Mac		mstack[MAXMSTACK];int		nmstack;void		emitdi(void);void		flushdi(void); /* * Run a user-defined macro. */void popmacro(void);intrunmacro(int dot, int argc, Rune **argv){	Rune *p;	int i;	Mac *m;	if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]);	p = getds(argv[0]);	if(p == nil){		if(verbose)			warn("ignoring unknown request %C%S", dot, argv[0]);		if(verbose > 1){			for(i=0; i<argc; i++)				fprint(2, " %S", argv[i]);			fprint(2, "\n");		}		return -1;	}	if(nmstack >= nelem(mstack)){		fprint(2, "%L: macro stack overflow:");		for(i=0; i<nmstack; i++)			fprint(2, " %S", mstack[i].argv[0]);		fprint(2, "\n");		return -1;	}	m = &mstack[nmstack++];	m->argc = argc;	for(i=0; i<argc; i++)		m->argv[i] = erunestrdup(argv[i]);	pushinputstring(p);	nr(L(".$"), argc-1);	inputnotify(popmacro);	return 0;} voidpopmacro(void){	int i;	Mac *m;		if(--nmstack < 0){		fprint(2, "%L: macro stack underflow\n");		return;	}	m = &mstack[nmstack];	for(i=0; i<m->argc; i++)		free(m->argv[i]);	if(nmstack > 0)		nr(L(".$"), mstack[nmstack-1].argc-1);	else		nr(L(".$"), 0);} void popmacro1(void);jmp_buf runjb[10];int nrunjb; voidrunmacro1(Rune *name){	Rune *argv[2];	int obol;	if(verbose) fprint(2, "outcb %p\n", outcb);	obol = bol;	argv[0] = name;	argv[1] = nil;	bol = 1;	if(runmacro('.', 1, argv) >= 0){		inputnotify(popmacro1);		if(!setjmp(runjb[nrunjb++]))			runinput();		else			if(verbose) fprint(2, "finished %S\n", name);	}	bol = obol;} voidpopmacro1(void){	popmacro();	if(nrunjb >= 0)		longjmp(runjb[--nrunjb], 1);} /* * macro arguments * *	"" means " inside " " *	"" empty string *	\newline can be done *	argument separator is space (not tab) *	number register .$ = number of arguments *	no arguments outside macros or in strings * *	arguments copied in copy mode */ /* * diversions * *	processed output diverted  *	dn dl registers vertical and horizontal size of last diversion *	.z - current diversion name */ /* * traps * *	skip most *	.t register - distance to next trap */static Rune *trap0; voidouttrap(void){	Rune *t; 	if(outcb)		return;	if(trap0){if(verbose) fprint(2, "trap: %S\n", trap0);		t = trap0;		trap0 = nil;		runmacro1(t);		free(t);	}} /* .wh - install trap */voidr_wh(int argc, Rune **argv){	int i; 	if(argc < 2)		return; 	i = eval(argv[1]);	if(argc == 2){		if(i == 0){			free(trap0);			trap0 = nil;		}else			if(verbose)				warn("not removing trap at %d", i);	}	if(argc > 2){		if(i == 0){			free(trap0);			trap0 = erunestrdup(argv[2]);		}else			if(verbose)				warn("not installing %S trap at %d", argv[2], i);	}} voidr_ch(int argc, Rune **argv){	int i;		if(argc == 2){		if(trap0 && runestrcmp(argv[1], trap0) == 0){			free(trap0);			trap0 = nil;		}else			if(verbose)				warn("not removing %S trap", argv[1]);		return;	}	if(argc >= 3){		i = eval(argv[2]);		if(i == 0){			free(trap0);			trap0 = erunestrdup(argv[1]);		}else			if(verbose)				warn("not moving %S trap to %d", argv[1], i);	}} voidr_dt(int argc, Rune **argv){	USED(argc);	USED(argv);	warn("ignoring diversion trap");} /* define macro - .de, .am, .ig */voidr_de(int argc, Rune **argv){	Rune *end, *p;	Fmt fmt;	int ignore, len; 	delreq(argv[1]);	delraw(argv[1]);	ignore = runestrcmp(argv[0], L("ig")) == 0;	if(!ignore)		runefmtstrinit(&fmt);	end = L("..");	if(argc >= 3)		end = argv[2];	if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil)		fmtrunestrcpy(&fmt, p);	len = runestrlen(end);	while((p = readline(CopyMode)) != nil){		if(runestrncmp(p, end, len) == 0 		&& (p[len]==' ' || p[len]==0 || p[len]=='\t'			|| (p[len]=='\\' && p[len+1]=='}'))){			free(p);			goto done;		}		if(!ignore)			fmtprint(&fmt, "%S\n", p);		free(p);	}	warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end);done:	if(ignore)		return;	p = runefmtstrflush(&fmt);	if(p == nil)		sysfatal("out of memory");	ds(argv[1], p);	free(p);} /* define string .ds .as */voidr_ds(Rune *cmd){	Rune *name, *line, *p;		name = copyarg();	line = readline(CopyMode);	if(name == nil || line == nil){		free(name);		return;	}	p = line;	if(*p == '"')		p++;	if(cmd[0] == 'd')		ds(name, p);	else		as(name, p);	free(name);	free(line);} /* remove request, macro, or string */voidr_rm(int argc, Rune **argv){	int i; 	emitdi();	for(i=1; i<argc; i++){		delreq(argv[i]);		delraw(argv[i]);		ds(argv[i], nil);	}} /* .rn - rename request, macro, or string */voidr_rn(int argc, Rune **argv){	USED(argc);	renreq(argv[1], argv[2]);	renraw(argv[1], argv[2]);	ds(argv[2], getds(argv[1]));	ds(argv[1], nil);} /* .di - divert output to macro xx *//* .da - divert, appending to macro *//* page offsetting is not done! */Fmt difmt;int difmtinit;Rune di[20][100];int ndi; voidemitdi(void){	flushdi();	runefmtstrinit(&difmt);	difmtinit = 1;	fmtrune(&difmt, Uformatted);} voidflushdi(void){	int n;	Rune *p;		if(ndi == 0 || difmtinit == 0)		return;	fmtrune(&difmt, Uunformatted);	p = runefmtstrflush(&difmt);	memset(&difmt, 0, sizeof difmt);	difmtinit = 0;	if(p == nil)		warn("out of memory in diversion %C%S", dot, di[ndi-1]);	else{		n = runestrlen(p);		if(n > 0 && p[n-1] != '\n'){			p = runerealloc(p, n+2);			p[n] = '\n';			p[n+1] = 0;		}	}	as(di[ndi-1], p);	free(p);} voidoutdi(Rune r){if(!difmtinit) abort();	if(r == Uempty)		return;	fmtrune(&difmt, r);} /* .di, .da */voidr_di(int argc, Rune **argv){	br();	if(argc > 2)		warn("extra arguments to %C%S", dot, argv[0]);	if(argc == 1){		/* end diversion */		if(ndi <= 0){			// warn("unmatched %C%S", dot, argv[0]);			return;		}		flushdi();		if(--ndi == 0){			_nr(L(".z"), nil);			outcb = nil;		}else{			_nr(L(".z"), di[ndi-1]);			runefmtstrinit(&difmt);			fmtrune(&difmt, Uformatted);			difmtinit = 1;		}		return;	}	/* start diversion */	/* various register state should be saved, but it's all useless to us */	flushdi();	if(ndi >= nelem(di))		sysfatal("%Cdi overflow", dot);	if(argv[0][1] == 'i')		ds(argv[1], nil);	_nr(L(".z"), argv[1]);	runestrcpy(di[ndi++], argv[1]);	runefmtstrinit(&difmt);	fmtrune(&difmt, Uformatted);	difmtinit = 1;	outcb = outdi;} /* .wh - install trap *//* .ch - change trap *//* .dt - install diversion trap */ /* set input-line count trap */int itrapcount;int itrapwaiting;Rune *itrapname; voidr_it(int argc, Rune **argv){	if(argc < 3){		itrapcount = 0;		return;	}	itrapcount = eval(argv[1]);	free(itrapname);	itrapname = erunestrdup(argv[2]);} voiditrap(void){	itrapset();	if(itrapwaiting){		itrapwaiting = 0;		runmacro1(itrapname);	}} voiditrapset(void){	if(itrapcount > 0 && --itrapcount == 0)		itrapwaiting = 1;} /* .em - invoke macro when all input is over */voidr_em(int argc, Rune **argv){	Rune buf[20];		USED(argc);	runesnprint(buf, nelem(buf), ".%S\n", argv[1]);	as(L("eof"), buf);} inte_star(void){	Rune *p;		p = getds(getname());	if(p)		pushinputstring(p);	return 0;} inte_t(void){	if(inputmode&CopyMode)		return '\t';	return 0;} inte_a(void){	if(inputmode&CopyMode)		return '\a';	return 0;} inte_backslash(void){	if(inputmode&ArgMode)		ungetrune('\\');	return backslash;} 

Lines 1–500 of 552.