From c42a1d3d6168df56f966ea1f3ba3ef39ebbff4e4 Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 21 Feb 2006 18:37:05 +0000 Subject: add --- src/cmd/htmlroff/roff.c | 750 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 750 insertions(+) create mode 100644 src/cmd/htmlroff/roff.c (limited to 'src/cmd/htmlroff/roff.c') diff --git a/src/cmd/htmlroff/roff.c b/src/cmd/htmlroff/roff.c new file mode 100644 index 00000000..6a7cd09e --- /dev/null +++ b/src/cmd/htmlroff/roff.c @@ -0,0 +1,750 @@ +#include "a.h" + +enum +{ + MAXREQ = 100, + MAXRAW = 40, + MAXESC = 60, + MAXLINE = 1024, + MAXIF = 20, + MAXARG = 10, +}; + +typedef struct Esc Esc; +typedef struct Req Req; +typedef struct Raw Raw; + +/* escape sequence handler, like for \c */ +struct Esc +{ + Rune r; + int (*f)(void); + int mode; +}; + +/* raw request handler, like for .ie */ +struct Raw +{ + Rune *name; + void (*f)(Rune*); +}; + +/* regular request handler, like for .ft */ +struct Req +{ + int argc; + Rune *name; + void (*f)(int, Rune**); +}; + +int dot = '.'; +int tick = '\''; +int backslash = '\\'; + +int inputmode; +Req req[MAXREQ]; +int nreq; +Raw raw[MAXRAW]; +int nraw; +Esc esc[MAXESC]; +int nesc; +int iftrue[MAXIF]; +int niftrue; + +int isoutput; +int linepos; + + +void +addraw(Rune *name, void (*f)(Rune*)) +{ + Raw *r; + + if(nraw >= nelem(raw)){ + fprint(2, "too many raw requets\n"); + return; + } + r = &raw[nraw++]; + r->name = erunestrdup(name); + r->f = f; +} + +void +delraw(Rune *name) +{ + int i; + + for(i=0; i= nelem(req)){ + fprint(2, "too many requests\n"); + return; + } + r = &req[nreq++]; + r->name = erunestrdup(s); + r->f = f; + r->argc = argc; +} + +void +delreq(Rune *name) +{ + int i; + + for(i=0; i= nelem(esc)){ + fprint(2, "too many escapes\n"); + return; + } + e = &esc[nesc++]; + e->r = r; + e->f = f; + e->mode = mode; +} + +/* + * Get the next logical character in the input stream. + */ +int +getnext(void) +{ + int i, r; + +next: + r = getrune(); + if(r < 0) + return -1; + if(r == Uformatted){ + br(); + assert(!isoutput); + while((r = getrune()) >= 0 && r != Uunformatted){ + if(r == Uformatted) + continue; + outrune(r); + } + goto next; + } + if(r == Uunformatted) + goto next; + if(r == backslash){ + r = getrune(); + if(r < 0) + return -1; + for(i=0; i= 0 && c != '\n') + ; + ungetrune('\n'); + } + r = erunestrdup(buf); + return r; +} + +/* + * Read the current line in given mode. Newline not kept. + * Uses different buffer from copyarg! + */ +Rune* +readline(int m) +{ + static Rune buf[MaxLine]; + Rune *r; + + if(_readx(buf, sizeof buf, m, 1) < 0) + return nil; + r = erunestrdup(buf); + return r; +} + +/* + * Given the argument line (already read in copy+arg mode), + * parse into arguments. Note that \" has been left in place + * during copy+arg mode parsing, so comments still need to be stripped. + */ +int +parseargs(Rune *p, Rune **argv) +{ + int argc; + Rune *w; + + for(argc=0; argc 1+req[i].argc) + warn("too many arguments for %C%S", dot, req[i].name); + } + req[i].f(argc, argv); + free(argv[0]); + free(a); + return; + } + } + + /* + * Invoke user-defined macros. + */ + runmacro(dot, argc, argv); + free(argv[0]); + free(a); +} + +/* + * newlines are magical in various ways. + */ +int bol; +void +newline(void) +{ + int n; + + if(bol) + sp(eval(L("1v"))); + bol = 1; + if((n=getnr(L(".ce"))) > 0){ + nr(L(".ce"), n-1); + br(); + } + if(getnr(L(".fi")) == 0) + br(); + outrune('\n'); +} + +void +startoutput(void) +{ + char *align; + double ps, vs, lm, rm, ti; + Rune buf[200]; + + if(isoutput) + return; + isoutput = 1; + + if(getnr(L(".paragraph")) == 0) + return; + + nr(L(".ns"), 0); + isoutput = 1; + ps = getnr(L(".s")); + if(ps <= 1) + ps = 10; + ps /= 72.0; + USED(ps); + + vs = getnr(L(".v"))*getnr(L(".ls")) * 1.0/UPI; + vs /= (10.0/72.0); /* ps */ + if(vs == 0) + vs = 1.2; + + lm = (getnr(L(".o"))+getnr(L(".i"))) * 1.0/UPI; + ti = getnr(L(".ti")) * 1.0/UPI; + nr(L(".ti"), 0); + + rm = 8.0 - getnr(L(".l"))*1.0/UPI - getnr(L(".o"))*1.0/UPI; + if(rm < 0) + rm = 0; + switch(getnr(L(".j"))){ + default: + case 0: + align = "left"; + break; + case 1: + align = "justify"; + break; + case 3: + align = "center"; + break; + case 5: + align = "right"; + break; + } + if(getnr(L(".ce"))) + align = "center"; + if(!getnr(L(".margin"))) + runesnprint(buf, nelem(buf), "

