/* * 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. */voiddsnr(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;} voidds(Rune *name, Rune *val){ dsnr(name, val, &dslist);} voidas(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);} voidprintds(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);} voidnr(Rune *name, int val){ Rune buf[20]; runesnprint(buf, nelem(buf), "%d", val); _nr(name, buf);} voidaf(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;} voidprintnr(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);} intgetnr(Rune *name){ Rune *p; p = _getnr(name); if(p == nil) return 0; return eval(p);} /* new register */voidr_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 */voidr_af(int argc, Rune **argv){ USED(argc); af(argv[1], argv[2]);} /* remove register */voidr_rr(int argc, Rune **argv){ int i; for(i=1; i<argc; i++) _nr(argv[i], nil);} /* fmt integer in base 26 */voidalpha(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! */voidroman(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 */inte_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 */inte_g(void){ Rune *p; p = getaf(getname()); if(p == nil) p = L("1"); pushinputstring(p); return 0;} voidr_pnr(int argc, Rune **argv){ USED(argc); USED(argv); printnr();} voidt8init(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);}
/*
* 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);
}