commit c42a1d3d6168df56f966ea1f3ba3ef39ebbff4e4 from: rsc date: Tue Feb 21 18:37:05 2006 UTC add commit - 49a1496cbbb871bc623cfd0925566628e246c9ba commit + c42a1d3d6168df56f966ea1f3ba3ef39ebbff4e4 blob - /dev/null blob + c17da850c6552993a6429feada4870782574a4fd (mode 644) --- /dev/null +++ src/cmd/htmlroff/a.h @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +enum +{ + Unbsp = 0x00A0, + Uprivate = 0xF000, + Uempty, /* \& */ + Uamp, /* raw & */ + Ult, /* raw < */ + Ugt, /* raw > */ + Utick, /* raw ' */ + Ubtick, /* raw ` */ + Uminus, /* raw - */ + Uspace, /* raw space */ + Upl, /* symbol + */ + Ueq, /* symbol = */ + Umi, /* symbol - */ + Uformatted, /* start diverted output */ + Uunformatted, /* end diverted output */ + + UPI = 720, /* units per inch */ + UPX = 10, /* units per pixel */ + + /* special input modes */ + CopyMode = 1<<1, + ExpandMode = 1<<2, + ArgMode = 1<<3, + HtmlMode = 1<<4, + + MaxLine = 1024, +}; + +Rune* L(char*); + +void addesc(Rune, int (*)(void), int); +void addraw(Rune*, void(*)(Rune*)); +void addreq(Rune*, void(*)(int, Rune**), int); +void af(Rune*, Rune*); +void as(Rune*, Rune*); +void br(void); +void closehtml(void); +Rune* copyarg(void); +void delraw(Rune*); +void delreq(Rune*); +void ds(Rune*, Rune*); +int dv(int); +int e_nop(void); +int e_warn(void); +void* emalloc(uint); +void* erealloc(void*, uint); +Rune* erunesmprint(char*, ...); +Rune* erunestrdup(Rune*); +char* esmprint(char*, ...); +char* estrdup(char*); +int eval(Rune*); +int evalscale(Rune*, int); +Rune* getname(void); +int getnext(void); +Rune* getds(Rune*); +Rune* _getnr(Rune*); +int getnr(Rune*); +int getnrr(Rune*); +int getrune(void); +Rune* getqarg(void); +Rune* getline(void); +void hideihtml(void); +void html(Rune*, Rune*); +void htmlinit(void); +void ihtml(Rune*, Rune*); +void inputnotify(void(*)(void)); +void itrap(void); +void itrapset(void); +int linefmt(Fmt*); +void nr(Rune*, int); +void _nr(Rune*, Rune*); +void out(Rune*); +void (*outcb)(Rune); +void outhtml(Rune*); +void outrune(Rune); +void outtrap(void); +int popinput(void); +void printds(int); +int pushinputfile(Rune*); +void pushinputstring(Rune*); +int pushstdin(void); +int queueinputfile(Rune*); +int queuestdin(void); +void r_nop(int, Rune**); +void r_warn(int, Rune**); +Rune *readline(int); +void reitag(void); +void renraw(Rune*, Rune*); +void renreq(Rune*, Rune*); +void run(void); +void runinput(void); +int runmacro(int, int, Rune**); +void runmacro1(Rune*); +Rune* rune2html(Rune); +void setlinenumber(Rune*, int); +void showihtml(void); +void sp(int); +void t1init(void); +void t2init(void); +void t3init(void); +void t4init(void); +void t5init(void); +void t6init(void); +void t7init(void); +void t8init(void); +void t9init(void); +void t10init(void); +void t11init(void); +void t12init(void); +void t13init(void); +void t14init(void); +void t15init(void); +void t16init(void); +void t17init(void); +void t18init(void); +void t19init(void); +void t20init(void); +Rune troff2rune(Rune*); +void unfont(void); +void ungetnext(Rune); +void ungetrune(Rune); +void unitag(void); +void warn(char*, ...); + +extern int backslash; +extern int bol; +extern Biobuf bout; +extern int broke; +extern int dot; +extern int inputmode; +extern int inrequest; +extern int tick; +extern int utf8; +extern int verbose; +extern int linepos; + +#define runemalloc(n) (Rune*)emalloc((n)*sizeof(Rune)) +#define runerealloc(r, n) (Rune*)erealloc(r, (n)*sizeof(Rune)) +#define runemove(a, b, n) memmove(a, b, (n)*sizeof(Rune)) + +#pragma varargck type "L" void blob - /dev/null blob + 1c7d1237b4145775170a8716ad6b21866ad0b57a (mode 644) --- /dev/null +++ src/cmd/htmlroff/char.c @@ -0,0 +1,116 @@ +#include "a.h" + +/* + * Translate Unicode to HTML by asking tcs(1). + * This way we don't have yet another table. + */ +Rune* +rune2html(Rune r) +{ + static Biobuf b; + static int fd = -1; + static Rune **tcscache[256]; + int p[2]; + char *q; + + if(r == '\n') + return L("\n"); + + if(tcscache[r>>8] && tcscache[r>>8][r&0xFF]) + return tcscache[r>>8][r&0xFF]; + + if(fd < 0){ + if(pipe(p) < 0) + sysfatal("pipe: %r"); + switch(fork()){ + case -1: + sysfatal("fork: %r"); + case 0: + dup(p[0], 0); + dup(p[0], 1); + close(p[1]); + execl("tcs", "tcs", "-t", "html", nil); + _exits(0); + default: + close(p[0]); + fd = p[1]; + Binit(&b, fd, OREAD); + break; + } + } + fprint(fd, "%C\n", r); + q = Brdline(&b, '\n'); + if(q == nil) + sysfatal("tcs: early eof"); + q[Blinelen(&b)-1] = 0; + if(tcscache[r>>8] == nil) + tcscache[r>>8] = emalloc(256*sizeof tcscache[0][0]); + tcscache[r>>8][r&0xFF] = erunesmprint("%s", q); + return tcscache[r>>8][r&0xFF]; +} + +/* + * Translate troff to Unicode by looking in troff's utfmap. + * This way we don't have yet another hard-coded table. + */ +typedef struct Trtab Trtab; +struct Trtab +{ + char t[3]; + Rune r; +}; + +static Trtab trtab[200]; +int ntrtab; + +static Trtab trinit[] = +{ + "pl", Upl, + "eq", Ueq, + "em", 0x2014, + "en", 0x2013, + "mi", Umi, + "fm", 0x2032, +}; + +Rune +troff2rune(Rune *rs) +{ + char *file, *f[10], *p, s[3]; + int i, nf; + Biobuf *b; + + if(rs[0] >= Runeself || rs[1] >= Runeself) + return Runeerror; + s[0] = rs[0]; + s[1] = rs[1]; + s[2] = 0; + if(ntrtab == 0){ + for(i=0; i= nelem(trtab)) + fprint(2, "%s: trtab too small\n", argv0); + } + + for(i=0; is && *(p-1) == '/'){ + close: + for(p0=t+1; *p0 && *p0 != Ult; p0++) + ; + runemove(t, p0, runestrlen(p0)+1); + } + } + return t; +} + +void +html(Rune *id, Rune *s) +{ + Rune *es; + Tag *t, *tt, *next; + + br(); + hideihtml(); /* br already did, but be paranoid */ + for(t=tagstack; t; t=t->next){ + if(runestrcmp(t->id, id) == 0){ + for(tt=tagstack;; tt=next){ + next = tt->next; + free(tt->id); + free(tt->open); + out(tt->close); + outrune('\n'); + free(tt->close); + free(tt); + if(tt == t){ + tagstack = next; + goto cleared; + } + } + } + } + +cleared: + if(s == nil || s[0] == 0) + return; + out(s); + outrune('\n'); + es = closingtag(s); + if(es[0] == 0){ + free(es); + return; + } + if(runestrcmp(id, L("-")) == 0){ + out(es); + outrune('\n'); + free(es); + return; + } + t = emalloc(sizeof *t); + t->id = erunestrdup(id); + t->close = es; + t->next = tagstack; + tagstack = t; +} + +void +closehtml(void) +{ + Tag *t, *next; + + br(); + hideihtml(); + for(t=tagstack; t; t=next){ + next = t->next; + out(t->close); + outrune('\n'); + free(t->id); + free(t->close); + free(t); + } +} + +static void +rshow(Tag *t, Tag *end) +{ + if(t == nil || t == end) + return; + rshow(t->next, end); + out(t->open); +} + +void +ihtml(Rune *id, Rune *s) +{ + Tag *t, *tt, **l; + + for(t=tagset; t; t=t->next){ + if(runestrcmp(t->id, id) == 0){ + if(s && t->open && runestrcmp(t->open, s) == 0) + return; + for(l=&tagset; (tt=*l); l=&tt->next){ + if(!hidingset) + out(tt->close); + if(tt == t) + break; + } + *l = t->next; + free(t->id); + free(t->close); + free(t->open); + free(t); + if(!hidingset) + rshow(tagset, *l); + goto cleared; + } + } + +cleared: + if(s == nil || s[0] == 0) + return; + t = emalloc(sizeof *t); + t->id = erunestrdup(id); + t->open = erunestrdup(s); + t->close = closingtag(s); + if(!hidingset) + out(s); + t->next = tagset; + tagset = t; +} + +void +hideihtml(void) +{ + Tag *t; + + if(hidingset) + return; + hidingset = 1; + for(t=tagset; t; t=t->next) + out(t->close); +} + +void +showihtml(void) +{ + if(!hidingset) + return; + hidingset = 0; + rshow(tagset, nil); +} + +int +e_lt(void) +{ + return Ult; +} + +int +e_gt(void) +{ + return Ugt; +} + +int +e_at(void) +{ + return Uamp; +} + +int +e_tick(void) +{ + return Utick; +} + +int +e_btick(void) +{ + return Ubtick; +} + +int +e_minus(void) +{ + return Uminus; +} + +void +r_html(Rune *name) +{ + Rune *id, *line, *p; + + id = copyarg(); + line = readline(HtmlMode); + for(p=line; *p; p++){ + switch(*p){ + case '<': + *p = Ult; + break; + case '>': + *p = Ugt; + break; + case '&': + *p = Uamp; + break; + case ' ': + *p = Uspace; + break; + } + } + if(name[0] == 'i') + ihtml(id, line); + else + html(id, line); + free(id); + free(line); +} + +char defaultfont[] = + ".ihtml f1\n" + ".ihtml f\n" + ".ihtml f \n" + ".if \\n(.f==2 .ihtml f1 \n" + ".if \\n(.f==3 .ihtml f1 \n" + ".if \\n(.f==4 .ihtml f1 \n" + ".if \\n(.f==5 .ihtml f1 \n" + ".if \\n(.f==6 .ihtml f1 \n" + "..\n" +; + +void +htmlinit(void) +{ + addraw(L("html"), r_html); + addraw(L("ihtml"), r_html); + + addesc('<', e_lt, CopyMode); + addesc('>', e_gt, CopyMode); + addesc('\'', e_tick, CopyMode); + addesc('`', e_btick, CopyMode); + addesc('-', e_minus, CopyMode); + addesc('@', e_at, CopyMode); + + ds(L("font"), L(defaultfont)); +} + blob - /dev/null blob + 99e0d56e9d806cc79794bfee92724380b94c0b3a (mode 644) --- /dev/null +++ src/cmd/htmlroff/input.c @@ -0,0 +1,241 @@ +/* + * Read input files. + */ +#include "a.h" + +typedef struct Istack Istack; +struct Istack +{ + Rune unget[3]; + int nunget; + Biobuf *b; + Rune *p; + Rune *ep; + Rune *s; + int lineno; + Rune *name; + Istack *next; + void (*fn)(void); +}; + +Istack *istack; +Istack *ibottom; + +static void +setname(void) +{ + Rune *r, *p; + + if(istack == nil || istack->name == nil) + return; + _nr(L(".F"), istack->name); + r = erunestrdup(istack->name); + p = runestrchr(r, '.'); + if(p) + *p = 0; + _nr(L(".B"), r); + free(r); +} + +static void +ipush(Istack *is) +{ + if(istack == nil) + ibottom = is; + else + is->next = istack; + istack = is; + setname(); +} + +static void +iqueue(Istack *is) +{ + if(ibottom == nil){ + istack = is; + setname(); + }else + ibottom->next = is; + ibottom = is; +} + +int +_inputfile(Rune *s, void (*push)(Istack*)) +{ + Istack *is; + Biobuf *b; + char *t; + + t = esmprint("%S", s); + if((b = Bopen(t, OREAD)) == nil){ + free(t); + fprint(2, "%s: open %S: %r\n", argv0, s); + return -1; + } + free(t); + is = emalloc(sizeof *is); + is->b = b; + is->name = erunestrdup(s); + is->lineno = 1; + push(is); + return 0; +} + +int +pushinputfile(Rune *s) +{ + return _inputfile(s, ipush); +} + +int +queueinputfile(Rune *s) +{ + return _inputfile(s, iqueue); +} + +int +_inputstdin(void (*push)(Istack*)) +{ + Biobuf *b; + Istack *is; + + if((b = Bopen("/dev/null", OREAD)) == nil){ + fprint(2, "%s: open /dev/null: %r\n", argv0); + return -1; + } + dup(0, b->fid); + is = emalloc(sizeof *is); + is->b = b; + is->name = erunestrdup(L("stdin")); + is->lineno = 1; + push(is); + return 0; +} + +int +pushstdin(void) +{ + return _inputstdin(ipush); +} + +int +queuestdin(void) +{ + return _inputstdin(iqueue); +} + +void +_inputstring(Rune *s, void (*push)(Istack*)) +{ + Istack *is; + + is = emalloc(sizeof *is); + is->s = erunestrdup(s); + is->p = is->s; + is->ep = is->p+runestrlen(is->p); + push(is); +} + +void +pushinputstring(Rune *s) +{ + _inputstring(s, ipush); +} + + +void +inputnotify(void (*fn)(void)) +{ + if(istack) + istack->fn = fn; +} + +int +popinput(void) +{ + Istack *is; + + is = istack; + if(is == nil) + return 0; + + istack = istack->next; + if(is->b) + Bterm(is->b); + free(is->s); + free(is->name); + if(is->fn) + is->fn(); + free(is); + setname(); + return 1; +} + +int +getrune(void) +{ + Rune r; + int c; + +top: + if(istack == nil) + return -1; + if(istack->nunget) + return istack->unget[--istack->nunget]; + else if(istack->p){ + if(istack->p >= istack->ep){ + popinput(); + goto top; + } + r = *istack->p++; + }else if(istack->b){ + if((c = Bgetrune(istack->b)) < 0){ + popinput(); + goto top; + } + r = c; + }else{ + r = 0; + sysfatal("getrune - can't happen"); + } + if(r == '\n') + istack->lineno++; + return r; +} + +void +ungetrune(Rune r) +{ + if(istack == nil || istack->nunget >= nelem(istack->unget)) + pushinputstring(L("")); + istack->unget[istack->nunget++] = r; +} + +int +linefmt(Fmt *f) +{ + Istack *is; + + for(is=istack; is && !is->b; is=is->next) + ; + if(is) + return fmtprint(f, "%S:%d", is->name, is->lineno); + else + return fmtprint(f, ""); +} + +void +setlinenumber(Rune *s, int n) +{ + Istack *is; + + for(is=istack; is && !is->name; is=is->next) + ; + if(is){ + if(s){ + free(is->name); + is->name = erunestrdup(s); + } + is->lineno = n; + } +} blob - /dev/null blob + b6af1e7b405495ec02c6b434d5aa37df656794c9 (mode 644) --- /dev/null +++ src/cmd/htmlroff/main.c @@ -0,0 +1,72 @@ +/* + * Convert troff -ms input to HTML. + */ + +#include "a.h" + +Biobuf bout; +char* tmacdir; +int verbose; +int utf8 = 0; + +void +usage(void) +{ + fprint(2, "usage: htmlroff [-iuv] [-m mac] [-r an] [file...]\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int i, dostdin; + char *p; + Rune *r; + Rune buf[2]; + + Binit(&bout, 1, OWRITE); + fmtinstall('L', linefmt); + quotefmtinstall(); + + tmacdir = unsharp("#9/tmac"); + dostdin = 0; + ARGBEGIN{ + case 'i': + dostdin = 1; + break; + case 'm': + r = erunesmprint("%s/tmac.%s", tmacdir, EARGF(usage())); + if(queueinputfile(r) < 0) + fprint(2, "%S: %r\n", r); + break; + case 'r': + p = EARGF(usage()); + p += chartorune(buf, p); + buf[1] = 0; + _nr(buf, erunesmprint("%s", p+1)); + break; + case 'u': + utf8 = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + }ARGEND + + for(i=0; iauth.html + # 9 pic auth.ms | 9 eqn | ./o.htmlroff htmlmac.s /usr/local/plan9/tmac/tmac.skeep - >auth.html + +test%.html: o.htmlroff test.% htmlmac.s + ./o.htmlroff htmlmac.s test.$stem - >$target + +eqn:V: eqn.html + web eqn.html + +eqn.html: o.htmlroff htmlmac.s eqn.ms + 9 eqn eqn.ms | ./o.htmlroff htmlmac.s - >eqn.html + +eqn0.html: o.htmlroff htmlmac.s eqn0.ms + ./o.htmlroff htmlmac.s eqn0.ms - >eqn0.html + +rc.html: o.htmlroff rc.ms htmlmac.s + 9 tbl rc.ms | ./o.htmlroff -ms >rc.html + blob - /dev/null blob + 6a7cd09e4c64b81d7079e2c8cb738177233c638e (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 8236694de7c081d02882eb9b403244632fcda360 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t1.c @@ -0,0 +1,186 @@ +#include "a.h" + +/* + * Section 1 - General Explanation. + */ + +/* 1.3 - Numerical parameter input. */ +char *units = "icPmnpuvx"; +int +scale2units(char c) +{ + int x; + + switch(c){ + case 'i': /* inch */ + return UPI; + case 'c': /* centimeter */ + return 0.3937008 * UPI; + case 'P': /* pica = 1/6 inch */ + return UPI / 6; + case 'm': /* em = S points */ + return UPI / 72.0 * getnr(L(".s")); + case 'n': /* en = em/2 */ + return UPI / 72.0 * getnr(L(".s")) / 2; + case 'p': /* point = 1/72 inch */ + return UPI / 72; + case 'u': /* basic unit */ + return 1; + case 'v': /* vertical line space V */ + x = getnr(L(".v")); + if(x == 0) + x = 12 * UPI / 72; + return x; + case 'x': /* pixel (htmlroff addition) */ + return UPX; + default: + return 1; + } +} + +/* 1.4 - Numerical expressions. */ +int eval0(Rune**, int, int); +int +eval(Rune *s) +{ + return eval0(&s, 1, 1); +} +long +runestrtol(Rune *a, Rune **p) +{ + long n; + + n = 0; + while('0' <= *a && *a <= '9'){ + n = n*10 + *a-'0'; + a++; + } + *p = a; + return n; +} + +int +evalscale(Rune *s, int c) +{ + return eval0(&s, scale2units(c), 1); +} + +int +eval0(Rune **pline, int scale, int recur) +{ + Rune *p; + int neg; + double f, p10; + int x, y; + + neg = 0; + p = *pline; + while(*p == '-'){ + neg = 1 - neg; + p++; + } + if(*p == '('){ + p++; + x = eval0(&p, scale, 1); + if (*p != ')'){ + *pline = p; + return x; + } + p++; + }else{ + f = runestrtol(p, &p); + if(*p == '.'){ + p10 = 1.0; + p++; + while('0' <= *p && *p <= '9'){ + p10 /= 10; + f += p10*(*p++ - '0'); + } + } + if(*p && strchr(units, *p)){ + if(scale) + f *= scale2units(*p); + p++; + }else if(scale) + f *= scale; + x = f; + } + if(neg) + x = -x; + if(!recur){ + *pline = p; + return x; + } + + while(*p){ + switch(*p++) { + case '+': + x += eval0(&p, scale, 0); + continue; + case '-': + x -= eval0(&p, scale, 0); + continue; + case '*': + x *= eval0(&p, scale, 0); + continue; + case '/': + y = eval0(&p, scale, 0); + if (y == 0) { + fprint(2, "%L: divide by zero %S\n", p); + y = 1; + } + x /= y; + continue; + case '%': + y = eval0(&p, scale, 0); + if (!y) { + fprint(2, "%L: modulo by zero %S\n", p); + y = 1; + } + x %= y; + continue; + case '<': + if (*p == '=') { + p++; + x = x <= eval0(&p, scale, 0); + continue; + } + x = x < eval0(&p, scale, 0); + continue; + case '>': + if (*p == '=') { + p++; + x = x >= eval0(&p, scale, 0); + continue; + } + x = x > eval0(&p, scale, 0); + continue; + case '=': + if (*p == '=') + p++; + x = x == eval0(&p, scale, 0); + continue; + case '&': + x &= eval0(&p, scale, 0); + continue; + case ':': + x |= eval0(&p, scale, 0); + continue; + } + } + *pline = p; + return x; +} + +void +t1init(void) +{ + Tm tm; + + tm = *localtime(time(0)); + nr(L("dw"), tm.wday+1); + nr(L("dy"), tm.mday); + nr(L("mo"), tm.mon); + nr(L("yr"), tm.year%100); +} + blob - /dev/null blob + e029db35fd7a8a52f24bf9f66d49bf1e3fc1c702 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t10.c @@ -0,0 +1,140 @@ +#include "a.h" + +/* + * 10. Input and Output Conventions and Character Translation. + */ + +/* set escape character */ +void +r_ec(int argc, Rune **argv) +{ + if(argc == 1) + backslash = '\\'; + else + backslash = argv[1][0]; +} + +/* turn off escape character */ +void +r_eo(int argc, Rune **argv) +{ + USED(argc); + USED(argv); + backslash = -2; +} + +/* continuous underline (same as ul in troff) for the next N lines */ +/* set underline font */ +void +g_uf(int argc, Rune **argv) +{ + USED(argc); + USED(argv); +} + +/* set control character */ +void +r_cc(int argc, Rune **argv) +{ + if(argc == 1) + dot = '.'; + else + dot = argv[1][0]; +} + +/* set no-break control character */ +void +r_c2(int argc, Rune **argv) +{ + if(argc == 1) + tick = '\''; + else + tick = argv[1][0]; +} + +/* output translation */ + +int +e_bang(void) +{ + Rune *line; + + line = readline(CopyMode); + out(line); + outrune('\n'); + free(line); + return 0; +} + +int +e_X(void) +{ + int c; + + while((c = getrune()) >= 0 && c != '\'' && c != '\n') + outrune(c); + if(c == '\n'){ + warn("newline in %CX'...'", backslash); + outrune(c); + } + if(c < 0) + warn("eof in %CX'...'", backslash); + return 0; +} + +int +e_quote(void) +{ + int c; + + if(inputmode&ArgMode){ + /* Leave \" around for argument parsing */ + ungetrune('"'); + return '\\'; + } + while((c = getrune()) >= 0 && c != '\n') + ; + return '\n'; +} + +int +e_newline(void) +{ + return 0; +} + +int +e_e(void) +{ + return backslash; +} + +void +r_comment(Rune *name) +{ + int c; + + USED(name); + while((c = getrune()) >= 0 && c != '\n') + ; +} + +void +t10init(void) +{ + addreq(L("ec"), r_ec, -1); + addreq(L("eo"), r_eo, 0); + addreq(L("lg"), r_nop, -1); + addreq(L("cc"), r_cc, -1); + addreq(L("c2"), r_c2, -1); + addreq(L("tr"), r_warn, -1); + addreq(L("ul"), r_nop, -1); + addraw(L("\\\""), r_comment); + + addesc('!', e_bang, 0); + addesc('X', e_X, 0); + addesc('\"', e_quote, CopyMode|ArgMode); + addesc('\n', e_newline, CopyMode|ArgMode|HtmlMode); + addesc('e', e_e, 0); +} + blob - /dev/null blob + 53d68aac08dcd82f0c73652daf5ef413713ad6e4 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t11.c @@ -0,0 +1,107 @@ +#include "a.h" + +/* + * 11. Local Horizontal and Vertical Motions, and the Width Function. + */ + +int +e_0(void) +{ + /* digit-width space */ + return ' '; +} + +int +dv(int d) +{ + Rune sub[6]; + + d += getnr(L(".dv")); + nr(L(".dv"), d); + + runestrcpy(sub, L("")); + sub[0] = Ult; + sub[4] = Ugt; + if(d < 0){ + sub[3] = 'p'; + ihtml(L(".dv"), sub); + }else if(d > 0) + ihtml(L(".dv"), sub); + else + ihtml(L(".dv"), nil); + return 0; +} + +int +e_v(void) +{ + dv(eval(getqarg())); + return 0; +} + +int +e_u(void) +{ + dv(eval(L("-0.5m"))); + return 0; +} + +int +e_d(void) +{ + dv(eval(L("0.5m"))); + return 0; +} + +int +e_r(void) +{ + dv(eval(L("-1m"))); + return 0; +} + +int +e_h(void) +{ + getqarg(); + return 0; +} + +int +e_w(void) +{ + Rune *a; + Rune buf[40]; + + a = getqarg(); + runesnprint(buf, sizeof buf, "%ld", runestrlen(a)); + pushinputstring(buf); + nr(L("st"), 0); + nr(L("sb"), 0); + nr(L("ct"), 0); + return 0; +} + +int +e_k(void) +{ + getname(); + warn("%Ck not available", backslash); + return 0; +} + +void +t11init(void) +{ + addesc('|', e_nop, 0); + addesc('^', e_nop, 0); + addesc('v', e_v, 0); + addesc('h', e_h, 0); + addesc('w', e_w, 0); + addesc('0', e_0, 0); + addesc('u', e_u, 0); + addesc('d', e_d, 0); + addesc('r', e_r, 0); + addesc('k', e_k, 0); +} + blob - /dev/null blob + 5ec577d353c56cad1033cfcfaa9f3549d7d52ca0 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t12.c @@ -0,0 +1,67 @@ +#include "a.h" + +/* + * 12. Overstrike, bracket, line-drawing, graphics, and zero-width functions. + */ + +/* + \o'asdf' + \zc + \b'asdf' + \l'Nc' + \L'Nc' + \D'xxx' +*/ + +int +e_o(void) +{ + pushinputstring(getqarg()); + return 0; +} + +int +e_z(void) +{ + getnext(); + return 0; +} + +int +e_b(void) +{ + pushinputstring(getqarg()); + return 0; +} + +int +e_l(void) +{ + getqarg(); + return 0; +} + +int +e_L(void) +{ + getqarg(); + return 0; +} + +int +e_D(void) +{ + getqarg(); + return 0; +} + +void +t12init(void) +{ + addesc('o', e_o, 0); + addesc('z', e_z, 0); + addesc('b', e_b, 0); + addesc('l', e_l, 0); + addesc('L', e_L, 0); + addesc('D', e_D, 0); +} blob - /dev/null blob + 0fadab3ad296a6f1cbe2dcd29706576cdd6596b0 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t13.c @@ -0,0 +1,17 @@ +#include "a.h" + +/* + * 13. Hyphenation. + */ + +void +t13init(void) +{ + addreq(L("nh"), r_nop, -1); + addreq(L("hy"), r_nop, -1); + addreq(L("hc"), r_nop, -1); + addreq(L("hw"), r_nop, -1); + + addesc('%', e_nop, 0); +} + blob - /dev/null blob + 1dab3516747297a15609938fe81351338c5b05f4 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t14.c @@ -0,0 +1,33 @@ +#include "a.h" + +/* + * 14. Three-part titles. + */ +void +r_lt(int argc, Rune **argv) +{ + Rune *p; + + if(argc < 2) + nr(L(".lt"), evalscale(L("6.5i"), 'm')); + else{ + if(argc > 2) + warn("too many arguments for .lt"); + p = argv[1]; + if(p[0] == '-') + nr(L(".lt"), getnr(L(".lt"))-evalscale(p+1, 'm')); + else if(p[0] == '+') + nr(L(".lt"), getnr(L(".lt"))+evalscale(p+1, 'm')); + else + nr(L(".lt"), evalscale(p, 'm')); + } +} + +void +t14init(void) +{ + addreq(L("tl"), r_warn, -1); + addreq(L("pc"), r_nop, -1); /* page number char */ + addreq(L("lt"), r_lt, -1); +} + blob - /dev/null blob + fbfd5128fc2cb642890ea0cb1f425f82a8a376a2 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t15.c @@ -0,0 +1,13 @@ +#include "a.h" + +/* + * 15. Output line numbering. + */ + +void +t15init(void) +{ + addreq(L("nm"), r_warn, -1); + addreq(L("nn"), r_warn, -1); +} + blob - /dev/null blob + 3a9c427e8a4e1d52ec8dac1815f8c832ad6c8020 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t16.c @@ -0,0 +1,156 @@ +#include "a.h" + +/* + * 16. Conditional acceptance of input. + * + * conditions are + * c - condition letter (o, e, t, n) + * !c - not c + * N - N>0 + * !N - N <= 0 + * 'a'b' - if a==b + * !'a'b' - if a!=b + * + * \{xxx\} can be used for newline in bodies + * + * .if .ie .el + * + */ + +int iftrue[20]; +int niftrue; + +void +startbody(void) +{ + int c; + + while((c = getrune()) == ' ' || c == '\t') + ; + ungetrune(c); +} + +void +skipbody(void) +{ + int c, cc, nbrace; + + nbrace = 0; + for(cc=0; (c = getrune()) >= 0; cc=c){ + if(c == '\n' && nbrace <= 0) + break; + if(cc == '\\' && c == '{') + nbrace++; + if(cc == '\\' && c == '}') + nbrace--; + } +} + +int +ifeval(void) +{ + int c, cc, neg, nc; + Rune line[MaxLine], *p, *e, *q; + Rune *a; + + while((c = getnext()) == ' ' || c == '\t') + ; + neg = 0; + while(c == '!'){ + neg = !neg; + c = getnext(); + } + + if('0' <= c && c <= '9'){ + ungetnext(c); + a = copyarg(); + c = (eval(a)>0) ^ neg; + free(a); + return c; + } + + switch(c){ + case ' ': + case '\n': + ungetnext(c); + return !neg; + case 'o': /* odd page */ + case 't': /* troff */ + case 'h': /* htmlroff */ + while((c = getrune()) != ' ' && c != '\t' && c != '\n' && c >= 0) + ; + return 1 ^ neg; + case 'n': /* nroff */ + case 'e': /* even page */ + while((c = getnext()) != ' ' && c != '\t' && c != '\n' && c >= 0) + ; + return 0 ^ neg; + } + + /* string comparison 'string1'string2' */ + p = line; + e = p+nelem(line); + nc = 0; + q = nil; + while((cc=getnext()) >= 0 && cc != '\n' && p= nelem(iftrue)) + sysfatal("%Cie overflow", dot); + iftrue[niftrue++] = n; + } + if(n) + startbody(); + else + skipbody(); +} + +void +r_el(Rune *name) +{ + USED(name); + + if(niftrue <= 0){ + warn("%Cel underflow", dot); + return; + } + if(iftrue[--niftrue]) + skipbody(); + else + startbody(); +} + +void +t16init(void) +{ + addraw(L("if"), r_if); + addraw(L("ie"), r_if); + addraw(L("el"), r_el); + + addesc('{', e_nop, HtmlMode|ArgMode); + addesc('}', e_nop, HtmlMode|ArgMode); +} blob - /dev/null blob + 2800ec7655c78a681a1fd87d819b947046a68c68 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t17.c @@ -0,0 +1,131 @@ +#include "a.h" + +/* + * 17. Environment switching. + */ +typedef struct Env Env; +struct Env +{ + int s; + int s0; + int f; + int f0; + int fi; + int ad; + int ce; + int v; + int v0; + int ls; + int ls0; + int it; + /* - ta */ + /* - tc */ + /* - lc */ + /* - ul */ + /* - cu */ + /* - cc */ + /* - c2 */ + /* - nh */ + /* - hy */ + /* - hc */ + /* - lt */ + /* - nm */ + /* - nn */ + /* - mc */ +}; + +Env defenv = +{ + 10, + 10, + 1, + 1, + 1, + 1, + 0, + 12, + 12, + 0, + 0, + 0, +}; + +Env env[3]; +Env *evstack[20]; +int nevstack; + +void +saveenv(Env *e) +{ + e->s = getnr(L(".s")); + e->s0 = getnr(L(".s0")); + e->f = getnr(L(".f")); + e->f0 = getnr(L(".f0")); + e->fi = getnr(L(".fi")); + e->ad = getnr(L(".ad")); + e->ce = getnr(L(".ce")); + e->v = getnr(L(".v")); + e->v0 = getnr(L(".v0")); + e->ls = getnr(L(".ls")); + e->ls0 = getnr(L(".ls0")); + e->it = getnr(L(".it")); +} + +void +restoreenv(Env *e) +{ + nr(L(".s"), e->s); + nr(L(".s0"), e->s0); + nr(L(".f"), e->f); + nr(L(".f0"), e->f0); + nr(L(".fi"), e->fi); + nr(L(".ad"), e->ad); + nr(L(".ce"), e->ce); + nr(L(".v"), e->v); + nr(L(".v0"), e->v0); + nr(L(".ls"), e->ls); + nr(L(".ls0"), e->ls0); + nr(L(".it"), e->it); + + nr(L(".ev"), e-env); + runmacro1(L("font")); +} + + +void +r_ev(int argc, Rune **argv) +{ + int i; + Env *e; + + if(argc == 1){ + if(nevstack <= 0){ + if(verbose) warn(".ev stack underflow"); + return; + } + restoreenv(evstack[--nevstack]); + return; + } + if(nevstack >= nelem(evstack)) + sysfatal(".ev stack overflow"); + i = eval(argv[1]); + if(i < 0 || i > 2){ + warn(".ev bad environment %d", i); + i = 0; + } + e = &env[getnr(L(".ev"))]; + saveenv(e); + evstack[nevstack++] = e; + restoreenv(&env[i]); +} + +void +t17init(void) +{ + int i; + + for(i=0; i 1) + fprint(2, "%S", argv[1]); + else + fprint(2, "%c", 7/*BEL*/); + } + + if(!didstdin){ + Binit(&bstdin, 0, OREAD); + didstdin = 1; + } + runefmtstrinit(&fmt); + while((s = Brdstr(&bstdin, '\n', 0)) != nil){ + if(s[0] == '\n'){ + free(s); + break; + } + fmtprint(&fmt, "%s", s); + free(s); + } + p = runefmtstrflush(&fmt); + if(p == nil) + warn("out of memory in %Crd", dot); + ds(L(".rd"), p); + argc--; + argv++; + argv[0] = L(".rd"); + runmacro('.', argc, argv); + ds(L(".rd"), nil); +} + +/* terminate exactly as if input had ended */ +void +r_ex(int argc, Rune **argv) +{ + USED(argc); + USED(argv); + + while(popinput()) + ; +} + +void +t18init(void) +{ + addreq(L("rd"), r_rd, -1); + addreq(L("ex"), r_ex, 0); +} blob - /dev/null blob + a4cc18f443d9c8516e72e8b0d3d5b9172966eaaa (mode 644) --- /dev/null +++ src/cmd/htmlroff/t19.c @@ -0,0 +1,142 @@ +#include "a.h" + +/* + * 19. Input/output file switching. + */ + +/* .so - push new source file */ +void +r_so(int argc, Rune **argv) +{ + USED(argc); + pushinputfile(erunesmprint("%s", unsharp(esmprint("%S", argv[1])))); +} + +/* .nx - end this file, switch to arg */ +void +r_nx(int argc, Rune **argv) +{ + int n; + + if(argc == 1){ + while(popinput()) + ; + }else{ + if(argc > 2) + warn("too many arguments for .nx"); + while((n=popinput()) && n != 2) + ; + pushinputfile(argv[1]); + } +} + +/* .sy - system: run string */ +void +r_sy(Rune *name) +{ + USED(name); + warn(".sy not implemented"); +} + +/* .pi - pipe output to string */ +void +r_pi(Rune *name) +{ + USED(name); + warn(".pi not implemented"); +} + +/* .cf - copy contents of filename to output */ +void +r_cf(int argc, Rune **argv) +{ + int c; + char *p; + Biobuf *b; + + USED(argc); + p = esmprint("%S", argv[1]); + if((b = Bopen(p, OREAD)) == nil){ + fprint(2, "%L: open %s: %r\n", p); + free(p); + return; + } + free(p); + + while((c = Bgetrune(b)) >= 0) + outrune(c); + Bterm(b); +} + +void +r_inputpipe(Rune *name) +{ + Rune *cmd, *stop, *line; + int n, pid, p[2], len; + Waitmsg *w; + + USED(name); + if(pipe(p) < 0){ + warn("pipe: %r"); + return; + } + stop = copyarg(); + cmd = readline(CopyMode); + pid = fork(); + switch(pid){ + case 0: + if(p[0] != 0){ + dup(p[0], 0); + close(p[0]); + } + close(p[1]); + execl(unsharp("#9/bin/rc"), "rc", "-c", esmprint("%S", cmd), nil); + warn("%Cdp %S: %r", dot, cmd); + _exits(nil); + case -1: + warn("fork: %r"); + default: + close(p[0]); + len = runestrlen(stop); + fprint(p[1], ".ps %d\n", getnr(L(".s"))); + fprint(p[1], ".vs %du\n", getnr(L(".v"))); + fprint(p[1], ".ft %d\n", getnr(L(".f"))); + fprint(p[1], ".ll 8i\n"); + fprint(p[1], ".pl 30i\n"); + while((line = readline(~0)) != nil){ + if(runestrncmp(line, stop, len) == 0 + && (line[len]==' ' || line[len]==0 || line[len]=='\t' + || (line[len]=='\\' && line[len+1]=='}'))) + break; + n = runestrlen(line); + line[n] = '\n'; + fprint(p[1], "%.*S", n+1, line); + free(line); + } + free(stop); + close(p[1]); + w = wait(); + if(w == nil){ + warn("wait: %r"); + return; + } + if(w->msg[0]) + sysfatal("%C%S %S: %s", dot, name, cmd, w->msg); + free(cmd); + free(w); + } +} + +void +t19init(void) +{ + addreq(L("so"), r_so, 1); + addreq(L("nx"), r_nx, -1); + addraw(L("sy"), r_sy); + addraw(L("inputpipe"), r_inputpipe); + addraw(L("pi"), r_pi); + addreq(L("cf"), r_cf, 1); + + nr(L("$$"), getpid()); +} + blob - /dev/null blob + 54481d0a56ac33145ef8a922bcff3c424c5460f2 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t2.c @@ -0,0 +1,274 @@ +#include "a.h" + +/* + * Section 2 - Font and character size control. + */ + +/* 2.1 - Character set */ +/* XXX + * + * \C'name' - character named name + * \N'n' - character number + * \(xx - two-letter character + * \- + * \` + * \' + * ` + * ' + * - + */ + +Rune* +getqarg(void) +{ + static Rune buf[MaxLine]; + int c; + Rune *p, *e; + + p = buf; + e = p+sizeof buf-1; + + if(getrune() != '\'') + return nil; + while(p < e){ + c = getrune(); + if(c < 0) + return nil; + if(c == '\'') + break; + *p++ = c; + } + *p = 0; + return buf; +} + +int +e_N(void) +{ + Rune *a; + if((a = getqarg()) == nil) + goto error; + return eval(a); + +error: + warn("malformed %CN'...'", backslash); + return 0; +} + +int +e_paren(void) +{ + int c, cc; + Rune buf[2], r; + + if((c = getrune()) < 0 || c == '\n') + goto error; + if((cc = getrune()) < 0 || cc == '\n') + goto error; + buf[0] = c; + buf[1] = cc; + r = troff2rune(buf); + if(r == Runeerror) + warn("unknown char %C(%C%C", backslash, c, cc); + return r; + +error: + warn("malformed %C(xx", backslash); + return 0; +} + +/* 2.2 - Fonts */ +Rune fonttab[10][100]; + +/* + * \fx \f(xx \fN - font change + * number register .f - current font + * \f0 previous font (undocumented?) + */ +/* change to font f. also \fx, \f(xx, \fN */ +/* .ft LongName is okay - temporarily at fp 0 */ +void +ft(Rune *f) +{ + int i; + int fn; + + if(f && runestrcmp(f, L("P")) == 0) + f = nil; + if(f == nil) + fn = 0; + else if(isdigit(f[0])) + fn = eval(f); + else{ + for(i=0; i= nelem(fonttab)){ + warn("unknown font %d", fn); + fn = 1; + } + if(fn == 0) + fn = getnr(L(".f0")); + nr(L(".f0"), getnr(L(".f"))); + nr(L(".f"), fn); + runmacro1(L("font")); +} + +/* mount font named f on physical position N */ +void +fp(int i, Rune *f) +{ + if(i <= 0 || i >= nelem(fonttab)){ + warn("bad font position %d", i); + return; + } + runestrecpy(fonttab[i], fonttab[i]+sizeof fonttab[i], f); +} + +int +e_f(void) +{ + ft(getname()); + return 0; +} + +void +r_ft(int argc, Rune **argv) +{ + if(argc == 1) + ft(nil); + else + ft(argv[1]); +} + +void +r_fp(int argc, Rune **argv) +{ + if(argc < 3){ + warn("missing arguments to %Cfp", dot); + return; + } + fp(eval(argv[1]), argv[2]); +} + +/* 2.3 - Character size */ + +/* \H'±N' sets height */ + +void +ps(int s) +{ + if(s == 0) + s = getnr(L(".s0")); + nr(L(".s0"), getnr(L(".s"))); + nr(L(".s"), s); + runmacro1(L("font")); +} + +/* set point size */ +void +r_ps(int argc, Rune **argv) +{ + Rune *p; + + if(argc == 1 || argv[1][0] == 0) + ps(0); + else{ + p = argv[1]; + if(p[0] == '-') + ps(getnr(L(".s"))-eval(p+1)); + else if(p[0] == '+') + ps(getnr(L(".s"))+eval(p+1)); + else + ps(eval(p)); + } +} + +int +e_s(void) +{ + int c, cc, ccc, n, twodigit; + + c = getnext(); + if(c < 0) + return 0; + if(c == '+' || c == '-'){ + cc = getnext(); + if(cc == '('){ + cc = getnext(); + ccc = getnext(); + if(cc < '0' || cc > '9' || ccc < '0' || ccc > '9'){ + warn("bad size %Cs%C(%C%C", backslash, c, cc, ccc); + return 0; + } + n = (cc-'0')*10+ccc-'0'; + }else{ + if(cc < '0' || cc > '9'){ + warn("bad size %Cs%C%C", backslash, c, cc); + return 0; + } + n = cc-'0'; + } + if(c == '+') + ps(getnr(L(".s"))+n); + else + ps(getnr(L(".s"))-n); + return 0; + } + twodigit = 0; + if(c == '('){ + twodigit = 1; + c = getnext(); + if(c < 0) + return 0; + } + if(c < '0' || c > '9'){ + warn("bad size %Cs%C", backslash, c); + ungetnext(c); + return 0; + } + if(twodigit || (c < '4' && c != '0')){ + cc = getnext(); + if(c < 0) + return 0; + n = (c-'0')*10+cc-'0'; + }else + n = c-'0'; + ps(n); + return 0; +} + +void +t2init(void) +{ + fp(1, L("R")); + fp(2, L("I")); + fp(3, L("B")); + fp(4, L("BI")); + fp(5, L("CW")); + + nr(L(".s"), 10); + nr(L(".s0"), 10); + + addreq(L("ft"), r_ft, -1); + addreq(L("fp"), r_fp, -1); + addreq(L("ps"), r_ps, -1); + addreq(L("ss"), r_warn, -1); + addreq(L("cs"), r_warn, -1); + addreq(L("bd"), r_warn, -1); + + addesc('f', e_f, 0); + addesc('s', e_s, 0); + addesc('(', e_paren, 0); /* ) */ + addesc('C', e_warn, 0); + addesc('N', e_N, 0); + /* \- \' \` are handled in html.c */ +} + blob - /dev/null blob + 62ea914fc04a0994d371db81aa6d80823615932e (mode 644) --- /dev/null +++ src/cmd/htmlroff/t20.c @@ -0,0 +1,79 @@ +#include "a.h" + +/* + * 20. Miscellaneous + */ + +/* .mc - margin character */ +/* .ig - ignore; treated like a macro in t7.c */ + +/* .pm - print macros and strings */ + +void +r_pm(int argc, Rune **argv) +{ + int i; + + if(argc == 1){ + printds(0); + return; + } + if(runestrcmp(argv[1], L("t")) == 0){ + printds(1); + return; + } + for(i=1; i 5) + fv = eval(L("1v")) * 1.0/UPI; + runesnprint(buf, nelem(buf), "

