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