aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/htmlroff/t8.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/htmlroff/t8.c')
-rw-r--r--src/cmd/htmlroff/t8.c449
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);
+}
+