#include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h> enum{ Nfont = 11, Wid = 20 /* tmac.anhtml sets page width to 20" so we can recognize .nf text */}; typedef ulong Char;typedef struct Troffchar Troffchar;typedef struct Htmlchar Htmlchar;typedef struct Font Font;typedef struct HTMLfont HTMLfont; /* a Char is 32 bits. low 16 bits are the rune. higher are attributes */enum{ Italic = 16, Bold, CW, Indent1, Indent2, Indent3, Heading = 25, Anchor = 26 /* must be last */}; enum /* magic emissions */{ Estring = 0, Epp = 1<<16}; int attrorder[] = { Indent1, Indent2, Indent3, Heading, Anchor, Italic, Bold, CW }; int nest[10];int nnest; struct Troffchar{ char *name; char *value;}; struct Htmlchar{ char *utf; char *name; int value;}; #include "chars.h" struct Font{ char *name; HTMLfont *htmlfont;}; struct HTMLfont{ char *name; char *htmlname; int bit;}; /* R must be first; it's the default representation for fonts we don't recognize */HTMLfont htmlfonts[] ={ "R", nil, 0, "LuxiSans", nil, 0, "I", "i", Italic, "LuxiSans-Oblique", "i", Italic, "CW", "tt", CW, "LuxiMono", "tt", CW, nil, nil}; #define TABLE "<table border=0 cellpadding=0 cellspacing=0>" char*onattr[8*sizeof(ulong)] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "<i>", /* italic */ "<b>", /* bold */ "<tt><font size=+1>", /* cw */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent1 */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent2 */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent3 */ 0, 0, 0, "<p><font size=+1><b>", /* heading 25 */ "<unused>", /* anchor 26 */}; char*offattr[8*sizeof(ulong)] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "</i>", /* italic */ "</b>", /* bold */ "</font></tt>", /* cw */ "<-/table>", /* indent1 */ "<-/table>", /* indent2 */ "<-/table>", /* indent3 */ 0, 0, 0, "</b></font>", /* heading 25 */ "</a>", /* anchor 26 */}; Font *font[Nfont]; Biobuf bout;int debug = 0; /* troff state */int page = 1;int ft = 1;int vp = 0;int hp = 0;int ps = 1;int res = 720; int didP = 0;int atnewline = 1;int prevlineH = 0;ulong attr = 0; /* or'ed into each Char */ Char *chars;int nchars;int nalloc;char** anchors; /* allocated in order */int nanchors; char *pagename;char *section; char *filename;int cno;char buf[8192];char *title = "Plan 9 man page"; void process(Biobuf*, char*);void mountfont(int, char*);void switchfont(int);void header(char*);void flush(void);void trailer(void); void*emalloc(ulong n){ void *p; p = malloc(n); if(p == nil) sysfatal("malloc failed: %r"); return p;} void*erealloc(void *p, ulong n){ p = realloc(p, n); if(p == nil) sysfatal("realloc failed: %r"); return p;} char*estrdup(char *s){ char *t; t = strdup(s); if(t == nil) sysfatal("strdup failed: %r"); return t;} voidusage(void){ fprint(2, "usage: troff2html [-d] [-t title] [file ...]\n"); exits("usage");} inthccmp(const void *va, const void *vb){ Htmlchar *a, *b; a = (Htmlchar*)va; b = (Htmlchar*)vb; return a->value - b->value;} voidmain(int argc, char *argv[]){ int i; Biobuf in, *inp; Rune r; for(i=0; i<nelem(htmlchars); i++){ chartorune(&r, htmlchars[i].utf); htmlchars[i].value = r; } qsort(htmlchars, nelem(htmlchars), sizeof(htmlchars[0]), hccmp); ARGBEGIN{ case 't': title = ARGF(); if(title == nil) usage(); break; case 'd': debug++; break; default: usage(); }ARGEND Binit(&bout, 1, OWRITE); if(argc == 0){ Binit(&in, 0, OREAD); process(&in, "<stdin>"); }else{ for(i=0; i<argc; i++){ inp = Bopen(argv[i], OREAD); if(inp == nil) sysfatal("can't open %s: %r", argv[i]); process(inp, argv[i]); Bterm(inp); } } header(title); flush(); trailer(); exits(nil);} voidemitul(ulong ul, int special){ ulong a, c; if(nalloc == nchars){ nalloc += 10000; chars = realloc(chars, nalloc*sizeof(chars[0])); if(chars == nil) sysfatal("malloc failed: %r"); } if(!special){ a = ul&~0xFFFF; c = ul&0xFFFF; /* * Attr-specific transformations. */ if((a&(1<<CW)) && c=='-') c = 0x2212; if(!(a&(1<<CW))){ if(c == '`') c = 0x2018; if(c == '\'') c = 0x2019; } ul = a|c; /* * Turn single quotes into double quotes. */ if(nchars > 0){ if(c == 0x2018 && (chars[nchars-1]&0xFFFF) == 0x2018 && a==(chars[nchars-1]&~0xFFFF)){ chars[nchars-1] = (ul&~0xFFFF) | 0x201C; return; } if(c == 0x2019 && (chars[nchars-1]&0xFFFF) == 0x2019 && a==(chars[nchars-1]&~0xFFFF)){ chars[nchars-1] = (ul&~0xFFFF) | 0x201D; return; } } } chars[nchars++] = ul;} voidemit(Rune r){ emitul(r | attr, 0); /* * Close man page references early, so that * .IR proof (1), * doesn't make the comma part of the link. */ if(r == ')') attr &= ~(1<<Anchor);} voidemitstr(char *s){ emitul(Estring | attr, 0); emitul((ulong)s, 1);} int indentlevel;int linelen; voidiputrune(Biobuf *b, Rune r){ int i; if(linelen++ > 60 && r == ' ') r = '\n'; if(r >= 0x80) Bprint(b, "&#%d;", r); else Bputrune(b, r); if(r == '\n'){ for(i=0; i<indentlevel; i++) Bprint(b, " "); linelen = 0; }} voidiputs(Biobuf *b, char *s){ if(s[0]=='<' && s[1]=='+'){ iputrune(b, '\n'); Bprint(b, "<%s", s+2); indentlevel++; iputrune(b, '\n'); }else if(s[0]=='<' && s[1]=='-'){ indentlevel--; iputrune(b, '\n'); Bprint(b, "<%s", s+2); iputrune(b, '\n'); }else Bprint(b, "%s", s);} voidsetattr(ulong a){ int on, off, i, j; on = a & ~attr; off = attr & ~a; /* walk up the nest stack until we reach something we need to turn off. */ for(i=0; i<nnest; i++) if(off&(1<<nest[i])) break; /* turn off everything above that */ for(j=nnest-1; j>=i; j--) iputs(&bout, offattr[nest[j]]); /* turn on everything we just turned off but didn't want to */ for(j=i; j<nnest; j++) if(a&(1<<nest[j])) iputs(&bout, onattr[nest[j]]); else nest[j] = 0; /* shift the zeros (turned off things) up */ for(i=j=0; i<nnest; i++) if(nest[i] != 0) nest[j++] = nest[i]; nnest = j; /* now turn on the new attributes */ for(i=0; i<nelem(attrorder); i++){ j = attrorder[i]; if(on&(1<<j)){ if(j == Anchor) onattr[j] = anchors[nanchors++]; iputs(&bout, onattr[j]); nest[nnest++] = j; } } attr = a;} voidflush(void){ int i; ulong c, a; nanchors = 0; for(i=0; i<nchars; i++){ c = chars[i]; if(c == Epp){ iputrune(&bout, '\n'); iputs(&bout, TABLE "<tr height=5><td></table>"); iputrune(&bout, '\n'); continue; } a = c & ~0xFFFF; c &= 0xFFFF; /* * If we're going to something off after a space, * let's just turn it off before. */ if(c==' ' && i<nchars-1 && (chars[i+1]&0xFFFF) >= 32) a ^= a & ~chars[i+1]; setattr(a); if(c == Estring){ /* next word is string to print */ iputs(&bout, (char*)chars[++i]); continue; } iputrune(&bout, c & 0xFFFF); }} voidheader(char *s){ char *p; Bprint(&bout, "<head>\n"); if(pagename && section){ char buf[512]; strecpy(buf, buf+sizeof buf, pagename); for(p=buf; *p; p++) *p = tolower((uchar)*p); Bprint(&bout, "<title>%s(%s) - %s</title>\n", buf, section, s); }else Bprint(&bout, "<title>%s</title>\n", s); Bprint(&bout, "<meta content=\"text/html; charset=utf-8\" http-equiv=Content-Type>\n"); Bprint(&bout, "</head>\n"); Bprint(&bout, "<body bgcolor=#ffffff>\n"); Bprint(&bout, "<table border=0 cellpadding=0 cellspacing=0 width=100%%>\n"); Bprint(&bout, "<tr height=10><td>\n"); Bprint(&bout, "<tr><td width=20><td>\n"); if(pagename && section){ Bprint(&bout, "<tr><td width=20><td><b>%s(%s)</b><td align=right><b>%s(%s)</b>\n", pagename, section, pagename, section); } Bprint(&bout, "<tr><td width=20><td colspan=2>\n");} voidtrailer(void){ Bprint(&bout, "<td width=20>\n"); Bprint(&bout, "<tr height=20><td>\n"); Bprint(&bout, "</table>\n"); #ifdef LUCENT { Tm *t; t = localtime(time(nil)); Bprint(&bout, TABLE "<tr height=20><td></table>\n"); Bprint(&bout, "<font size=-1><a href=\"http:/*www.lucent.com/copyright.html\">\n"); */ Bprint(&bout, "Portions Copyright</A> © %d Lucent Technologies. All rights reserved.</font>\n", t->year+1900); }#endif Bprint(&bout, "<!-- TRAILER -->\n"); Bprint(&bout, "</body></html>\n");} intgetc(Biobuf *b){ cno++; return Bgetrune(b);} voidungetc(Biobuf *b){ cno--; Bungetrune(b);} char*getline(Biobuf *b){ int i, c; for(i=0; i<sizeof buf; i++){ c = getc(b); if(c == Beof)Lines 1–500 of 871. Load more
#include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> enum{ Nfont = 11, Wid = 20 /* tmac.anhtml sets page width to 20" so we can recognize .nf text */ }; typedef ulong Char; typedef struct Troffchar Troffchar; typedef struct Htmlchar Htmlchar; typedef struct Font Font; typedef struct HTMLfont HTMLfont; /* a Char is 32 bits. low 16 bits are the rune. higher are attributes */ enum { Italic = 16, Bold, CW, Indent1, Indent2, Indent3, Heading = 25, Anchor = 26 /* must be last */ }; enum /* magic emissions */ { Estring = 0, Epp = 1<<16 }; int attrorder[] = { Indent1, Indent2, Indent3, Heading, Anchor, Italic, Bold, CW }; int nest[10]; int nnest; struct Troffchar { char *name; char *value; }; struct Htmlchar { char *utf; char *name; int value; }; #include "chars.h" struct Font{ char *name; HTMLfont *htmlfont; }; struct HTMLfont{ char *name; char *htmlname; int bit; }; /* R must be first; it's the default representation for fonts we don't recognize */ HTMLfont htmlfonts[] = { "R", nil, 0, "LuxiSans", nil, 0, "I", "i", Italic, "LuxiSans-Oblique", "i", Italic, "CW", "tt", CW, "LuxiMono", "tt", CW, nil, nil }; #define TABLE "<table border=0 cellpadding=0 cellspacing=0>" char* onattr[8*sizeof(ulong)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "<i>", /* italic */ "<b>", /* bold */ "<tt><font size=+1>", /* cw */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent1 */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent2 */ "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent3 */ 0, 0, 0, "<p><font size=+1><b>", /* heading 25 */ "<unused>", /* anchor 26 */ }; char* offattr[8*sizeof(ulong)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "</i>", /* italic */ "</b>", /* bold */ "</font></tt>", /* cw */ "<-/table>", /* indent1 */ "<-/table>", /* indent2 */ "<-/table>", /* indent3 */ 0, 0, 0, "</b></font>", /* heading 25 */ "</a>", /* anchor 26 */ }; Font *font[Nfont]; Biobuf bout; int debug = 0; /* troff state */ int page = 1; int ft = 1; int vp = 0; int hp = 0; int ps = 1; int res = 720; int didP = 0; int atnewline = 1; int prevlineH = 0; ulong attr = 0; /* or'ed into each Char */ Char *chars; int nchars; int nalloc; char** anchors; /* allocated in order */ int nanchors; char *pagename; char *section; char *filename; int cno; char buf[8192]; char *title = "Plan 9 man page"; void process(Biobuf*, char*); void mountfont(int, char*); void switchfont(int); void header(char*); void flush(void); void trailer(void); void* emalloc(ulong n) { void *p; p = malloc(n); if(p == nil) sysfatal("malloc failed: %r"); return p; } void* erealloc(void *p, ulong n) { p = realloc(p, n); if(p == nil) sysfatal("realloc failed: %r"); return p; } char* estrdup(char *s) { char *t; t = strdup(s); if(t == nil) sysfatal("strdup failed: %r"); return t; } void usage(void) { fprint(2, "usage: troff2html [-d] [-t title] [file ...]\n"); exits("usage"); } int hccmp(const void *va, const void *vb) { Htmlchar *a, *b; a = (Htmlchar*)va; b = (Htmlchar*)vb; return a->value - b->value; } void main(int argc, char *argv[]) { int i; Biobuf in, *inp; Rune r; for(i=0; i<nelem(htmlchars); i++){ chartorune(&r, htmlchars[i].utf); htmlchars[i].value = r; } qsort(htmlchars, nelem(htmlchars), sizeof(htmlchars[0]), hccmp); ARGBEGIN{ case 't': title = ARGF(); if(title == nil) usage(); break; case 'd': debug++; break; default: usage(); }ARGEND Binit(&bout, 1, OWRITE); if(argc == 0){ Binit(&in, 0, OREAD); process(&in, "<stdin>"); }else{ for(i=0; i<argc; i++){ inp = Bopen(argv[i], OREAD); if(inp == nil) sysfatal("can't open %s: %r", argv[i]); process(inp, argv[i]); Bterm(inp); } } header(title); flush(); trailer(); exits(nil); } void emitul(ulong ul, int special) { ulong a, c; if(nalloc == nchars){ nalloc += 10000; chars = realloc(chars, nalloc*sizeof(chars[0])); if(chars == nil) sysfatal("malloc failed: %r"); } if(!special){ a = ul&~0xFFFF; c = ul&0xFFFF; /* * Attr-specific transformations. */ if((a&(1<<CW)) && c=='-') c = 0x2212; if(!(a&(1<<CW))){ if(c == '`') c = 0x2018; if(c == '\'') c = 0x2019; } ul = a|c; /* * Turn single quotes into double quotes. */ if(nchars > 0){ if(c == 0x2018 && (chars[nchars-1]&0xFFFF) == 0x2018 && a==(chars[nchars-1]&~0xFFFF)){ chars[nchars-1] = (ul&~0xFFFF) | 0x201C; return; } if(c == 0x2019 && (chars[nchars-1]&0xFFFF) == 0x2019 && a==(chars[nchars-1]&~0xFFFF)){ chars[nchars-1] = (ul&~0xFFFF) | 0x201D; return; } } } chars[nchars++] = ul; } void emit(Rune r) { emitul(r | attr, 0); /* * Close man page references early, so that * .IR proof (1), * doesn't make the comma part of the link. */ if(r == ')') attr &= ~(1<<Anchor); } void emitstr(char *s) { emitul(Estring | attr, 0); emitul((ulong)s, 1); } int indentlevel; int linelen; void iputrune(Biobuf *b, Rune r) { int i; if(linelen++ > 60 && r == ' ') r = '\n'; if(r >= 0x80) Bprint(b, "&#%d;", r); else Bputrune(b, r); if(r == '\n'){ for(i=0; i<indentlevel; i++) Bprint(b, " "); linelen = 0; } } void iputs(Biobuf *b, char *s) { if(s[0]=='<' && s[1]=='+'){ iputrune(b, '\n'); Bprint(b, "<%s", s+2); indentlevel++; iputrune(b, '\n'); }else if(s[0]=='<' && s[1]=='-'){ indentlevel--; iputrune(b, '\n'); Bprint(b, "<%s", s+2); iputrune(b, '\n'); }else Bprint(b, "%s", s); } void setattr(ulong a) { int on, off, i, j; on = a & ~attr; off = attr & ~a; /* walk up the nest stack until we reach something we need to turn off. */ for(i=0; i<nnest; i++) if(off&(1<<nest[i])) break; /* turn off everything above that */ for(j=nnest-1; j>=i; j--) iputs(&bout, offattr[nest[j]]); /* turn on everything we just turned off but didn't want to */ for(j=i; j<nnest; j++) if(a&(1<<nest[j])) iputs(&bout, onattr[nest[j]]); else nest[j] = 0; /* shift the zeros (turned off things) up */ for(i=j=0; i<nnest; i++) if(nest[i] != 0) nest[j++] = nest[i]; nnest = j; /* now turn on the new attributes */ for(i=0; i<nelem(attrorder); i++){ j = attrorder[i]; if(on&(1<<j)){ if(j == Anchor) onattr[j] = anchors[nanchors++]; iputs(&bout, onattr[j]); nest[nnest++] = j; } } attr = a; } void flush(void) { int i; ulong c, a; nanchors = 0; for(i=0; i<nchars; i++){ c = chars[i]; if(c == Epp){ iputrune(&bout, '\n'); iputs(&bout, TABLE "<tr height=5><td></table>"); iputrune(&bout, '\n'); continue; } a = c & ~0xFFFF; c &= 0xFFFF; /* * If we're going to something off after a space, * let's just turn it off before. */ if(c==' ' && i<nchars-1 && (chars[i+1]&0xFFFF) >= 32) a ^= a & ~chars[i+1]; setattr(a); if(c == Estring){ /* next word is string to print */ iputs(&bout, (char*)chars[++i]); continue; } iputrune(&bout, c & 0xFFFF); } } void header(char *s) { char *p; Bprint(&bout, "<head>\n"); if(pagename && section){ char buf[512]; strecpy(buf, buf+sizeof buf, pagename); for(p=buf; *p; p++) *p = tolower((uchar)*p); Bprint(&bout, "<title>%s(%s) - %s</title>\n", buf, section, s); }else Bprint(&bout, "<title>%s</title>\n", s); Bprint(&bout, "<meta content=\"text/html; charset=utf-8\" http-equiv=Content-Type>\n"); Bprint(&bout, "</head>\n"); Bprint(&bout, "<body bgcolor=#ffffff>\n"); Bprint(&bout, "<table border=0 cellpadding=0 cellspacing=0 width=100%%>\n"); Bprint(&bout, "<tr height=10><td>\n"); Bprint(&bout, "<tr><td width=20><td>\n"); if(pagename && section){ Bprint(&bout, "<tr><td width=20><td><b>%s(%s)</b><td align=right><b>%s(%s)</b>\n", pagename, section, pagename, section); } Bprint(&bout, "<tr><td width=20><td colspan=2>\n"); } void trailer(void) { Bprint(&bout, "<td width=20>\n"); Bprint(&bout, "<tr height=20><td>\n"); Bprint(&bout, "</table>\n"); #ifdef LUCENT { Tm *t; t = localtime(time(nil)); Bprint(&bout, TABLE "<tr height=20><td></table>\n"); Bprint(&bout, "<font size=-1><a href=\"http:/*www.lucent.com/copyright.html\">\n"); */ Bprint(&bout, "Portions Copyright</A> © %d Lucent Technologies. All rights reserved.</font>\n", t->year+1900); } #endif Bprint(&bout, "<!-- TRAILER -->\n"); Bprint(&bout, "</body></html>\n"); } int getc(Biobuf *b) { cno++; return Bgetrune(b); } void ungetc(Biobuf *b) { cno--; Bungetrune(b); } char* getline(Biobuf *b) { int i, c; for(i=0; i<sizeof buf; i++){ c = getc(b); if(c == Beof)