Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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*
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
85
ds(Rune *name, Rune *val)
86
{
87
	dsnr(name, val, &dslist);
88
}
89
 
90
void
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*
106
getds(Rune *name)
107
{
108
	return getdsnr(name, dslist);
109
}
110
 
111
void
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
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
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*
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
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
176
_nr(Rune *name, Rune *val)
177
{
178
	dsnr(name, val, &nrlist);
179
}
180
 
181
Rune*
182
_getnr(Rune *name)
183
{
184
	return getdsnr(name, nrlist);
185
}
186
 
187
int
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
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
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
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
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
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*
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
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
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
431
r_pnr(int argc, Rune **argv)
432
{
433
	USED(argc);
434
	USED(argv);
435
	printnr();
436
}
437
 
438
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