\n", + vs, ti, align); + else + runesnprint(buf, nelem(buf), "

\n", + vs, lm, ti, rm, align); + outhtml(buf); +} +void +br(void) +{ + if(!isoutput) + return; + isoutput = 0; + + nr(L(".dv"), 0); + dv(0); + hideihtml(); + if(getnr(L(".paragraph"))) + outhtml(L("

")); +} + +void +r_margin(int argc, Rune **argv) +{ + USED(argc); + + nr(L(".margin"), eval(argv[1])); +} + +int inrequest; +void +runinput(void) +{ + int c; + + bol = 1; + for(;;){ + c = getnext(); + if(c < 0) + break; + if((c == dot || c == tick) && bol){ + inrequest = 1; + dotline(c); + bol = 1; + inrequest = 0; + }else if(c == '\n'){ + newline(); + itrap(); + linepos = 0; + }else{ + outtrap(); + startoutput(); + showihtml(); + if(c == '\t'){ + /* XXX do better */ + outrune(' '); + while(++linepos%4) + outrune(' '); + }else{ + outrune(c); + linepos++; + } + bol = 0; + } + } +} + +void +run(void) +{ + t1init(); + t2init(); + t3init(); + t4init(); + t5init(); + t6init(); + t7init(); + t8init(); + /* t9init(); t9.c */ + t10init(); + t11init(); + /* t12init(); t12.c */ + t13init(); + t14init(); + t15init(); + t16init(); + t17init(); + t18init(); + t19init(); + t20init(); + htmlinit(); + hideihtml(); + + addreq(L("margin"), r_margin, 1); + nr(L(".margin"), 1); + nr(L(".paragraph"), 1); + + runinput(); + while(popinput()) + ; + dot = '.'; + if(verbose) + fprint(2, "eof\n"); + runmacro1(L("eof")); + closehtml(); +} + +void +out(Rune *s) +{ + if(s == nil) + return; + for(; *s; s++) + outrune(*s); +} + +void (*outcb)(Rune); + +void +inroman(Rune r) +{ + int f; + + f = getnr(L(".f")); + nr(L(".f"), 1); + runmacro1(L("font")); + outrune(r); + nr(L(".f"), f); + runmacro1(L("font")); +} + +void +Brune(Rune r) +{ + if(r == '&') + Bprint(&bout, "&"); + else if(r == '<') + Bprint(&bout, "<"); + else if(r == '>') + Bprint(&bout, ">"); + else if(r < Runeself || utf8) + Bprint(&bout, "%C", r); + else + Bprint(&bout, "%S", rune2html(r)); +} + +void +outhtml(Rune *s) +{ + Rune r; + + for(; *s; s++){ + switch(r = *s){ + case '<': + r = Ult; + break; + case '>': + r = Ugt; + break; + case '&': + r = Uamp; + break; + case ' ': + r = Uspace; + break; + } + outrune(r); + } +} + +void +outrune(Rune r) +{ + switch(r){ + case ' ': + if(getnr(L(".fi")) == 0) + r = Unbsp; + break; + case Uformatted: + case Uunformatted: + abort(); + } + if(outcb){ + if(r == ' ') + r = Uspace; + outcb(r); + return; + } + /* writing to bout */ + switch(r){ + case Uempty: + return; + case Upl: + inroman('+'); + return; + case Ueq: + inroman('='); + return; + case Umi: + inroman(0x2212); + return; + case Utick: + r = '\''; + break; + case Ubtick: + r = '`'; + break; + case Uminus: + r = '-'; + break; + case '\'': + Bprint(&bout, "’"); + return; + case '`': + Bprint(&bout, "‘"); + return; + case Uamp: + Bputrune(&bout, '&'); + return; + case Ult: + Bputrune(&bout, '<'); + return; + case Ugt: + Bputrune(&bout, '>'); + return; + case Uspace: + Bputrune(&bout, ' '); + return; + case 0x2032: + /* + * In Firefox, at least, the prime is not + * a superscript by default. + */ + Bprint(&bout, ""); + Brune(r); + Bprint(&bout, ""); + return; + } + Brune(r); +} + +void +r_nop(int argc, Rune **argv) +{ + USED(argc); + USED(argv); +} + +void +r_warn(int argc, Rune **argv) +{ + USED(argc); + warn("ignoring %C%S", dot, argv[0]); +} + +int +e_warn(void) +{ + /* dispatch loop prints a warning for us */ + return 0; +} + +int +e_nop(void) +{ + return 0; +} -- cgit v1.2.3