xref: /plan9/sys/src/cmd/htmlroff/t7.c (revision 426d2b71458df9b491ba6c167f699b3f1f7b0428)
1*426d2b71SDavid du Colombier /*
2*426d2b71SDavid du Colombier  * 7.  Macros, strings, diversion, and position traps.
3*426d2b71SDavid du Colombier  *
4*426d2b71SDavid du Colombier  * 	macros can override builtins
5*426d2b71SDavid du Colombier  *	builtins can be renamed or removed!
6*426d2b71SDavid du Colombier  */
7*426d2b71SDavid du Colombier 
8*426d2b71SDavid du Colombier #include "a.h"
9*426d2b71SDavid du Colombier 
10*426d2b71SDavid du Colombier enum
11*426d2b71SDavid du Colombier {
12*426d2b71SDavid du Colombier 	MAXARG = 10,
13*426d2b71SDavid du Colombier 	MAXMSTACK = 40
14*426d2b71SDavid du Colombier };
15*426d2b71SDavid du Colombier 
16*426d2b71SDavid du Colombier /* macro invocation frame */
17*426d2b71SDavid du Colombier typedef struct Mac Mac;
18*426d2b71SDavid du Colombier struct Mac
19*426d2b71SDavid du Colombier {
20*426d2b71SDavid du Colombier 	int argc;
21*426d2b71SDavid du Colombier 	Rune *argv[MAXARG];
22*426d2b71SDavid du Colombier };
23*426d2b71SDavid du Colombier 
24*426d2b71SDavid du Colombier Mac		mstack[MAXMSTACK];
25*426d2b71SDavid du Colombier int		nmstack;
26*426d2b71SDavid du Colombier void		emitdi(void);
27*426d2b71SDavid du Colombier void		flushdi(void);
28*426d2b71SDavid du Colombier 
29*426d2b71SDavid du Colombier /*
30*426d2b71SDavid du Colombier  * Run a user-defined macro.
31*426d2b71SDavid du Colombier  */
32*426d2b71SDavid du Colombier void popmacro(void);
33*426d2b71SDavid du Colombier int
runmacro(int dot,int argc,Rune ** argv)34*426d2b71SDavid du Colombier runmacro(int dot, int argc, Rune **argv)
35*426d2b71SDavid du Colombier {
36*426d2b71SDavid du Colombier 	Rune *p;
37*426d2b71SDavid du Colombier 	int i;
38*426d2b71SDavid du Colombier 	Mac *m;
39*426d2b71SDavid du Colombier 
40*426d2b71SDavid du Colombier if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]);
41*426d2b71SDavid du Colombier 	p = getds(argv[0]);
42*426d2b71SDavid du Colombier 	if(p == nil){
43*426d2b71SDavid du Colombier 		if(verbose)
44*426d2b71SDavid du Colombier 			warn("ignoring unknown request %C%S", dot, argv[0]);
45*426d2b71SDavid du Colombier 		if(verbose > 1){
46*426d2b71SDavid du Colombier 			for(i=0; i<argc; i++)
47*426d2b71SDavid du Colombier 				fprint(2, " %S", argv[i]);
48*426d2b71SDavid du Colombier 			fprint(2, "\n");
49*426d2b71SDavid du Colombier 		}
50*426d2b71SDavid du Colombier 		return -1;
51*426d2b71SDavid du Colombier 	}
52*426d2b71SDavid du Colombier 	if(nmstack >= nelem(mstack)){
53*426d2b71SDavid du Colombier 		fprint(2, "%L: macro stack overflow:");
54*426d2b71SDavid du Colombier 		for(i=0; i<nmstack; i++)
55*426d2b71SDavid du Colombier 			fprint(2, " %S", mstack[i].argv[0]);
56*426d2b71SDavid du Colombier 		fprint(2, "\n");
57*426d2b71SDavid du Colombier 		return -1;
58*426d2b71SDavid du Colombier 	}
59*426d2b71SDavid du Colombier 	m = &mstack[nmstack++];
60*426d2b71SDavid du Colombier 	m->argc = argc;
61*426d2b71SDavid du Colombier 	for(i=0; i<argc; i++)
62*426d2b71SDavid du Colombier 		m->argv[i] = erunestrdup(argv[i]);
63*426d2b71SDavid du Colombier 	pushinputstring(p);
64*426d2b71SDavid du Colombier 	nr(L(".$"), argc-1);
65*426d2b71SDavid du Colombier 	inputnotify(popmacro);
66*426d2b71SDavid du Colombier 	return 0;
67*426d2b71SDavid du Colombier }
68*426d2b71SDavid du Colombier 
69*426d2b71SDavid du Colombier void
popmacro(void)70*426d2b71SDavid du Colombier popmacro(void)
71*426d2b71SDavid du Colombier {
72*426d2b71SDavid du Colombier 	int i;
73*426d2b71SDavid du Colombier 	Mac *m;
74*426d2b71SDavid du Colombier 
75*426d2b71SDavid du Colombier 	if(--nmstack < 0){
76*426d2b71SDavid du Colombier 		fprint(2, "%L: macro stack underflow\n");
77*426d2b71SDavid du Colombier 		return;
78*426d2b71SDavid du Colombier 	}
79*426d2b71SDavid du Colombier 	m = &mstack[nmstack];
80*426d2b71SDavid du Colombier 	for(i=0; i<m->argc; i++)
81*426d2b71SDavid du Colombier 		free(m->argv[i]);
82*426d2b71SDavid du Colombier 	if(nmstack > 0)
83*426d2b71SDavid du Colombier 		nr(L(".$"), mstack[nmstack-1].argc-1);
84*426d2b71SDavid du Colombier 	else
85*426d2b71SDavid du Colombier 		nr(L(".$"), 0);
86*426d2b71SDavid du Colombier }
87*426d2b71SDavid du Colombier 
88*426d2b71SDavid du Colombier void popmacro1(void);
89*426d2b71SDavid du Colombier jmp_buf runjb[10];
90*426d2b71SDavid du Colombier int nrunjb;
91*426d2b71SDavid du Colombier 
92*426d2b71SDavid du Colombier void
runmacro1(Rune * name)93*426d2b71SDavid du Colombier runmacro1(Rune *name)
94*426d2b71SDavid du Colombier {
95*426d2b71SDavid du Colombier 	Rune *argv[2];
96*426d2b71SDavid du Colombier 	int obol;
97*426d2b71SDavid du Colombier 
98*426d2b71SDavid du Colombier if(verbose) fprint(2, "outcb %p\n", outcb);
99*426d2b71SDavid du Colombier 	obol = bol;
100*426d2b71SDavid du Colombier 	argv[0] = name;
101*426d2b71SDavid du Colombier 	argv[1] = nil;
102*426d2b71SDavid du Colombier 	bol = 1;
103*426d2b71SDavid du Colombier 	if(runmacro('.', 1, argv) >= 0){
104*426d2b71SDavid du Colombier 		inputnotify(popmacro1);
105*426d2b71SDavid du Colombier 		if(!setjmp(runjb[nrunjb++]))
106*426d2b71SDavid du Colombier 			runinput();
107*426d2b71SDavid du Colombier 		else
108*426d2b71SDavid du Colombier 			if(verbose) fprint(2, "finished %S\n", name);
109*426d2b71SDavid du Colombier 	}
110*426d2b71SDavid du Colombier 	bol = obol;
111*426d2b71SDavid du Colombier }
112*426d2b71SDavid du Colombier 
113*426d2b71SDavid du Colombier void
popmacro1(void)114*426d2b71SDavid du Colombier popmacro1(void)
115*426d2b71SDavid du Colombier {
116*426d2b71SDavid du Colombier 	popmacro();
117*426d2b71SDavid du Colombier 	if(nrunjb >= 0)
118*426d2b71SDavid du Colombier 		longjmp(runjb[--nrunjb], 1);
119*426d2b71SDavid du Colombier }
120*426d2b71SDavid du Colombier 
121*426d2b71SDavid du Colombier /*
122*426d2b71SDavid du Colombier  * macro arguments
123*426d2b71SDavid du Colombier  *
124*426d2b71SDavid du Colombier  *	"" means " inside " "
125*426d2b71SDavid du Colombier  *	"" empty string
126*426d2b71SDavid du Colombier  *	\newline can be done
127*426d2b71SDavid du Colombier  *	argument separator is space (not tab)
128*426d2b71SDavid du Colombier  *	number register .$ = number of arguments
129*426d2b71SDavid du Colombier  *	no arguments outside macros or in strings
130*426d2b71SDavid du Colombier  *
131*426d2b71SDavid du Colombier  *	arguments copied in copy mode
132*426d2b71SDavid du Colombier  */
133*426d2b71SDavid du Colombier 
134*426d2b71SDavid du Colombier /*
135*426d2b71SDavid du Colombier  * diversions
136*426d2b71SDavid du Colombier  *
137*426d2b71SDavid du Colombier  *	processed output diverted
138*426d2b71SDavid du Colombier  *	dn dl registers vertical and horizontal size of last diversion
139*426d2b71SDavid du Colombier  *	.z - current diversion name
140*426d2b71SDavid du Colombier  */
141*426d2b71SDavid du Colombier 
142*426d2b71SDavid du Colombier /*
143*426d2b71SDavid du Colombier  * traps
144*426d2b71SDavid du Colombier  *
145*426d2b71SDavid du Colombier  *	skip most
146*426d2b71SDavid du Colombier  *	.t register - distance to next trap
147*426d2b71SDavid du Colombier  */
148*426d2b71SDavid du Colombier static Rune *trap0;
149*426d2b71SDavid du Colombier 
150*426d2b71SDavid du Colombier void
outtrap(void)151*426d2b71SDavid du Colombier outtrap(void)
152*426d2b71SDavid du Colombier {
153*426d2b71SDavid du Colombier 	Rune *t;
154*426d2b71SDavid du Colombier 
155*426d2b71SDavid du Colombier 	if(outcb)
156*426d2b71SDavid du Colombier 		return;
157*426d2b71SDavid du Colombier 	if(trap0){
158*426d2b71SDavid du Colombier if(verbose) fprint(2, "trap: %S\n", trap0);
159*426d2b71SDavid du Colombier 		t = trap0;
160*426d2b71SDavid du Colombier 		trap0 = nil;
161*426d2b71SDavid du Colombier 		runmacro1(t);
162*426d2b71SDavid du Colombier 		free(t);
163*426d2b71SDavid du Colombier 	}
164*426d2b71SDavid du Colombier }
165*426d2b71SDavid du Colombier 
166*426d2b71SDavid du Colombier /* .wh - install trap */
167*426d2b71SDavid du Colombier void
r_wh(int argc,Rune ** argv)168*426d2b71SDavid du Colombier r_wh(int argc, Rune **argv)
169*426d2b71SDavid du Colombier {
170*426d2b71SDavid du Colombier 	int i;
171*426d2b71SDavid du Colombier 
172*426d2b71SDavid du Colombier 	if(argc < 2)
173*426d2b71SDavid du Colombier 		return;
174*426d2b71SDavid du Colombier 
175*426d2b71SDavid du Colombier 	i = eval(argv[1]);
176*426d2b71SDavid du Colombier 	if(argc == 2){
177*426d2b71SDavid du Colombier 		if(i == 0){
178*426d2b71SDavid du Colombier 			free(trap0);
179*426d2b71SDavid du Colombier 			trap0 = nil;
180*426d2b71SDavid du Colombier 		}else
181*426d2b71SDavid du Colombier 			if(verbose)
182*426d2b71SDavid du Colombier 				warn("not removing trap at %d", i);
183*426d2b71SDavid du Colombier 	}
184*426d2b71SDavid du Colombier 	if(argc > 2){
185*426d2b71SDavid du Colombier 		if(i == 0){
186*426d2b71SDavid du Colombier 			free(trap0);
187*426d2b71SDavid du Colombier 			trap0 = erunestrdup(argv[2]);
188*426d2b71SDavid du Colombier 		}else
189*426d2b71SDavid du Colombier 			if(verbose)
190*426d2b71SDavid du Colombier 				warn("not installing %S trap at %d", argv[2], i);
191*426d2b71SDavid du Colombier 	}
192*426d2b71SDavid du Colombier }
193*426d2b71SDavid du Colombier 
194*426d2b71SDavid du Colombier void
r_ch(int argc,Rune ** argv)195*426d2b71SDavid du Colombier r_ch(int argc, Rune **argv)
196*426d2b71SDavid du Colombier {
197*426d2b71SDavid du Colombier 	int i;
198*426d2b71SDavid du Colombier 
199*426d2b71SDavid du Colombier 	if(argc == 2){
200*426d2b71SDavid du Colombier 		if(trap0 && runestrcmp(argv[1], trap0) == 0){
201*426d2b71SDavid du Colombier 			free(trap0);
202*426d2b71SDavid du Colombier 			trap0 = nil;
203*426d2b71SDavid du Colombier 		}else
204*426d2b71SDavid du Colombier 			if(verbose)
205*426d2b71SDavid du Colombier 				warn("not removing %S trap", argv[1]);
206*426d2b71SDavid du Colombier 		return;
207*426d2b71SDavid du Colombier 	}
208*426d2b71SDavid du Colombier 	if(argc >= 3){
209*426d2b71SDavid du Colombier 		i = eval(argv[2]);
210*426d2b71SDavid du Colombier 		if(i == 0){
211*426d2b71SDavid du Colombier 			free(trap0);
212*426d2b71SDavid du Colombier 			trap0 = erunestrdup(argv[1]);
213*426d2b71SDavid du Colombier 		}else
214*426d2b71SDavid du Colombier 			if(verbose)
215*426d2b71SDavid du Colombier 				warn("not moving %S trap to %d", argv[1], i);
216*426d2b71SDavid du Colombier 	}
217*426d2b71SDavid du Colombier }
218*426d2b71SDavid du Colombier 
219*426d2b71SDavid du Colombier void
r_dt(int argc,Rune ** argv)220*426d2b71SDavid du Colombier r_dt(int argc, Rune **argv)
221*426d2b71SDavid du Colombier {
222*426d2b71SDavid du Colombier 	USED(argc);
223*426d2b71SDavid du Colombier 	USED(argv);
224*426d2b71SDavid du Colombier 	warn("ignoring diversion trap");
225*426d2b71SDavid du Colombier }
226*426d2b71SDavid du Colombier 
227*426d2b71SDavid du Colombier /* define macro - .de, .am, .ig */
228*426d2b71SDavid du Colombier void
r_de(int argc,Rune ** argv)229*426d2b71SDavid du Colombier r_de(int argc, Rune **argv)
230*426d2b71SDavid du Colombier {
231*426d2b71SDavid du Colombier 	Rune *end, *p;
232*426d2b71SDavid du Colombier 	Fmt fmt;
233*426d2b71SDavid du Colombier 	int ignore, len;
234*426d2b71SDavid du Colombier 
235*426d2b71SDavid du Colombier 	delreq(argv[1]);
236*426d2b71SDavid du Colombier 	delraw(argv[1]);
237*426d2b71SDavid du Colombier 	ignore = runestrcmp(argv[0], L("ig")) == 0;
238*426d2b71SDavid du Colombier 	if(!ignore)
239*426d2b71SDavid du Colombier 		runefmtstrinit(&fmt);
240*426d2b71SDavid du Colombier 	end = L("..");
241*426d2b71SDavid du Colombier 	if(argc >= 3)
242*426d2b71SDavid du Colombier 		end = argv[2];
243*426d2b71SDavid du Colombier 	if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil)
244*426d2b71SDavid du Colombier 		fmtrunestrcpy(&fmt, p);
245*426d2b71SDavid du Colombier 	len = runestrlen(end);
246*426d2b71SDavid du Colombier 	while((p = readline(CopyMode)) != nil){
247*426d2b71SDavid du Colombier 		if(runestrncmp(p, end, len) == 0
248*426d2b71SDavid du Colombier 		&& (p[len]==' ' || p[len]==0 || p[len]=='\t'
249*426d2b71SDavid du Colombier 			|| (p[len]=='\\' && p[len+1]=='}'))){
250*426d2b71SDavid du Colombier 			free(p);
251*426d2b71SDavid du Colombier 			goto done;
252*426d2b71SDavid du Colombier 		}
253*426d2b71SDavid du Colombier 		if(!ignore)
254*426d2b71SDavid du Colombier 			fmtprint(&fmt, "%S\n", p);
255*426d2b71SDavid du Colombier 		free(p);
256*426d2b71SDavid du Colombier 	}
257*426d2b71SDavid du Colombier 	warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end);
258*426d2b71SDavid du Colombier done:
259*426d2b71SDavid du Colombier 	if(ignore)
260*426d2b71SDavid du Colombier 		return;
261*426d2b71SDavid du Colombier 	p = runefmtstrflush(&fmt);
262*426d2b71SDavid du Colombier 	if(p == nil)
263*426d2b71SDavid du Colombier 		sysfatal("out of memory");
264*426d2b71SDavid du Colombier 	ds(argv[1], p);
265*426d2b71SDavid du Colombier 	free(p);
266*426d2b71SDavid du Colombier }
267*426d2b71SDavid du Colombier 
268*426d2b71SDavid du Colombier /* define string .ds .as */
269*426d2b71SDavid du Colombier void
r_ds(Rune * cmd)270*426d2b71SDavid du Colombier r_ds(Rune *cmd)
271*426d2b71SDavid du Colombier {
272*426d2b71SDavid du Colombier 	Rune *name, *line, *p;
273*426d2b71SDavid du Colombier 
274*426d2b71SDavid du Colombier 	name = copyarg();
275*426d2b71SDavid du Colombier 	line = readline(CopyMode);
276*426d2b71SDavid du Colombier 	if(name == nil || line == nil){
277*426d2b71SDavid du Colombier 		free(name);
278*426d2b71SDavid du Colombier 		return;
279*426d2b71SDavid du Colombier 	}
280*426d2b71SDavid du Colombier 	p = line;
281*426d2b71SDavid du Colombier 	if(*p == '"')
282*426d2b71SDavid du Colombier 		p++;
283*426d2b71SDavid du Colombier 	if(cmd[0] == 'd')
284*426d2b71SDavid du Colombier 		ds(name, p);
285*426d2b71SDavid du Colombier 	else
286*426d2b71SDavid du Colombier 		as(name, p);
287*426d2b71SDavid du Colombier 	free(name);
288*426d2b71SDavid du Colombier 	free(line);
289*426d2b71SDavid du Colombier }
290*426d2b71SDavid du Colombier 
291*426d2b71SDavid du Colombier /* remove request, macro, or string */
292*426d2b71SDavid du Colombier void
r_rm(int argc,Rune ** argv)293*426d2b71SDavid du Colombier r_rm(int argc, Rune **argv)
294*426d2b71SDavid du Colombier {
295*426d2b71SDavid du Colombier 	int i;
296*426d2b71SDavid du Colombier 
297*426d2b71SDavid du Colombier 	emitdi();
298*426d2b71SDavid du Colombier 	for(i=1; i<argc; i++){
299*426d2b71SDavid du Colombier 		delreq(argv[i]);
300*426d2b71SDavid du Colombier 		delraw(argv[i]);
301*426d2b71SDavid du Colombier 		ds(argv[i], nil);
302*426d2b71SDavid du Colombier 	}
303*426d2b71SDavid du Colombier }
304*426d2b71SDavid du Colombier 
305*426d2b71SDavid du Colombier /* .rn - rename request, macro, or string */
306*426d2b71SDavid du Colombier void
r_rn(int argc,Rune ** argv)307*426d2b71SDavid du Colombier r_rn(int argc, Rune **argv)
308*426d2b71SDavid du Colombier {
309*426d2b71SDavid du Colombier 	USED(argc);
310*426d2b71SDavid du Colombier 	renreq(argv[1], argv[2]);
311*426d2b71SDavid du Colombier 	renraw(argv[1], argv[2]);
312*426d2b71SDavid du Colombier 	ds(argv[2], getds(argv[1]));
313*426d2b71SDavid du Colombier 	ds(argv[1], nil);
314*426d2b71SDavid du Colombier }
315*426d2b71SDavid du Colombier 
316*426d2b71SDavid du Colombier /* .di - divert output to macro xx */
317*426d2b71SDavid du Colombier /* .da - divert, appending to macro */
318*426d2b71SDavid du Colombier /* page offsetting is not done! */
319*426d2b71SDavid du Colombier Fmt difmt;
320*426d2b71SDavid du Colombier int difmtinit;
321*426d2b71SDavid du Colombier Rune di[20][100];
322*426d2b71SDavid du Colombier int ndi;
323*426d2b71SDavid du Colombier 
324*426d2b71SDavid du Colombier void
emitdi(void)325*426d2b71SDavid du Colombier emitdi(void)
326*426d2b71SDavid du Colombier {
327*426d2b71SDavid du Colombier 	flushdi();
328*426d2b71SDavid du Colombier 	runefmtstrinit(&difmt);
329*426d2b71SDavid du Colombier 	difmtinit = 1;
330*426d2b71SDavid du Colombier 	fmtrune(&difmt, Uformatted);
331*426d2b71SDavid du Colombier }
332*426d2b71SDavid du Colombier 
333*426d2b71SDavid du Colombier void
flushdi(void)334*426d2b71SDavid du Colombier flushdi(void)
335*426d2b71SDavid du Colombier {
336*426d2b71SDavid du Colombier 	int n;
337*426d2b71SDavid du Colombier 	Rune *p;
338*426d2b71SDavid du Colombier 
339*426d2b71SDavid du Colombier 	if(ndi == 0 || difmtinit == 0)
340*426d2b71SDavid du Colombier 		return;
341*426d2b71SDavid du Colombier 	fmtrune(&difmt, Uunformatted);
342*426d2b71SDavid du Colombier 	p = runefmtstrflush(&difmt);
343*426d2b71SDavid du Colombier 	memset(&difmt, 0, sizeof difmt);
344*426d2b71SDavid du Colombier 	difmtinit = 0;
345*426d2b71SDavid du Colombier 	if(p == nil)
346*426d2b71SDavid du Colombier 		warn("out of memory in diversion %C%S", dot, di[ndi-1]);
347*426d2b71SDavid du Colombier 	else{
348*426d2b71SDavid du Colombier 		n = runestrlen(p);
349*426d2b71SDavid du Colombier 		if(n > 0 && p[n-1] != '\n'){
350*426d2b71SDavid du Colombier 			p = runerealloc(p, n+2);
351*426d2b71SDavid du Colombier 			p[n] = '\n';
352*426d2b71SDavid du Colombier 			p[n+1] = 0;
353*426d2b71SDavid du Colombier 		}
354*426d2b71SDavid du Colombier 	}
355*426d2b71SDavid du Colombier 	as(di[ndi-1], p);
356*426d2b71SDavid du Colombier 	free(p);
357*426d2b71SDavid du Colombier }
358*426d2b71SDavid du Colombier 
359*426d2b71SDavid du Colombier void
outdi(Rune r)360*426d2b71SDavid du Colombier outdi(Rune r)
361*426d2b71SDavid du Colombier {
362*426d2b71SDavid du Colombier if(!difmtinit) abort();
363*426d2b71SDavid du Colombier 	if(r == Uempty)
364*426d2b71SDavid du Colombier 		return;
365*426d2b71SDavid du Colombier 	fmtrune(&difmt, r);
366*426d2b71SDavid du Colombier }
367*426d2b71SDavid du Colombier 
368*426d2b71SDavid du Colombier /* .di, .da */
369*426d2b71SDavid du Colombier void
r_di(int argc,Rune ** argv)370*426d2b71SDavid du Colombier r_di(int argc, Rune **argv)
371*426d2b71SDavid du Colombier {
372*426d2b71SDavid du Colombier 	br();
373*426d2b71SDavid du Colombier 	if(argc > 2)
374*426d2b71SDavid du Colombier 		warn("extra arguments to %C%S", dot, argv[0]);
375*426d2b71SDavid du Colombier 	if(argc == 1){
376*426d2b71SDavid du Colombier 		/* end diversion */
377*426d2b71SDavid du Colombier 		if(ndi <= 0){
378*426d2b71SDavid du Colombier 			// warn("unmatched %C%S", dot, argv[0]);
379*426d2b71SDavid du Colombier 			return;
380*426d2b71SDavid du Colombier 		}
381*426d2b71SDavid du Colombier 		flushdi();
382*426d2b71SDavid du Colombier 		if(--ndi == 0){
383*426d2b71SDavid du Colombier 			_nr(L(".z"), nil);
384*426d2b71SDavid du Colombier 			outcb = nil;
385*426d2b71SDavid du Colombier 		}else{
386*426d2b71SDavid du Colombier 			_nr(L(".z"), di[ndi-1]);
387*426d2b71SDavid du Colombier 			runefmtstrinit(&difmt);
388*426d2b71SDavid du Colombier 			fmtrune(&difmt, Uformatted);
389*426d2b71SDavid du Colombier 			difmtinit = 1;
390*426d2b71SDavid du Colombier 		}
391*426d2b71SDavid du Colombier 		return;
392*426d2b71SDavid du Colombier 	}
393*426d2b71SDavid du Colombier 	/* start diversion */
394*426d2b71SDavid du Colombier 	/* various register state should be saved, but it's all useless to us */
395*426d2b71SDavid du Colombier 	flushdi();
396*426d2b71SDavid du Colombier 	if(ndi >= nelem(di))
397*426d2b71SDavid du Colombier 		sysfatal("%Cdi overflow", dot);
398*426d2b71SDavid du Colombier 	if(argv[0][1] == 'i')
399*426d2b71SDavid du Colombier 		ds(argv[1], nil);
400*426d2b71SDavid du Colombier 	_nr(L(".z"), argv[1]);
401*426d2b71SDavid du Colombier 	runestrcpy(di[ndi++], argv[1]);
402*426d2b71SDavid du Colombier 	runefmtstrinit(&difmt);
403*426d2b71SDavid du Colombier 	fmtrune(&difmt, Uformatted);
404*426d2b71SDavid du Colombier 	difmtinit = 1;
405*426d2b71SDavid du Colombier 	outcb = outdi;
406*426d2b71SDavid du Colombier }
407*426d2b71SDavid du Colombier 
408*426d2b71SDavid du Colombier /* .wh - install trap */
409*426d2b71SDavid du Colombier /* .ch - change trap */
410*426d2b71SDavid du Colombier /* .dt - install diversion trap */
411*426d2b71SDavid du Colombier 
412*426d2b71SDavid du Colombier /* set input-line count trap */
413*426d2b71SDavid du Colombier int itrapcount;
414*426d2b71SDavid du Colombier int itrapwaiting;
415*426d2b71SDavid du Colombier Rune *itrapname;
416*426d2b71SDavid du Colombier 
417*426d2b71SDavid du Colombier void
r_it(int argc,Rune ** argv)418*426d2b71SDavid du Colombier r_it(int argc, Rune **argv)
419*426d2b71SDavid du Colombier {
420*426d2b71SDavid du Colombier 	if(argc < 3){
421*426d2b71SDavid du Colombier 		itrapcount = 0;
422*426d2b71SDavid du Colombier 		return;
423*426d2b71SDavid du Colombier 	}
424*426d2b71SDavid du Colombier 	itrapcount = eval(argv[1]);
425*426d2b71SDavid du Colombier 	free(itrapname);
426*426d2b71SDavid du Colombier 	itrapname = erunestrdup(argv[2]);
427*426d2b71SDavid du Colombier }
428*426d2b71SDavid du Colombier 
429*426d2b71SDavid du Colombier void
itrap(void)430*426d2b71SDavid du Colombier itrap(void)
431*426d2b71SDavid du Colombier {
432*426d2b71SDavid du Colombier 	itrapset();
433*426d2b71SDavid du Colombier 	if(itrapwaiting){
434*426d2b71SDavid du Colombier 		itrapwaiting = 0;
435*426d2b71SDavid du Colombier 		runmacro1(itrapname);
436*426d2b71SDavid du Colombier 	}
437*426d2b71SDavid du Colombier }
438*426d2b71SDavid du Colombier 
439*426d2b71SDavid du Colombier void
itrapset(void)440*426d2b71SDavid du Colombier itrapset(void)
441*426d2b71SDavid du Colombier {
442*426d2b71SDavid du Colombier 	if(itrapcount > 0 && --itrapcount == 0)
443*426d2b71SDavid du Colombier 		itrapwaiting = 1;
444*426d2b71SDavid du Colombier }
445*426d2b71SDavid du Colombier 
446*426d2b71SDavid du Colombier /* .em - invoke macro when all input is over */
447*426d2b71SDavid du Colombier void
r_em(int argc,Rune ** argv)448*426d2b71SDavid du Colombier r_em(int argc, Rune **argv)
449*426d2b71SDavid du Colombier {
450*426d2b71SDavid du Colombier 	Rune buf[20];
451*426d2b71SDavid du Colombier 
452*426d2b71SDavid du Colombier 	USED(argc);
453*426d2b71SDavid du Colombier 	runesnprint(buf, nelem(buf), ".%S\n", argv[1]);
454*426d2b71SDavid du Colombier 	as(L("eof"), buf);
455*426d2b71SDavid du Colombier }
456*426d2b71SDavid du Colombier 
457*426d2b71SDavid du Colombier int
e_star(void)458*426d2b71SDavid du Colombier e_star(void)
459*426d2b71SDavid du Colombier {
460*426d2b71SDavid du Colombier 	Rune *p;
461*426d2b71SDavid du Colombier 
462*426d2b71SDavid du Colombier 	p = getds(getname());
463*426d2b71SDavid du Colombier 	if(p)
464*426d2b71SDavid du Colombier 		pushinputstring(p);
465*426d2b71SDavid du Colombier 	return 0;
466*426d2b71SDavid du Colombier }
467*426d2b71SDavid du Colombier 
468*426d2b71SDavid du Colombier int
e_t(void)469*426d2b71SDavid du Colombier e_t(void)
470*426d2b71SDavid du Colombier {
471*426d2b71SDavid du Colombier 	if(inputmode&CopyMode)
472*426d2b71SDavid du Colombier 		return '\t';
473*426d2b71SDavid du Colombier 	return 0;
474*426d2b71SDavid du Colombier }
475*426d2b71SDavid du Colombier 
476*426d2b71SDavid du Colombier int
e_a(void)477*426d2b71SDavid du Colombier e_a(void)
478*426d2b71SDavid du Colombier {
479*426d2b71SDavid du Colombier 	if(inputmode&CopyMode)
480*426d2b71SDavid du Colombier 		return '\a';
481*426d2b71SDavid du Colombier 	return 0;
482*426d2b71SDavid du Colombier }
483*426d2b71SDavid du Colombier 
484*426d2b71SDavid du Colombier int
e_backslash(void)485*426d2b71SDavid du Colombier e_backslash(void)
486*426d2b71SDavid du Colombier {
487*426d2b71SDavid du Colombier 	if(inputmode&ArgMode)
488*426d2b71SDavid du Colombier 		ungetrune('\\');
489*426d2b71SDavid du Colombier 	return backslash;
490*426d2b71SDavid du Colombier }
491*426d2b71SDavid du Colombier 
492*426d2b71SDavid du Colombier int
e_dot(void)493*426d2b71SDavid du Colombier e_dot(void)
494*426d2b71SDavid du Colombier {
495*426d2b71SDavid du Colombier 	return '.';
496*426d2b71SDavid du Colombier }
497*426d2b71SDavid du Colombier 
498*426d2b71SDavid du Colombier int
e_dollar(void)499*426d2b71SDavid du Colombier e_dollar(void)
500*426d2b71SDavid du Colombier {
501*426d2b71SDavid du Colombier 	int c;
502*426d2b71SDavid du Colombier 
503*426d2b71SDavid du Colombier 	c = getnext();
504*426d2b71SDavid du Colombier 	if(c < '1' || c > '9'){
505*426d2b71SDavid du Colombier 		ungetnext(c);
506*426d2b71SDavid du Colombier 		return 0;
507*426d2b71SDavid du Colombier 	}
508*426d2b71SDavid du Colombier 	c -= '0';
509*426d2b71SDavid du Colombier 	if(nmstack <= 0 || mstack[nmstack-1].argc <= c)
510*426d2b71SDavid du Colombier 		return 0;
511*426d2b71SDavid du Colombier 	pushinputstring(mstack[nmstack-1].argv[c]);
512*426d2b71SDavid du Colombier 	return 0;
513*426d2b71SDavid du Colombier }
514*426d2b71SDavid du Colombier 
515*426d2b71SDavid du Colombier void
t7init(void)516*426d2b71SDavid du Colombier t7init(void)
517*426d2b71SDavid du Colombier {
518*426d2b71SDavid du Colombier 	addreq(L("de"), r_de, -1);
519*426d2b71SDavid du Colombier 	addreq(L("am"), r_de, -1);
520*426d2b71SDavid du Colombier 	addreq(L("ig"), r_de, -1);
521*426d2b71SDavid du Colombier 	addraw(L("ds"), r_ds);
522*426d2b71SDavid du Colombier 	addraw(L("as"), r_ds);
523*426d2b71SDavid du Colombier 	addreq(L("rm"), r_rm, -1);
524*426d2b71SDavid du Colombier 	addreq(L("rn"), r_rn, -1);
525*426d2b71SDavid du Colombier 	addreq(L("di"), r_di, -1);
526*426d2b71SDavid du Colombier 	addreq(L("da"), r_di, -1);
527*426d2b71SDavid du Colombier 	addreq(L("it"), r_it, -1);
528*426d2b71SDavid du Colombier 	addreq(L("em"), r_em, 1);
529*426d2b71SDavid du Colombier 	addreq(L("wh"), r_wh, -1);
530*426d2b71SDavid du Colombier 	addreq(L("ch"), r_ch, -1);
531*426d2b71SDavid du Colombier 	addreq(L("dt"), r_dt, -1);
532*426d2b71SDavid du Colombier 
533*426d2b71SDavid du Colombier 	addesc('$', e_dollar, CopyMode|ArgMode|HtmlMode);
534*426d2b71SDavid du Colombier 	addesc('*', e_star, CopyMode|ArgMode|HtmlMode);
535*426d2b71SDavid du Colombier 	addesc('t', e_t, CopyMode|ArgMode);
536*426d2b71SDavid du Colombier 	addesc('a', e_a, CopyMode|ArgMode);
537*426d2b71SDavid du Colombier 	addesc('\\', e_backslash, ArgMode|CopyMode);
538*426d2b71SDavid du Colombier 	addesc('.', e_dot, CopyMode|ArgMode);
539*426d2b71SDavid du Colombier 
540*426d2b71SDavid du Colombier 	ds(L("eof"), L(".sp 0.5i\n"));
541*426d2b71SDavid du Colombier 	ds(L(".."), L(""));
542*426d2b71SDavid du Colombier }
543*426d2b71SDavid du Colombier 
544