xref: /plan9/sys/src/cmd/htmlroff/t8.c (revision 426d2b71458df9b491ba6c167f699b3f1f7b0428)
1 #include "a.h"
2 /*
3  * 8. Number Registers
4  * (Reg register implementation is also here.)
5  */
6 
7 /*
8  *	\nx		N
9  *	\n(xx	N
10  *	\n+x		N+=M
11  *	\n-x		N-=M
12  *
13  *	.nr R ±N M
14  *	.af R c
15  *
16  *	formats
17  *		1	0, 1, 2, 3, ...
18  *		001	001, 002, 003, ...
19  *		i	0, i, ii, iii, iv, v, ...
20  *		I	0, I, II, III, IV, V, ...
21  *		a	0, a, b, ..., aa, ab, ..., zz, aaa, ...
22  *		A	0, A, B, ..., AA, AB, ..., ZZ, AAA, ...
23  *
24  *	\gx \g(xx return format of number register
25  *
26  *	.rr R
27  */
28 
29 typedef struct Reg Reg;
30 struct Reg
31 {
32 	Reg *next;
33 	Rune *name;
34 	Rune *val;
35 	Rune *fmt;
36 	int inc;
37 };
38 
39 Reg *dslist;
40 Reg *nrlist;
41 
42 /*
43  * Define strings and numbers.
44  */
45 void
dsnr(Rune * name,Rune * val,Reg ** l)46 dsnr(Rune *name, Rune *val, Reg **l)
47 {
48 	Reg *s;
49 
50 	for(s = *l; s != nil; s = *l){
51 		if(runestrcmp(s->name, name) == 0)
52 			break;
53 		l = &s->next;
54 	}
55 	if(val == nil){
56 		if(s){
57 			*l = s->next;
58 			free(s->val);
59 			free(s->fmt);
60 			free(s);
61 		}
62 		return;
63 	}
64 	if(s == nil){
65 		s = emalloc(sizeof(Reg));
66 		*l = s;
67 		s->name = erunestrdup(name);
68 	}else
69 		free(s->val);
70 	s->val = erunestrdup(val);
71 }
72 
73 Rune*
getdsnr(Rune * name,Reg * list)74 getdsnr(Rune *name, Reg *list)
75 {
76 	Reg *s;
77 
78 	for(s=list; s; s=s->next)
79 		if(runestrcmp(name, s->name) == 0)
80 			return s->val;
81 	return nil;
82 }
83 
84 void
ds(Rune * name,Rune * val)85 ds(Rune *name, Rune *val)
86 {
87 	dsnr(name, val, &dslist);
88 }
89 
90 void
as(Rune * name,Rune * val)91 as(Rune *name, Rune *val)
92 {
93 	Rune *p, *q;
94 
95 	p = getds(name);
96 	if(p == nil)
97 		p = L("");
98 	q = runemalloc(runestrlen(p)+runestrlen(val)+1);
99 	runestrcpy(q, p);
100 	runestrcat(q, val);
101 	ds(name, q);
102 	free(q);
103 }
104 
105 Rune*
getds(Rune * name)106 getds(Rune *name)
107 {
108 	return getdsnr(name, dslist);
109 }
110 
111 void
printds(int t)112 printds(int t)
113 {
114 	int n, total;
115 	Reg *s;
116 
117 	total = 0;
118 	for(s=dslist; s; s=s->next){
119 		if(s->val)
120 			n = runestrlen(s->val);
121 		else
122 			n = 0;
123 		total += n;
124 		if(!t)
125 			fprint(2, "%S\t%d\n", s->name, n);
126 	}
127 	fprint(2, "total\t%d\n", total);
128 }
129 
130 void
nr(Rune * name,int val)131 nr(Rune *name, int val)
132 {
133 	Rune buf[20];
134 
135 	runesnprint(buf, nelem(buf), "%d", val);
136 	_nr(name, buf);
137 }
138 
139 void
af(Rune * name,Rune * fmt)140 af(Rune *name, Rune *fmt)
141 {
142 	Reg *s;
143 
144 	if(_getnr(name) == nil)
145 		_nr(name, L("0"));
146 	for(s=nrlist; s; s=s->next)
147 		if(runestrcmp(s->name, name) == 0)
148 			s->fmt = erunestrdup(fmt);
149 }
150 
151 Rune*
getaf(Rune * name)152 getaf(Rune *name)
153 {
154 	Reg *s;
155 
156 	for(s=nrlist; s; s=s->next)
157 		if(runestrcmp(s->name, name) == 0)
158 			return s->fmt;
159 	return nil;
160 }
161 
162 void
printnr(void)163 printnr(void)
164 {
165 	Reg *r;
166 
167 	for(r=nrlist; r; r=r->next)
168 		fprint(2, "%S %S %d\n", r->name, r->val, r->inc);
169 }
170 
171 /*
172  * Some internal number registers are actually strings,
173  * so provide _ versions to get at them.
174  */
175 void
_nr(Rune * name,Rune * val)176 _nr(Rune *name, Rune *val)
177 {
178 	dsnr(name, val, &nrlist);
179 }
180 
181 Rune*
_getnr(Rune * name)182 _getnr(Rune *name)
183 {
184 	return getdsnr(name, nrlist);
185 }
186 
187 int
getnr(Rune * name)188 getnr(Rune *name)
189 {
190 	Rune *p;
191 
192 	p = _getnr(name);
193 	if(p == nil)
194 		return 0;
195 	return eval(p);
196 }
197 
198 /* new register */
199 void
r_nr(int argc,Rune ** argv)200 r_nr(int argc, Rune **argv)
201 {
202 	Reg *s;
203 
204 	if(argc < 2)
205 		return;
206 	if(argc < 3)
207 		nr(argv[1], 0);
208 	else{
209 		if(argv[2][0] == '+')
210 			nr(argv[1], getnr(argv[1])+eval(argv[2]+1));
211 		else if(argv[2][0] == '-')
212 			nr(argv[1], getnr(argv[1])-eval(argv[2]+1));
213 		else
214 			nr(argv[1], eval(argv[2]));
215 	}
216 	if(argc > 3){
217 		for(s=nrlist; s; s=s->next)
218 			if(runestrcmp(s->name, argv[1]) == 0)
219 				s->inc = eval(argv[3]);
220 	}
221 }
222 
223 /* assign format */
224 void
r_af(int argc,Rune ** argv)225 r_af(int argc, Rune **argv)
226 {
227 	USED(argc);
228 
229 	af(argv[1], argv[2]);
230 }
231 
232 /* remove register */
233 void
r_rr(int argc,Rune ** argv)234 r_rr(int argc, Rune **argv)
235 {
236 	int i;
237 
238 	for(i=1; i<argc; i++)
239 		_nr(argv[i], nil);
240 }
241 
242 /* fmt integer in base 26 */
243 void
alpha(Rune * buf,int n,int a)244 alpha(Rune *buf, int n, int a)
245 {
246 	int i, v;
247 
248 	i = 1;
249 	for(v=n; v>0; v/=26)
250 		i++;
251 	if(i == 0)
252 		i = 1;
253 	buf[i] = 0;
254 	while(i > 0){
255 		buf[--i] = a+n%26;
256 		n /= 26;
257 	}
258 }
259 
260 struct romanv {
261 	char *s;
262 	int v;
263 } romanv[] =
264 {
265 	"m",	1000,
266 	"cm", 900,
267 	"d", 500,
268 	"cd", 400,
269 	"c", 100,
270 	"xc", 90,
271 	"l", 50,
272 	"xl", 40,
273 	"x", 10,
274 	"ix", 9,
275 	"v", 5,
276 	"iv", 4,
277 	"i", 1
278 };
279 
280 /* fmt integer in roman numerals! */
281 void
roman(Rune * buf,int n,int upper)282 roman(Rune *buf, int n, int upper)
283 {
284 	Rune *p;
285 	char *q;
286 	struct romanv *r;
287 
288 	if(upper)
289 		upper = 'A' - 'a';
290 	if(n >= 5000 || n <= 0){
291 		runestrcpy(buf, L("-"));
292 		return;
293 	}
294 	p = buf;
295 	r = romanv;
296 	while(n > 0){
297 		while(n >= r->v){
298 			for(q=r->s; *q; q++)
299 				*p++ = *q + upper;
300 			n -= r->v;
301 		}
302 		r++;
303 	}
304 	*p = 0;
305 }
306 
307 Rune*
getname(void)308 getname(void)
309 {
310 	int i, c, cc;
311 	static Rune buf[100];
312 
313 	/* XXX add [name] syntax as in groff */
314 	c = getnext();
315 	if(c < 0)
316 		return L("");
317 	if(c == '\n'){
318 		warn("newline in name\n");
319 		ungetnext(c);
320 		return L("");
321 	}
322 	if(c == '['){
323 		for(i=0; i<nelem(buf)-1; i++){
324 			if((c = getrune()) < 0)
325 				return L("");
326 			if(c == ']'){
327 				buf[i] = 0;
328 				return buf;
329 			}
330 			buf[i] = c;
331 		}
332 		return L("");
333 	}
334 	if(c != '('){
335 		buf[0] = c;
336 		buf[1] = 0;
337 		return buf;
338 	}
339 	c = getnext();
340 	cc = getnext();
341 	if(c < 0 || cc < 0)
342 		return L("");
343 	if(c == '\n' | cc == '\n'){
344 		warn("newline in \\n");
345 		ungetnext(cc);
346 		if(c == '\n')
347 			ungetnext(c);
348 	}
349 	buf[0] = c;
350 	buf[1] = cc;
351 	buf[2] = 0;
352 	return buf;
353 }
354 
355 /* \n - return number register */
356 int
e_n(void)357 e_n(void)
358 {
359 	int inc, v, l;
360 	Rune *name, *fmt, buf[100];
361 	Reg *s;
362 
363 	inc = getnext();
364 	if(inc < 0)
365 		return -1;
366 	if(inc != '+' && inc != '-'){
367 		ungetnext(inc);
368 		inc = 0;
369 	}
370 	name = getname();
371 	if(_getnr(name) == nil)
372 		_nr(name, L("0"));
373 	for(s=nrlist; s; s=s->next){
374 		if(runestrcmp(s->name, name) == 0){
375 			if(s->fmt == nil && !inc && s->val[0]){
376 				/* might be a string! */
377 				pushinputstring(s->val);
378 				return 0;
379 			}
380 			v = eval(s->val);
381 			if(inc){
382 				if(inc == '+')
383 					v += s->inc;
384 				else
385 					v -= s->inc;
386 				runesnprint(buf, nelem(buf), "%d", v);
387 				free(s->val);
388 				s->val = erunestrdup(buf);
389 			}
390 			fmt = s->fmt;
391 			if(fmt == nil)
392 				fmt = L("1");
393 			switch(fmt[0]){
394 			case 'i':
395 			case 'I':
396 				roman(buf, v, fmt[0]=='I');
397 				break;
398 			case 'a':
399 			case 'A':
400 				alpha(buf, v, fmt[0]);
401 				break;
402 			default:
403 				l = runestrlen(fmt);
404 				if(l == 0)
405 					l = 1;
406 				runesnprint(buf, sizeof buf, "%0*d", l, v);
407 				break;
408 			}
409 			pushinputstring(buf);
410 			return 0;
411 		}
412 	}
413 	pushinputstring(L(""));
414 	return 0;
415 }
416 
417 /* \g - number register format */
418 int
e_g(void)419 e_g(void)
420 {
421 	Rune *p;
422 
423 	p = getaf(getname());
424 	if(p == nil)
425 		p = L("1");
426 	pushinputstring(p);
427 	return 0;
428 }
429 
430 void
r_pnr(int argc,Rune ** argv)431 r_pnr(int argc, Rune **argv)
432 {
433 	USED(argc);
434 	USED(argv);
435 	printnr();
436 }
437 
438 void
t8init(void)439 t8init(void)
440 {
441 	addreq(L("nr"), r_nr, -1);
442 	addreq(L("af"), r_af, 2);
443 	addreq(L("rr"), r_rr, -1);
444 	addreq(L("pnr"), r_pnr, 0);
445 
446 	addesc('n', e_n, CopyMode|ArgMode|HtmlMode);
447 	addesc('g', e_g, 0);
448 }
449 
450