\n", fv); + outhtml(buf); +} +void +r_sp(int argc, Rune **argv) +{ + if(getnr(L(".ns"))) + return; + if(argc < 2) + sp(eval(L("1v"))); + else{ + if(argv[1][0] == '|'){ + /* XXX if there's no output yet, do the absolute! */ + if(verbose) + warn("ignoring absolute .sp %d", eval(argv[1]+1)); + return; + } + sp(evalscale(argv[1], 'v')); + } +} + +void +r_ns(int argc, Rune **argv) +{ + USED(argc); + USED(argv); + nr(L(".ns"), 1); +} + +void +r_rs(int argc, Rune **argv) +{ + USED(argc); + USED(argv); + nr(L(".ns"), 0); +} + +void +t5init(void) +{ + addreq(L("vs"), r_vs, -1); + addreq(L("ls"), r_ls, -1); + addreq(L("sp"), r_sp, -1); + addreq(L("sv"), r_sp, -1); + addreq(L("os"), r_nop, -1); + addreq(L("ns"), r_ns, 0); + addreq(L("rs"), r_rs, 0); + + nr(L(".v"), eval(L("12p"))); + nr(L(".v0"), eval(L("12p"))); + nr(L(".ls"), 1); + nr(L(".ls0"), 1); +} + blob - /dev/null blob + 88a069546efd85c8770d19124d8fef911e0d6c8b (mode 644) --- /dev/null +++ src/cmd/htmlroff/t6.c @@ -0,0 +1,74 @@ +#include "a.h" + +/* + * Section 6 - line length and indenting. + */ + +/* set line length */ +void +ll(int v) +{ + if(v == 0) + v = getnr(L(".l0")); + nr(L(".l0"), getnr(L(".l"))); + nr(L(".l"), v); +} +void +r_ll(int argc, Rune **argv) +{ + if(argc < 2) + ll(0); + else if(argv[1][0] == '+') + ll(getnr(L(".l"))+evalscale(argv[1]+1, 'v')); + else if(argv[1][0] == '-') + ll(getnr(L(".l"))-evalscale(argv[1]+1, 'v')); + else + ll(evalscale(argv[1], 'm')); + if(argc > 2) + warn("extra arguments to .ll"); +} + +void +in(int v) +{ + nr(L(".i0"), getnr(L(".i"))); + nr(L(".i"), v); + /* XXX */ +} +void +r_in(int argc, Rune **argv) +{ + if(argc < 2) + in(getnr(L(".i0"))); + else if(argv[1][0] == '+') + in(getnr(L(".i"))+evalscale(argv[1]+1, 'm')); + else if(argv[1][0] == '-') + in(getnr(L(".i"))-evalscale(argv[1]+1, 'm')); + else + in(evalscale(argv[1], 'm')); + if(argc > 3) + warn("extra arguments to .in"); +} + +void +ti(int v) +{ + nr(L(".ti"), v); +} +void +r_ti(int argc, Rune **argv) +{ + USED(argc); + ti(evalscale(argv[1], 'm')); +} + +void +t6init(void) +{ + addreq(L("ll"), r_ll, -1); + addreq(L("in"), r_in, -1); + addreq(L("ti"), r_ti, 1); + + nr(L(".l"), eval(L("6.5i"))); +} + blob - /dev/null blob + 19b77ec1f9c3f5ac6bc7d140b1c2f83aa3a2cfe7 (mode 644) --- /dev/null +++ src/cmd/htmlroff/t7.c @@ -0,0 +1,543 @@ +/* + * 7. Macros, strings, diversion, and position traps. + * + * macros can override builtins + * builtins can be renamed or removed! + */ + +#include "a.h" + +enum +{ + MAXARG = 10, + MAXMSTACK = 40 +}; + +/* macro invocation frame */ +typedef struct Mac Mac; +struct Mac +{ + int argc; + Rune *argv[MAXARG]; +}; + +Mac mstack[MAXMSTACK]; +int nmstack; +void emitdi(void); +void flushdi(void); + +/* + * Run a user-defined macro. + */ +void popmacro(void); +int +runmacro(int dot, int argc, Rune **argv) +{ + Rune *p; + int i; + Mac *m; + +if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]); + p = getds(argv[0]); + if(p == nil){ + if(verbose) + warn("ignoring unknown request %C%S", dot, argv[0]); + if(verbose > 1){ + for(i=0; i= nelem(mstack)){ + fprint(2, "%L: macro stack overflow:"); + for(i=0; iargc = argc; + for(i=0; iargv[i] = erunestrdup(argv[i]); + pushinputstring(p); + nr(L(".$"), argc-1); + inputnotify(popmacro); + return 0; +} + +void +popmacro(void) +{ + int i; + Mac *m; + + if(--nmstack < 0){ + fprint(2, "%L: macro stack underflow\n"); + return; + } + m = &mstack[nmstack]; + for(i=0; iargc; i++) + free(m->argv[i]); + if(nmstack > 0) + nr(L(".$"), mstack[nmstack-1].argc-1); + else + nr(L(".$"), 0); +} + +void popmacro1(void); +jmp_buf runjb[10]; +int nrunjb; + +void +runmacro1(Rune *name) +{ + Rune *argv[2]; + int obol; + +if(verbose) fprint(2, "outcb %p\n", outcb); + obol = bol; + argv[0] = name; + argv[1] = nil; + bol = 1; + if(runmacro('.', 1, argv) >= 0){ + inputnotify(popmacro1); + if(!setjmp(runjb[nrunjb++])) + runinput(); + else + if(verbose) fprint(2, "finished %S\n", name); + } + bol = obol; +} + +void +popmacro1(void) +{ + popmacro(); + if(nrunjb >= 0) + longjmp(runjb[--nrunjb], 1); +} + +/* + * macro arguments + * + * "" means " inside " " + * "" empty string + * \newline can be done + * argument separator is space (not tab) + * number register .$ = number of arguments + * no arguments outside macros or in strings + * + * arguments copied in copy mode + */ + +/* + * diversions + * + * processed output diverted + * dn dl registers vertical and horizontal size of last diversion + * .z - current diversion name + */ + +/* + * traps + * + * skip most + * .t register - distance to next trap + */ +static Rune *trap0; + +void +outtrap(void) +{ + Rune *t; + + if(outcb) + return; + if(trap0){ +if(verbose) fprint(2, "trap: %S\n", trap0); + t = trap0; + trap0 = nil; + runmacro1(t); + free(t); + } +} + +/* .wh - install trap */ +void +r_wh(int argc, Rune **argv) +{ + int i; + + if(argc < 2) + return; + + i = eval(argv[1]); + if(argc == 2){ + if(i == 0){ + free(trap0); + trap0 = nil; + }else + if(verbose) + warn("not removing trap at %d", i); + } + if(argc > 2){ + if(i == 0){ + free(trap0); + trap0 = erunestrdup(argv[2]); + }else + if(verbose) + warn("not installing %S trap at %d", argv[2], i); + } +} + +void +r_ch(int argc, Rune **argv) +{ + int i; + + if(argc == 2){ + if(trap0 && runestrcmp(argv[1], trap0) == 0){ + free(trap0); + trap0 = nil; + }else + if(verbose) + warn("not removing %S trap", argv[1]); + return; + } + if(argc >= 3){ + i = eval(argv[2]); + if(i == 0){ + free(trap0); + trap0 = erunestrdup(argv[1]); + }else + if(verbose) + warn("not moving %S trap to %d", argv[1], i); + } +} + +void +r_dt(int argc, Rune **argv) +{ + USED(argc); + USED(argv); + warn("ignoring diversion trap"); +} + +/* define macro - .de, .am, .ig */ +void +r_de(int argc, Rune **argv) +{ + Rune *end, *p; + Fmt fmt; + int ignore, len; + + delreq(argv[1]); + delraw(argv[1]); + ignore = runestrcmp(argv[0], L("ig")) == 0; + if(!ignore) + runefmtstrinit(&fmt); + end = L(".."); + if(argc >= 3) + end = argv[2]; + if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil) + fmtrunestrcpy(&fmt, p); + len = runestrlen(end); + while((p = readline(CopyMode)) != nil){ + if(runestrncmp(p, end, len) == 0 + && (p[len]==' ' || p[len]==0 || p[len]=='\t' + || (p[len]=='\\' && p[len+1]=='}'))){ + free(p); + goto done; + } + if(!ignore) + fmtprint(&fmt, "%S\n", p); + free(p); + } + warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end); +done: + if(ignore) + return; + p = runefmtstrflush(&fmt); + if(p == nil) + sysfatal("out of memory"); + ds(argv[1], p); + free(p); +} + +/* define string .ds .as */ +void +r_ds(Rune *cmd) +{ + Rune *name, *line, *p; + + name = copyarg(); + line = readline(CopyMode); + if(name == nil || line == nil){ + free(name); + return; + } + p = line; + if(*p == '"') + p++; + if(cmd[0] == 'd') + ds(name, p); + else + as(name, p); + free(name); + free(line); +} + +/* remove request, macro, or string */ +void +r_rm(int argc, Rune **argv) +{ + int i; + + emitdi(); + for(i=1; i 0 && p[n-1] != '\n'){ + p = runerealloc(p, n+2); + p[n] = '\n'; + p[n+1] = 0; + } + } + as(di[ndi-1], p); + free(p); +} + +void +outdi(Rune r) +{ +if(!difmtinit) abort(); + if(r == Uempty) + return; + fmtrune(&difmt, r); +} + +/* .di, .da */ +void +r_di(int argc, Rune **argv) +{ + br(); + if(argc > 2) + warn("extra arguments to %C%S", dot, argv[0]); + if(argc == 1){ + /* end diversion */ + if(ndi <= 0){ + // warn("unmatched %C%S", dot, argv[0]); + return; + } + flushdi(); + if(--ndi == 0){ + _nr(L(".z"), nil); + outcb = nil; + }else{ + _nr(L(".z"), di[ndi-1]); + runefmtstrinit(&difmt); + fmtrune(&difmt, Uformatted); + difmtinit = 1; + } + return; + } + /* start diversion */ + /* various register state should be saved, but it's all useless to us */ + flushdi(); + if(ndi >= nelem(di)) + sysfatal("%Cdi overflow", dot); + if(argv[0][1] == 'i') + ds(argv[1], nil); + _nr(L(".z"), argv[1]); + runestrcpy(di[ndi++], argv[1]); + runefmtstrinit(&difmt); + fmtrune(&difmt, Uformatted); + difmtinit = 1; + outcb = outdi; +} + +/* .wh - install trap */ +/* .ch - change trap */ +/* .dt - install diversion trap */ + +/* set input-line count trap */ +int itrapcount; +int itrapwaiting; +Rune *itrapname; + +void +r_it(int argc, Rune **argv) +{ + if(argc < 3){ + itrapcount = 0; + return; + } + itrapcount = eval(argv[1]); + free(itrapname); + itrapname = erunestrdup(argv[2]); +} + +void +itrap(void) +{ + itrapset(); + if(itrapwaiting){ + itrapwaiting = 0; + runmacro1(itrapname); + } +} + +void +itrapset(void) +{ + if(itrapcount > 0 && --itrapcount == 0) + itrapwaiting = 1; +} + +/* .em - invoke macro when all input is over */ +void +r_em(int argc, Rune **argv) +{ + Rune buf[20]; + + USED(argc); + runesnprint(buf, nelem(buf), ".%S\n", argv[1]); + as(L("eof"), buf); +} + +int +e_star(void) +{ + Rune *p; + + p = getds(getname()); + if(p) + pushinputstring(p); + return 0; +} + +int +e_t(void) +{ + if(inputmode&CopyMode) + return '\t'; + return 0; +} + +int +e_a(void) +{ + if(inputmode&CopyMode) + return '\a'; + return 0; +} + +int +e_backslash(void) +{ + if(inputmode&ArgMode) + ungetrune('\\'); + return backslash; +} + +int +e_dot(void) +{ + return '.'; +} + +int +e_dollar(void) +{ + int c; + + c = getnext(); + if(c < '1' || c > '9'){ + ungetnext(c); + return 0; + } + c -= '0'; + if(nmstack <= 0 || mstack[nmstack-1].argc <= c) + return 0; + pushinputstring(mstack[nmstack-1].argv[c]); + return 0; +} + +void +t7init(void) +{ + addreq(L("de"), r_de, -1); + addreq(L("am"), r_de, -1); + addreq(L("ig"), r_de, -1); + addraw(L("ds"), r_ds); + addraw(L("as"), r_ds); + addreq(L("rm"), r_rm, -1); + addreq(L("rn"), r_rn, -1); + addreq(L("di"), r_di, -1); + addreq(L("da"), r_di, -1); + addreq(L("it"), r_it, -1); + addreq(L("em"), r_em, 1); + addreq(L("wh"), r_wh, -1); + addreq(L("ch"), r_ch, -1); + addreq(L("dt"), r_dt, -1); + + addesc('$', e_dollar, CopyMode|ArgMode|HtmlMode); + addesc('*', e_star, CopyMode|ArgMode|HtmlMode); + addesc('t', e_t, CopyMode|ArgMode); + addesc('a', e_a, CopyMode|ArgMode); + addesc('\\', e_backslash, ArgMode|CopyMode); + addesc('.', e_dot, CopyMode|ArgMode); + + ds(L("eof"), L(".sp 0.5i\n")); + ds(L(".."), L("")); +} + blob - /dev/null blob + ead5a020085382490c43bd76912c418fb7e25cc9 (mode 644) --- /dev/null +++ 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; i0; 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; inext){ + 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); +} + blob - /dev/null blob + c9e045642501c87185bd0340dd1c7c9f803428aa (mode 644) --- /dev/null +++ src/cmd/htmlroff/t9.c @@ -0,0 +1,6 @@ +/* + * 9. Tabs, leaders, and fields. + */ + +XXX + blob - /dev/null blob + 99e99543f16d229d322dfe99f2f7d194769ec68a (mode 644) --- /dev/null +++ src/cmd/htmlroff/util.c @@ -0,0 +1,123 @@ +#include "a.h" + +void* +emalloc(uint n) +{ + void *v; + + v = mallocz(n, 1); + if(v == nil) + sysfatal("out of memory"); + return v; +} + +char* +estrdup(char *s) +{ + char *t; + + t = strdup(s); + if(t == nil) + sysfatal("out of memory"); + return t; +} + +Rune* +erunestrdup(Rune *s) +{ + Rune *t; + + t = emalloc(sizeof(Rune)*(runestrlen(s)+1)); + if(t == nil) + sysfatal("out of memory"); + runestrcpy(t, s); + return t; +} + +void* +erealloc(void *ov, uint n) +{ + void *v; + + v = realloc(ov, n); + if(v == nil) + sysfatal("out of memory"); + return v; +} + +Rune* +erunesmprint(char *fmt, ...) +{ + Rune *s; + va_list arg; + + va_start(arg, fmt); + s = runevsmprint(fmt, arg); + va_end(arg); + if(s == nil) + sysfatal("out of memory"); + return s; +} + +char* +esmprint(char *fmt, ...) +{ + char *s; + va_list arg; + + va_start(arg, fmt); + s = vsmprint(fmt, arg); + va_end(arg); + if(s == nil) + sysfatal("out of memory"); + return s; +} + +void +warn(char *fmt, ...) +{ + va_list arg; + + fprint(2, "htmlroff: %L: "); + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + fprint(2, "\n"); +} + +/* + * For non-Unicode compilers, so we can say + * L("asdf") and get a Rune string. Assumes strings + * are identified by their pointers, so no mutable strings! + */ +typedef struct Lhash Lhash; +struct Lhash +{ + char *s; + Lhash *next; + Rune r[1]; +}; +static Lhash *hash[1127]; + +Rune* +L(char *s) +{ + Rune *p; + Lhash *l; + uint h; + + h = (uintptr)s%nelem(hash); + for(l=hash[h]; l; l=l->next) + if(l->s == s) + return l->r; + l = emalloc(sizeof *l+(utflen(s)+1)*sizeof(Rune)); + p = l->r; + l->s = s; + while(*s) + s += chartorune(p++, s); + *p = 0; + l->next = hash[h]; + hash[h] = l; + return l->r; +} + blob - /dev/null blob + d03381e769fa4241d98fa640e0e928efc09e6c7e (mode 644) --- /dev/null +++ tmac/tmac.html @@ -0,0 +1,94 @@ +.de HTML +\! \ +\! \ +.html html +.html head +.if !'\\$1'' .html title \\$1 +.HEAD +.html head +.html body +.. +.de FSFIRST +.de NOTES xx +._NOTES +.rm _NOTES +xx +.em NOTES +.da _NOTES +.sp +.B "Notes +.sp +.da +.. +.de FS +.FSFIRST +.rm FSFIRST +.da _NOTES +.. +.de FE +.sp +.da +.. +.nr png -1 1 +.de TS +.ds pngbase "\\*[basename] +.if '\\*[pngbase]'' .ds pngbase \\n(.B +.ds pngfile \\*[pngbase]\\n+[png].png +.html -
+.\" The .inputpipe must be the last line of the macro! +.inputpipe .TE troff2png >\\*[pngfile] +.. +.de TE +.. +.de PS +.ds pngbase "\\*[basename] +.if '\\*[pngbase]'' .ds pngbase \\n(.B +.ds pngfile \\*[pngbase]\\n+[png].png +.html -
+.inputpipe .PE troff2png >\\*[pngfile] +.. +.de PE +.. +.de B1 +.margin 0 +.nr TW 10 +.nr TW1 80 +.if !'\\$1'' .nr TW \\$1 +.if !'\\$2'' .nr TW1 \\$2 +.html box \ +
\ +\ +\ + \ +\ + +.html box0 +.html box1 \ +\ + +.html box +.margin 1 +.. blob - 0183e2d9281a76c73befe7f955ab170b3eb9bd75 blob + c14de15dc02c8b9ff2260e33ce3bfb7b577ec7c3 --- tmac/tmac.s +++ tmac/tmac.s @@ -308,9 +308,11 @@ .di WT .na .fi +.ie h .ll \\n(LLu +.el \{\ .ll 5.0i .if n .if \\n(TN .ll 29 -.if t .if \\n(TN .ll 3.5i +.if t .if \\n(TN .ll 3.5i \} .ft 3 .ps \\n(PS .if !\\n(TN \{\ @@ -318,6 +320,7 @@ . vs \\n(.s+2 . rm CS\} .hy 0 +.if h .ce 999 .. .de TX .rs @@ -358,6 +361,7 @@ . ft 3 . ll 16\}\} .ps \\n(PS +.if h .ce 999 .. .de AX .ft 1 @@ -503,6 +507,7 @@ ABSTRACT .ie \\n(VS>=41 .vs \\n(VSu .el .vs \\n(VSp .ti +\\n(PIu +.fi .. . \"AE - end of an abstract .de AE @@ -704,6 +709,14 @@ Computing Science Technical Report No. \\*(MN .if \\$1H .TQ .nr IX 1 .. +.if h \{\ +.de TS +.nr tp -1 1 +.ds tp x\\n+(tp.png +.html -
+.dp .TE troff2png >\\*(tp +.. +.\} .de TQ .di TT .nr IT 1 @@ -818,9 +831,18 @@ Computing Science Technical Report No. \\*(MN .in .if \\n($1>0 .sp .65 .. +.if h \{\ +.de PS +.nr tp -1 1 +.ds tp x\\n+(tp.png +.html -
+.dp .PE troff2png >\\*(tp +.. +.\} . \" .P1/.P2 macros for programs . .nr XP 1 \" delta point size for program +.if h .nr XP 0 .nr XV 1p \" delta vertical for programs .nr XT 8 \" delta tab stop for programs .nr DV .5v \" space before start of program @@ -832,10 +854,11 @@ Computing Science Technical Report No. \\*(MN .br .nr v \\n(.v .di p1 -.in \\n(P1u +.in +\\n(P1u .nf .ps -\\n(XP .vs -\\n(XVu +.nr xx \\n(.sp .ft CW .nr t \\n(XT*\\w'x'u .ta 1u*\\ntu 2u*\\ntu 3u*\\ntu 4u*\\ntu 5u*\\ntu 6u*\\ntu 7u*\\ntu 8u*\\ntu 9u*\\ntu 10u*\\ntu 11u*\\ntu 12u*\\ntu 13u*\\ntu 14u*\\ntu @@ -1565,6 +1588,50 @@ operating system\\$1 .if \\n(BQ .fi .br .. +.if h \{\ +.de B1 +.margin 0 +.nr TW 10 +.nr TW1 80 +.if !'\\$1'' .nr TW \\$1 +.if !'\\$2'' .nr TW1 \\$2 +.html pic \ +
\ +
\ + \ + \ + \ + \ +
\ + \ + \ + \ + \ +
+.. +.de B2 +.html box1 +.html box0
\ + \ + \ +
\ + \ + \ + \ + \ +
\ +\ + \ +\ + +.html pic0 +.html pic1 \ +\ + +.html pic \} +.margin 1 +.. +.\} .de AT .nf .sp blob - 40c712dca865398d66d5fa452eb358e254ee30dd blob + 63311c640f8c9d5eff7d3538bacb6454eb659d1a --- tmac/tmac.skeep +++ tmac/tmac.skeep @@ -71,12 +71,14 @@ .in 0 .ls 1 .if \\n(TB=0 .ev +.if \\n(TB=0 .KX .if \\n(TB=0 .br .if \\n(TB=0 .ev 2 .if \\n(TB=0 .KK .ls .ce 0 .if \\n(TB=0 .rm KK +.if \\n(TB=0 .KY .if \\n(TB .da KJ .if \\n(TB \!.KD \\n(dn \\n(KV .if \\n(TB .KK
\ + \ + \ + \ + \ +
\ + \ + \ + \ + \ +
\} +.. +.de B2 +.html pic1 +.html pic0
\ + \ + \ +
\ + \ + \ + \ + \ +