123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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);
- }
|