ref: 278caaf11931ec0c71fc13fd4c4794fae325c404
dir: /sys/src/cmd/htmlroff/t8.c/
#include "a.h" /* * 8. Number Registers * (Reg register implementation is also here.) */ /* * \nx N * \n(xx N * \n+x N+=M * \n-x N-=M * * .nr R ±N M * .af R c * * formats * 1 0, 1, 2, 3, ... * 001 001, 002, 003, ... * i 0, i, ii, iii, iv, v, ... * I 0, I, II, III, IV, V, ... * a 0, a, b, ..., aa, ab, ..., zz, aaa, ... * A 0, A, B, ..., AA, AB, ..., ZZ, AAA, ... * * \gx \g(xx return format of number register * * .rr R */ typedef struct Reg Reg; struct Reg { Reg *next; Rune *name; Rune *val; Rune *fmt; int inc; }; Reg *dslist; Reg *nrlist; /* * Define strings and numbers. */ void dsnr(Rune *name, Rune *val, Reg **l) { Reg *s; for(s = *l; s != nil; s = *l){ if(runestrcmp(s->name, name) == 0) break; l = &s->next; } if(val == nil){ if(s){ *l = s->next; free(s->val); free(s->fmt); free(s); } return; } if(s == nil){ s = emalloc(sizeof(Reg)); *l = s; s->name = erunestrdup(name); }else free(s->val); s->val = erunestrdup(val); } Rune* getdsnr(Rune *name, Reg *list) { Reg *s; for(s=list; s; s=s->next) if(runestrcmp(name, s->name) == 0) return s->val; return nil; } void ds(Rune *name, Rune *val) { dsnr(name, val, &dslist); } void as(Rune *name, Rune *val) { Rune *p, *q; p = getds(name); if(p == nil) p = L(""); q = runemalloc(runestrlen(p)+runestrlen(val)+1); runestrcpy(q, p); runestrcat(q, val); ds(name, q); free(q); } Rune* getds(Rune *name) { return getdsnr(name, dslist); } void printds(int t) { int n, total; Reg *s; total = 0; for(s=dslist; s; s=s->next){ if(s->val) n = runestrlen(s->val); else n = 0; total += n; if(!t) fprint(2, "%S\t%d\n", s->name, n); } fprint(2, "total\t%d\n", total); } void nr(Rune *name, int val) { Rune buf[20]; runesnprint(buf, nelem(buf), "%d", val); _nr(name, buf); } void af(Rune *name, Rune *fmt) { Reg *s; if(_getnr(name) == nil) _nr(name, L("0")); for(s=nrlist; s; s=s->next) if(runestrcmp(s->name, name) == 0) s->fmt = erunestrdup(fmt); } Rune* getaf(Rune *name) { Reg *s; for(s=nrlist; s; s=s->next) if(runestrcmp(s->name, name) == 0) return s->fmt; return nil; } void printnr(void) { Reg *r; for(r=nrlist; r; r=r->next) fprint(2, "%S %S %d\n", r->name, r->val, r->inc); } /* * Some internal number registers are actually strings, * so provide _ versions to get at them. */ void _nr(Rune *name, Rune *val) { dsnr(name, val, &nrlist); } Rune* _getnr(Rune *name) { return getdsnr(name, nrlist); } int getnr(Rune *name) { Rune *p; p = _getnr(name); if(p == nil) return 0; return eval(p); } /* new register */ void r_nr(int argc, Rune **argv) { Reg *s; if(argc < 2) return; if(argc < 3) nr(argv[1], 0); else{ if(argv[2][0] == '+') nr(argv[1], getnr(argv[1])+eval(argv[2]+1)); else if(argv[2][0] == '-') nr(argv[1], getnr(argv[1])-eval(argv[2]+1)); else nr(argv[1], eval(argv[2])); } if(argc > 3){ for(s=nrlist; s; s=s->next) if(runestrcmp(s->name, argv[1]) == 0) s->inc = eval(argv[3]); } } /* assign format */ void r_af(int argc, Rune **argv) { USED(argc); af(argv[1], argv[2]); } /* remove register */ void r_rr(int argc, Rune **argv) { int i; for(i=1; i<argc; i++) _nr(argv[i], nil); } /* fmt integer in base 26 */ void alpha(Rune *buf, int n, int a) { int i, v; i = 1; for(v=n; v>0; v/=26) i++; if(i == 0) i = 1; buf[i] = 0; while(i > 0){ buf[--i] = a+n%26; n /= 26; } } struct romanv { char *s; int v; } romanv[] = { "m", 1000, "cm", 900, "d", 500, "cd", 400, "c", 100, "xc", 90, "l", 50, "xl", 40, "x", 10, "ix", 9, "v", 5, "iv", 4, "i", 1 }; /* fmt integer in roman numerals! */ void roman(Rune *buf, int n, int upper) { Rune *p; char *q; struct romanv *r; if(upper) upper = 'A' - 'a'; if(n >= 5000 || n <= 0){ runestrcpy(buf, L("-")); return; } p = buf; r = romanv; while(n > 0){ while(n >= r->v){ for(q=r->s; *q; q++) *p++ = *q + upper; n -= r->v; } r++; } *p = 0; } Rune* getname(void) { int i, c, cc; static Rune buf[100]; /* XXX add [name] syntax as in groff */ c = getnext(); if(c < 0) return L(""); if(c == '\n'){ warn("newline in name\n"); ungetnext(c); return L(""); } if(c == '['){ for(i=0; i<nelem(buf)-1; i++){ if((c = getrune()) < 0) return L(""); if(c == ']'){ buf[i] = 0; return buf; } buf[i] = c; } return L(""); } if(c != '('){ buf[0] = c; buf[1] = 0; return buf; } c = getnext(); cc = getnext(); if(c < 0 || cc < 0) return L(""); if(c == '\n' || cc == '\n'){ warn("newline in \\n"); ungetnext(cc); if(c == '\n') ungetnext(c); } buf[0] = c; buf[1] = cc; buf[2] = 0; return buf; } /* \n - return number register */ int e_n(void) { int inc, v, l; Rune *name, *fmt, buf[100]; Reg *s; inc = getnext(); if(inc < 0) return -1; if(inc != '+' && inc != '-'){ ungetnext(inc); inc = 0; } name = getname(); if(_getnr(name) == nil) _nr(name, L("0")); for(s=nrlist; s; s=s->next){ if(runestrcmp(s->name, name) == 0){ if(s->fmt == nil && !inc && s->val[0]){ /* might be a string! */ pushinputstring(s->val); return 0; } v = eval(s->val); if(inc){ if(inc == '+') v += s->inc; else v -= s->inc; runesnprint(buf, nelem(buf), "%d", v); free(s->val); s->val = erunestrdup(buf); } fmt = s->fmt; if(fmt == nil) fmt = L("1"); switch(fmt[0]){ case 'i': case 'I': roman(buf, v, fmt[0]=='I'); break; case 'a': case 'A': alpha(buf, v, fmt[0]); break; default: l = runestrlen(fmt); if(l == 0) l = 1; runesnprint(buf, sizeof buf, "%0*d", l, v); break; } pushinputstring(buf); return 0; } } pushinputstring(L("")); return 0; } /* \g - number register format */ int e_g(void) { Rune *p; p = getaf(getname()); if(p == nil) p = L("1"); pushinputstring(p); return 0; } void r_pnr(int argc, Rune **argv) { USED(argc); USED(argv); printnr(); } void t8init(void) { addreq(L("nr"), r_nr, -1); addreq(L("af"), r_af, 2); addreq(L("rr"), r_rr, -1); addreq(L("pnr"), r_pnr, 0); addesc('n', e_n, CopyMode|ArgMode|HtmlMode); addesc('g', e_g, 0); }