Blob
1 #include "a.h"2 /*3 * 8. Number Registers4 * (Reg register implementation is also here.)5 */7 /*8 * \nx N9 * \n(xx N10 * \n+x N+=M11 * \n-x N-=M12 *13 * .nr R ±N M14 * .af R c15 *16 * formats17 * 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 register25 *26 * .rr R27 */29 typedef struct Reg Reg;30 struct Reg31 {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 void46 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 }else69 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 void85 ds(Rune *name, Rune *val)86 {87 dsnr(name, val, &dslist);88 }90 void91 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);103 }105 Rune*106 getds(Rune *name)107 {108 return getdsnr(name, dslist);109 }111 void112 printds(int t)113 {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 else122 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 }130 void131 nr(Rune *name, int val)132 {133 Rune buf[20];135 runesnprint(buf, nelem(buf), "%d", val);136 _nr(name, buf);137 }139 void140 af(Rune *name, Rune *fmt)141 {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);149 }151 Rune*152 getaf(Rune *name)153 {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;160 }162 void163 printnr(void)164 {165 Reg *r;167 for(r=nrlist; r; r=r->next)168 fprint(2, "%S %S %d\n", r->name, r->val, r->inc);169 }171 /*172 * Some internal number registers are actually strings,173 * so provide _ versions to get at them.174 */175 void176 _nr(Rune *name, Rune *val)177 {178 dsnr(name, val, &nrlist);179 }181 Rune*182 _getnr(Rune *name)183 {184 return getdsnr(name, nrlist);185 }187 int188 getnr(Rune *name)189 {190 Rune *p;192 p = _getnr(name);193 if(p == nil)194 return 0;195 return eval(p);196 }198 /* new register */199 void200 r_nr(int argc, Rune **argv)201 {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 else214 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 }223 /* assign format */224 void225 r_af(int argc, Rune **argv)226 {227 USED(argc);229 af(argv[1], argv[2]);230 }232 /* remove register */233 void234 r_rr(int argc, Rune **argv)235 {236 int i;238 for(i=1; i<argc; i++)239 _nr(argv[i], nil);240 }242 /* fmt integer in base 26 */243 void244 alpha(Rune *buf, int n, int a)245 {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;257 }258 }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", 1278 };280 /* fmt integer in roman numerals! */281 void282 roman(Rune *buf, int n, int upper)283 {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;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 }307 Rune*308 getname(void)309 {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("");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 }355 /* \n - return number register */356 int357 e_n(void)358 {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;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 else385 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 }417 /* \g - number register format */418 int419 e_g(void)420 {421 Rune *p;423 p = getaf(getname());424 if(p == nil)425 p = L("1");426 pushinputstring(p);427 return 0;428 }430 void431 r_pnr(int argc, Rune **argv)432 {433 USED(argc);434 USED(argv);435 printnr();436 }438 void439 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);446 addesc('n', e_n, CopyMode|ArgMode|HtmlMode);447 addesc('g', e_g, 0);448 }