diff options
Diffstat (limited to 'src/cmd/htmlroff/t8.c')
-rw-r--r-- | src/cmd/htmlroff/t8.c | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/src/cmd/htmlroff/t8.c b/src/cmd/htmlroff/t8.c new file mode 100644 index 00000000..ead5a020 --- /dev/null +++ b/src/cmd/htmlroff/t8.c @@ -0,0 +1,449 @@ +#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); +} + |