Blob


1 #include "a.h"
2 /*
3 * 8. Number Registers
4 * (Reg register implementation is also here.)
5 */
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 */
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 };
39 Reg *dslist;
40 Reg *nrlist;
42 /*
43 * Define strings and numbers.
44 */
45 void
46 dsnr(Rune *name, Rune *val, Reg **l)
47 {
48 Reg *s;
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 }
73 Rune*
74 getdsnr(Rune *name, Reg *list)
75 {
76 Reg *s;
78 for(s=list; s; s=s->next)
79 if(runestrcmp(name, s->name) == 0)
80 return s->val;
81 return nil;
82 }
84 void
85 ds(Rune *name, Rune *val)
86 {
87 dsnr(name, val, &dslist);
88 }
90 void
91 as(Rune *name, Rune *val)
92 {
93 Rune *p, *q;
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);
105 Rune*
106 getds(Rune *name)
108 return getdsnr(name, dslist);
111 void
112 printds(int t)
114 int n, total;
115 Reg *s;
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);
127 fprint(2, "total\t%d\n", total);
130 void
131 nr(Rune *name, int val)
133 Rune buf[20];
135 runesnprint(buf, nelem(buf), "%d", val);
136 _nr(name, buf);
139 void
140 af(Rune *name, Rune *fmt)
142 Reg *s;
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);
151 Rune*
152 getaf(Rune *name)
154 Reg *s;
156 for(s=nrlist; s; s=s->next)
157 if(runestrcmp(s->name, name) == 0)
158 return s->fmt;
159 return nil;
162 void
163 printnr(void)
165 Reg *r;
167 for(r=nrlist; r; r=r->next)
168 fprint(2, "%S %S %d\n", r->name, r->val, r->inc);
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)
178 dsnr(name, val, &nrlist);
181 Rune*
182 _getnr(Rune *name)
184 return getdsnr(name, nrlist);
187 int
188 getnr(Rune *name)
190 Rune *p;
192 p = _getnr(name);
193 if(p == nil)
194 return 0;
195 return eval(p);
198 /* new register */
199 void
200 r_nr(int argc, Rune **argv)
202 Reg *s;
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]));
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]);
223 /* assign format */
224 void
225 r_af(int argc, Rune **argv)
227 USED(argc);
229 af(argv[1], argv[2]);
232 /* remove register */
233 void
234 r_rr(int argc, Rune **argv)
236 int i;
238 for(i=1; i<argc; i++)
239 _nr(argv[i], nil);
242 /* fmt integer in base 26 */
243 void
244 alpha(Rune *buf, int n, int a)
246 int i, v;
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;
260 struct romanv {
261 char *s;
262 int v;
263 } romanv[] =
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 };
280 /* fmt integer in roman numerals! */
281 void
282 roman(Rune *buf, int n, int upper)
284 Rune *p;
285 char *q;
286 struct romanv *r;
288 if(upper)
289 upper = 'A' - 'a';
290 if(n >= 5000 || n <= 0){
291 runestrcpy(buf, L("-"));
292 return;
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;
302 r++;
304 *p = 0;
307 Rune*
308 getname(void)
310 int i, c, cc;
311 static Rune buf[100];
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("");
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;
330 buf[i] = c;
332 return L("");
334 if(c != '('){
335 buf[0] = c;
336 buf[1] = 0;
337 return buf;
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);
349 buf[0] = c;
350 buf[1] = cc;
351 buf[2] = 0;
352 return buf;
355 /* \n - return number register */
356 int
357 e_n(void)
359 int inc, v, l;
360 Rune *name, *fmt, buf[100];
361 Reg *s;
363 inc = getnext();
364 if(inc < 0)
365 return -1;
366 if(inc != '+' && inc != '-'){
367 ungetnext(inc);
368 inc = 0;
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;
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);
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;
409 pushinputstring(buf);
410 return 0;
413 pushinputstring(L(""));
414 return 0;
417 /* \g - number register format */
418 int
419 e_g(void)
421 Rune *p;
423 p = getaf(getname());
424 if(p == nil)
425 p = L("1");
426 pushinputstring(p);
427 return 0;
430 void
431 r_pnr(int argc, Rune **argv)
433 USED(argc);
434 USED(argv);
435 printnr();
438 void
439 t8init(void)
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);
446 addesc('n', e_n, CopyMode|ArgMode|HtmlMode);
447 addesc('g', e_g, 0);