1223a736eSDavid du Colombier #include <u.h> 2223a736eSDavid du Colombier #include <libc.h> 3223a736eSDavid du Colombier #include <bio.h> 4223a736eSDavid du Colombier 5223a736eSDavid du Colombier enum{ 6223a736eSDavid du Colombier Nfont = 11, 7223a736eSDavid du Colombier Wid = 20, /* tmac.anhtml sets page width to 20" so we can recognize .nf text */ 8223a736eSDavid du Colombier }; 9223a736eSDavid du Colombier 10223a736eSDavid du Colombier typedef ulong Char; 11223a736eSDavid du Colombier typedef struct Troffchar Troffchar; 12223a736eSDavid du Colombier typedef struct Htmlchar Htmlchar; 13223a736eSDavid du Colombier typedef struct Font Font; 14223a736eSDavid du Colombier typedef struct HTMLfont HTMLfont; 15223a736eSDavid du Colombier 16223a736eSDavid du Colombier /* a Char is 32 bits. low 16 bits are the rune. higher are attributes */ 17223a736eSDavid du Colombier enum 18223a736eSDavid du Colombier { 19223a736eSDavid du Colombier Italic = 16, 20*0fb05a45SDavid du Colombier Bold, 21*0fb05a45SDavid du Colombier CW, 22*0fb05a45SDavid du Colombier Indent1, 23*0fb05a45SDavid du Colombier Indent2, 24*0fb05a45SDavid du Colombier Indent3, 25223a736eSDavid du Colombier Heading = 25, 26223a736eSDavid du Colombier Anchor = 26, /* must be last */ 27223a736eSDavid du Colombier }; 28223a736eSDavid du Colombier 29*0fb05a45SDavid du Colombier enum /* magic emissions */ 30*0fb05a45SDavid du Colombier { 31*0fb05a45SDavid du Colombier Estring = 0, 32*0fb05a45SDavid du Colombier Epp = 1<<16, 33*0fb05a45SDavid du Colombier }; 34*0fb05a45SDavid du Colombier 35*0fb05a45SDavid du Colombier int attrorder[] = { Indent1, Indent2, Indent3, Heading, Anchor, Italic, Bold, CW }; 36*0fb05a45SDavid du Colombier 37*0fb05a45SDavid du Colombier int nest[10]; 38*0fb05a45SDavid du Colombier int nnest; 39*0fb05a45SDavid du Colombier 40223a736eSDavid du Colombier struct Troffchar 41223a736eSDavid du Colombier { 42223a736eSDavid du Colombier char *name; 43223a736eSDavid du Colombier char *value; 44223a736eSDavid du Colombier }; 45223a736eSDavid du Colombier 46223a736eSDavid du Colombier struct Htmlchar 47223a736eSDavid du Colombier { 48*0fb05a45SDavid du Colombier char *utf; 49223a736eSDavid du Colombier char *name; 50*0fb05a45SDavid du Colombier int value; 51223a736eSDavid du Colombier }; 52223a736eSDavid du Colombier 53223a736eSDavid du Colombier #include "chars.h" 54223a736eSDavid du Colombier 55223a736eSDavid du Colombier struct Font{ 56223a736eSDavid du Colombier char *name; 57223a736eSDavid du Colombier HTMLfont *htmlfont; 58223a736eSDavid du Colombier }; 59223a736eSDavid du Colombier 60223a736eSDavid du Colombier struct HTMLfont{ 61223a736eSDavid du Colombier char *name; 62223a736eSDavid du Colombier char *htmlname; 63223a736eSDavid du Colombier int bit; 64223a736eSDavid du Colombier }; 65223a736eSDavid du Colombier 66223a736eSDavid du Colombier /* R must be first; it's the default representation for fonts we don't recognize */ 67223a736eSDavid du Colombier HTMLfont htmlfonts[] = 68223a736eSDavid du Colombier { 69223a736eSDavid du Colombier "R", nil, 0, 70223a736eSDavid du Colombier "LucidaSans", nil, 0, 71*0fb05a45SDavid du Colombier "I", "i", Italic, 72*0fb05a45SDavid du Colombier "LucidaSansI", "i", Italic, 73*0fb05a45SDavid du Colombier "CW", "tt", CW, 74*0fb05a45SDavid du Colombier "LucidaCW", "tt", CW, 75223a736eSDavid du Colombier nil, nil, 76223a736eSDavid du Colombier }; 77223a736eSDavid du Colombier 78*0fb05a45SDavid du Colombier #define TABLE "<table border=0 cellpadding=0 cellspacing=0>" 79*0fb05a45SDavid du Colombier 80223a736eSDavid du Colombier char* 81*0fb05a45SDavid du Colombier onattr[8*sizeof(ulong)] = 82*0fb05a45SDavid du Colombier { 83*0fb05a45SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 84*0fb05a45SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 85*0fb05a45SDavid du Colombier "<i>", /* italic */ 86*0fb05a45SDavid du Colombier "<b>", /* bold */ 87*0fb05a45SDavid du Colombier "<tt><font size=+1>", /* cw */ 88*0fb05a45SDavid du Colombier "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent1 */ 89*0fb05a45SDavid du Colombier "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent2 */ 90*0fb05a45SDavid du Colombier "<+table border=0 cellpadding=0 cellspacing=0><tr height=2><td><tr><td width=20><td>\n", /* indent3 */ 91*0fb05a45SDavid du Colombier 0, 92*0fb05a45SDavid du Colombier 0, 93*0fb05a45SDavid du Colombier 0, 94*0fb05a45SDavid du Colombier "<p><font size=+1><b>", /* heading 25 */ 95*0fb05a45SDavid du Colombier "<unused>", /* anchor 26 */ 96223a736eSDavid du Colombier }; 97223a736eSDavid du Colombier 98223a736eSDavid du Colombier char* 99*0fb05a45SDavid du Colombier offattr[8*sizeof(ulong)] = 100*0fb05a45SDavid du Colombier { 101*0fb05a45SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 102*0fb05a45SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 103*0fb05a45SDavid du Colombier "</i>", /* italic */ 104*0fb05a45SDavid du Colombier "</b>", /* bold */ 105*0fb05a45SDavid du Colombier "</font></tt>", /* cw */ 106*0fb05a45SDavid du Colombier "<-/table>", /* indent1 */ 107*0fb05a45SDavid du Colombier "<-/table>", /* indent2 */ 108*0fb05a45SDavid du Colombier "<-/table>", /* indent3 */ 109*0fb05a45SDavid du Colombier 0, 110*0fb05a45SDavid du Colombier 0, 111*0fb05a45SDavid du Colombier 0, 112*0fb05a45SDavid du Colombier "</b></font>", /* heading 25 */ 113*0fb05a45SDavid du Colombier "</a>", /* anchor 26 */ 114223a736eSDavid du Colombier }; 115223a736eSDavid du Colombier 116223a736eSDavid du Colombier Font *font[Nfont]; 117223a736eSDavid du Colombier 118223a736eSDavid du Colombier Biobuf bout; 119223a736eSDavid du Colombier int debug = 0; 120223a736eSDavid du Colombier 121223a736eSDavid du Colombier /* troff state */ 122223a736eSDavid du Colombier int page = 1; 123223a736eSDavid du Colombier int ft = 1; 124223a736eSDavid du Colombier int vp = 0; 125223a736eSDavid du Colombier int hp = 0; 126223a736eSDavid du Colombier int ps = 1; 127223a736eSDavid du Colombier int res = 720; 128223a736eSDavid du Colombier 129223a736eSDavid du Colombier int didP = 0; 130223a736eSDavid du Colombier int atnewline = 1; 131223a736eSDavid du Colombier int prevlineH = 0; 132223a736eSDavid du Colombier ulong attr = 0; /* or'ed into each Char */ 133223a736eSDavid du Colombier 134223a736eSDavid du Colombier Char *chars; 135223a736eSDavid du Colombier int nchars; 136223a736eSDavid du Colombier int nalloc; 137223a736eSDavid du Colombier char** anchors; /* allocated in order */ 138223a736eSDavid du Colombier int nanchors; 139223a736eSDavid du Colombier 140223a736eSDavid du Colombier char *filename; 141223a736eSDavid du Colombier int cno; 142223a736eSDavid du Colombier char buf[8192]; 143223a736eSDavid du Colombier char *title = "Plan 9 man page"; 144223a736eSDavid du Colombier 145223a736eSDavid du Colombier void process(Biobuf*, char*); 146223a736eSDavid du Colombier void mountfont(int, char*); 147223a736eSDavid du Colombier void switchfont(int); 148223a736eSDavid du Colombier void header(char*); 149223a736eSDavid du Colombier void flush(void); 150223a736eSDavid du Colombier void trailer(void); 151223a736eSDavid du Colombier 152223a736eSDavid du Colombier void* 153223a736eSDavid du Colombier emalloc(ulong n) 154223a736eSDavid du Colombier { 155223a736eSDavid du Colombier void *p; 156223a736eSDavid du Colombier 157223a736eSDavid du Colombier p = malloc(n); 158223a736eSDavid du Colombier if(p == nil) 159223a736eSDavid du Colombier sysfatal("malloc failed: %r"); 160223a736eSDavid du Colombier return p; 161223a736eSDavid du Colombier } 162223a736eSDavid du Colombier 163223a736eSDavid du Colombier void* 164223a736eSDavid du Colombier erealloc(void *p, ulong n) 165223a736eSDavid du Colombier { 166223a736eSDavid du Colombier 167223a736eSDavid du Colombier p = realloc(p, n); 168223a736eSDavid du Colombier if(p == nil) 169223a736eSDavid du Colombier sysfatal("realloc failed: %r"); 170223a736eSDavid du Colombier return p; 171223a736eSDavid du Colombier } 172223a736eSDavid du Colombier 173223a736eSDavid du Colombier char* 174223a736eSDavid du Colombier estrdup(char *s) 175223a736eSDavid du Colombier { 176223a736eSDavid du Colombier char *t; 177223a736eSDavid du Colombier 178223a736eSDavid du Colombier t = strdup(s); 179223a736eSDavid du Colombier if(t == nil) 180223a736eSDavid du Colombier sysfatal("strdup failed: %r"); 181223a736eSDavid du Colombier return t; 182223a736eSDavid du Colombier } 183223a736eSDavid du Colombier 184223a736eSDavid du Colombier void 185223a736eSDavid du Colombier usage(void) 186223a736eSDavid du Colombier { 187*0fb05a45SDavid du Colombier fprint(2, "usage: troff2html [-d] [-t title] [file ...]\n"); 188223a736eSDavid du Colombier exits("usage"); 189223a736eSDavid du Colombier } 190223a736eSDavid du Colombier 191*0fb05a45SDavid du Colombier int 192*0fb05a45SDavid du Colombier hccmp(const void *va, const void *vb) 193*0fb05a45SDavid du Colombier { 194*0fb05a45SDavid du Colombier Htmlchar *a, *b; 195*0fb05a45SDavid du Colombier 196*0fb05a45SDavid du Colombier a = (Htmlchar*)va; 197*0fb05a45SDavid du Colombier b = (Htmlchar*)vb; 198*0fb05a45SDavid du Colombier return a->value - b->value; 199*0fb05a45SDavid du Colombier } 200*0fb05a45SDavid du Colombier 201223a736eSDavid du Colombier void 202223a736eSDavid du Colombier main(int argc, char *argv[]) 203223a736eSDavid du Colombier { 204223a736eSDavid du Colombier int i; 205223a736eSDavid du Colombier Biobuf in, *inp; 206*0fb05a45SDavid du Colombier Rune r; 207*0fb05a45SDavid du Colombier 208*0fb05a45SDavid du Colombier for(i=0; i<nelem(htmlchars); i++){ 209*0fb05a45SDavid du Colombier chartorune(&r, htmlchars[i].utf); 210*0fb05a45SDavid du Colombier htmlchars[i].value = r; 211*0fb05a45SDavid du Colombier } 212*0fb05a45SDavid du Colombier qsort(htmlchars, nelem(htmlchars), sizeof(htmlchars[0]), hccmp); 213223a736eSDavid du Colombier 214223a736eSDavid du Colombier ARGBEGIN{ 215223a736eSDavid du Colombier case 't': 216223a736eSDavid du Colombier title = ARGF(); 217223a736eSDavid du Colombier if(title == nil) 218223a736eSDavid du Colombier usage(); 219223a736eSDavid du Colombier break; 220223a736eSDavid du Colombier case 'd': 221223a736eSDavid du Colombier debug++; 222223a736eSDavid du Colombier break; 223223a736eSDavid du Colombier default: 224223a736eSDavid du Colombier usage(); 225223a736eSDavid du Colombier }ARGEND 226*0fb05a45SDavid du Colombier 227223a736eSDavid du Colombier Binit(&bout, 1, OWRITE); 228223a736eSDavid du Colombier if(argc == 0){ 229223a736eSDavid du Colombier header(title); 230223a736eSDavid du Colombier Binit(&in, 0, OREAD); 231223a736eSDavid du Colombier process(&in, "<stdin>"); 232223a736eSDavid du Colombier }else{ 233223a736eSDavid du Colombier header(title); 234223a736eSDavid du Colombier for(i=0; i<argc; i++){ 235223a736eSDavid du Colombier inp = Bopen(argv[i], OREAD); 236223a736eSDavid du Colombier if(inp == nil) 237223a736eSDavid du Colombier sysfatal("can't open %s: %r", argv[i]); 238223a736eSDavid du Colombier process(inp, argv[i]); 239223a736eSDavid du Colombier Bterm(inp); 240223a736eSDavid du Colombier } 241223a736eSDavid du Colombier } 242223a736eSDavid du Colombier flush(); 243223a736eSDavid du Colombier trailer(); 244223a736eSDavid du Colombier exits(nil); 245223a736eSDavid du Colombier } 246223a736eSDavid du Colombier 247223a736eSDavid du Colombier void 248223a736eSDavid du Colombier emitul(ulong ul) 249223a736eSDavid du Colombier { 250223a736eSDavid du Colombier if(nalloc == nchars){ 251223a736eSDavid du Colombier nalloc += 10000; 252223a736eSDavid du Colombier chars = realloc(chars, nalloc*sizeof(chars[0])); 253223a736eSDavid du Colombier if(chars == nil) 254223a736eSDavid du Colombier sysfatal("malloc failed: %r"); 255223a736eSDavid du Colombier } 256223a736eSDavid du Colombier chars[nchars++] = ul; 257223a736eSDavid du Colombier } 258223a736eSDavid du Colombier 259223a736eSDavid du Colombier void 260223a736eSDavid du Colombier emit(Rune r) 261223a736eSDavid du Colombier { 262223a736eSDavid du Colombier emitul(r | attr); 263*0fb05a45SDavid du Colombier /* 264*0fb05a45SDavid du Colombier * Close man page references early, so that 265*0fb05a45SDavid du Colombier * .IR proof (1), 266*0fb05a45SDavid du Colombier * doesn't make the comma part of the link. 267*0fb05a45SDavid du Colombier */ 268*0fb05a45SDavid du Colombier if(r == ')') 269*0fb05a45SDavid du Colombier attr &= ~(1<<Anchor); 270223a736eSDavid du Colombier } 271223a736eSDavid du Colombier 272223a736eSDavid du Colombier void 273223a736eSDavid du Colombier emitstr(char *s) 274223a736eSDavid du Colombier { 275*0fb05a45SDavid du Colombier emitul(Estring); 276223a736eSDavid du Colombier emitul((ulong)s); 277223a736eSDavid du Colombier } 278223a736eSDavid du Colombier 279*0fb05a45SDavid du Colombier int indentlevel; 280*0fb05a45SDavid du Colombier int linelen; 281*0fb05a45SDavid du Colombier 282*0fb05a45SDavid du Colombier void 283*0fb05a45SDavid du Colombier iputrune(Biobuf *b, Rune r) 284*0fb05a45SDavid du Colombier { 285*0fb05a45SDavid du Colombier int i; 286*0fb05a45SDavid du Colombier 287*0fb05a45SDavid du Colombier if(linelen++ > 60 && r == ' ') 288*0fb05a45SDavid du Colombier r = '\n'; 289*0fb05a45SDavid du Colombier Bputrune(b, r); 290*0fb05a45SDavid du Colombier if(r == '\n'){ 291*0fb05a45SDavid du Colombier for(i=0; i<indentlevel; i++) 292*0fb05a45SDavid du Colombier Bprint(b, " "); 293*0fb05a45SDavid du Colombier linelen = 0; 294*0fb05a45SDavid du Colombier } 295*0fb05a45SDavid du Colombier } 296*0fb05a45SDavid du Colombier 297*0fb05a45SDavid du Colombier void 298*0fb05a45SDavid du Colombier iputs(Biobuf *b, char *s) 299*0fb05a45SDavid du Colombier { 300*0fb05a45SDavid du Colombier if(s[0]=='<' && s[1]=='+'){ 301*0fb05a45SDavid du Colombier iputrune(b, '\n'); 302*0fb05a45SDavid du Colombier Bprint(b, "<%s", s+2); 303*0fb05a45SDavid du Colombier indentlevel++; 304*0fb05a45SDavid du Colombier iputrune(b, '\n'); 305*0fb05a45SDavid du Colombier }else if(s[0]=='<' && s[1]=='-'){ 306*0fb05a45SDavid du Colombier indentlevel--; 307*0fb05a45SDavid du Colombier iputrune(b, '\n'); 308*0fb05a45SDavid du Colombier Bprint(b, "<%s", s+2); 309*0fb05a45SDavid du Colombier iputrune(b, '\n'); 310*0fb05a45SDavid du Colombier }else 311*0fb05a45SDavid du Colombier Bprint(b, "%s", s); 312*0fb05a45SDavid du Colombier } 313*0fb05a45SDavid du Colombier 314*0fb05a45SDavid du Colombier void 315*0fb05a45SDavid du Colombier setattr(ulong a) 316*0fb05a45SDavid du Colombier { 317*0fb05a45SDavid du Colombier int on, off, i, j; 318*0fb05a45SDavid du Colombier 319*0fb05a45SDavid du Colombier on = a & ~attr; 320*0fb05a45SDavid du Colombier off = attr & ~a; 321*0fb05a45SDavid du Colombier 322*0fb05a45SDavid du Colombier /* walk up the nest stack until we reach something we need to turn off. */ 323*0fb05a45SDavid du Colombier for(i=0; i<nnest; i++) 324*0fb05a45SDavid du Colombier if(off&(1<<nest[i])) 325*0fb05a45SDavid du Colombier break; 326*0fb05a45SDavid du Colombier 327*0fb05a45SDavid du Colombier /* turn off everything above that */ 328*0fb05a45SDavid du Colombier for(j=nnest-1; j>=i; j--) 329*0fb05a45SDavid du Colombier iputs(&bout, offattr[nest[j]]); 330*0fb05a45SDavid du Colombier 331*0fb05a45SDavid du Colombier /* turn on everything we just turned off but didn't want to */ 332*0fb05a45SDavid du Colombier for(j=i; j<nnest; j++) 333*0fb05a45SDavid du Colombier if(a&(1<<nest[j])) 334*0fb05a45SDavid du Colombier iputs(&bout, onattr[nest[j]]); 335*0fb05a45SDavid du Colombier else 336*0fb05a45SDavid du Colombier nest[j] = 0; 337*0fb05a45SDavid du Colombier 338*0fb05a45SDavid du Colombier /* shift the zeros (turned off things) up */ 339*0fb05a45SDavid du Colombier for(i=j=0; i<nnest; i++) 340*0fb05a45SDavid du Colombier if(nest[i] != 0) 341*0fb05a45SDavid du Colombier nest[j++] = nest[i]; 342*0fb05a45SDavid du Colombier nnest = j; 343*0fb05a45SDavid du Colombier 344*0fb05a45SDavid du Colombier /* now turn on the new attributes */ 345*0fb05a45SDavid du Colombier for(i=0; i<nelem(attrorder); i++){ 346*0fb05a45SDavid du Colombier j = attrorder[i]; 347*0fb05a45SDavid du Colombier if(on&(1<<j)){ 348*0fb05a45SDavid du Colombier if(j == Anchor) 349*0fb05a45SDavid du Colombier onattr[j] = anchors[nanchors++]; 350*0fb05a45SDavid du Colombier iputs(&bout, onattr[j]); 351*0fb05a45SDavid du Colombier nest[nnest++] = j; 352*0fb05a45SDavid du Colombier } 353*0fb05a45SDavid du Colombier } 354*0fb05a45SDavid du Colombier attr = a; 355*0fb05a45SDavid du Colombier } 356*0fb05a45SDavid du Colombier 357223a736eSDavid du Colombier void 358223a736eSDavid du Colombier flush(void) 359223a736eSDavid du Colombier { 360*0fb05a45SDavid du Colombier int i; 361*0fb05a45SDavid du Colombier ulong c, a; 362223a736eSDavid du Colombier 363*0fb05a45SDavid du Colombier nanchors = 0; 364223a736eSDavid du Colombier for(i=0; i<nchars; i++){ 365223a736eSDavid du Colombier c = chars[i]; 366*0fb05a45SDavid du Colombier if(c == Estring){ 367223a736eSDavid du Colombier /* next word is string to print */ 368*0fb05a45SDavid du Colombier iputs(&bout, (char*)chars[++i]); 369223a736eSDavid du Colombier continue; 370223a736eSDavid du Colombier } 371*0fb05a45SDavid du Colombier if(c == Epp){ 372*0fb05a45SDavid du Colombier iputrune(&bout, '\n'); 373*0fb05a45SDavid du Colombier iputs(&bout, TABLE "<tr height=5><td></table>"); 374*0fb05a45SDavid du Colombier iputrune(&bout, '\n'); 375*0fb05a45SDavid du Colombier continue; 376223a736eSDavid du Colombier } 377*0fb05a45SDavid du Colombier a = c & ~0xFFFF; 378*0fb05a45SDavid du Colombier c &= 0xFFFF; 379*0fb05a45SDavid du Colombier /* 380*0fb05a45SDavid du Colombier * If we're going to something off after a space, 381*0fb05a45SDavid du Colombier * let's just turn it off before. 382*0fb05a45SDavid du Colombier */ 383*0fb05a45SDavid du Colombier if(c == ' ' && i<nchars-1 && (chars[i+1]&0xFFFF) >= 32) 384*0fb05a45SDavid du Colombier a ^= a & ~chars[i+1]; 385*0fb05a45SDavid du Colombier setattr(a); 386*0fb05a45SDavid du Colombier iputrune(&bout, c & 0xFFFF); 387223a736eSDavid du Colombier } 388223a736eSDavid du Colombier } 389223a736eSDavid du Colombier 390223a736eSDavid du Colombier void 391223a736eSDavid du Colombier header(char *s) 392223a736eSDavid du Colombier { 393*0fb05a45SDavid du Colombier Bprint(&bout, "<head>\n"); 394*0fb05a45SDavid du Colombier Bprint(&bout, "<title>%s</title>\n", s); 395*0fb05a45SDavid du Colombier Bprint(&bout, "<meta content=\"text/html; charset=utf-8\" http-equiv=Content-Type>\n"); 396*0fb05a45SDavid du Colombier Bprint(&bout, "</head>\n"); 397*0fb05a45SDavid du Colombier Bprint(&bout, "<body bgcolor=#ffffff>\n"); 398223a736eSDavid du Colombier } 399223a736eSDavid du Colombier 400223a736eSDavid du Colombier void 401223a736eSDavid du Colombier trailer(void) 402223a736eSDavid du Colombier { 4039a747e4fSDavid du Colombier 404*0fb05a45SDavid du Colombier #ifdef LUCENT 4059a747e4fSDavid du Colombier t = localtime(time(nil)); 406*0fb05a45SDavid du Colombier Bprint(&bout, TABLE "<tr height=20><td></table>\n"); 407*0fb05a45SDavid du Colombier Bprint(&bout, "<font size=-1><a href=\"http://www.lucent.com/copyright.html\">\n"); 408*0fb05a45SDavid du Colombier Bprint(&bout, "Copyright</A> © %d Lucent Technologies. All rights reserved.</font>\n", t->year+1900); 409*0fb05a45SDavid du Colombier #endif 410*0fb05a45SDavid du Colombier Bprint(&bout, "</body></html>\n"); 411223a736eSDavid du Colombier } 412223a736eSDavid du Colombier 413223a736eSDavid du Colombier int 414223a736eSDavid du Colombier getc(Biobuf *b) 415223a736eSDavid du Colombier { 416223a736eSDavid du Colombier cno++; 417223a736eSDavid du Colombier return Bgetrune(b); 418223a736eSDavid du Colombier } 419223a736eSDavid du Colombier 420223a736eSDavid du Colombier void 421223a736eSDavid du Colombier ungetc(Biobuf *b) 422223a736eSDavid du Colombier { 423223a736eSDavid du Colombier cno--; 424223a736eSDavid du Colombier Bungetrune(b); 425223a736eSDavid du Colombier } 426223a736eSDavid du Colombier 427223a736eSDavid du Colombier char* 428223a736eSDavid du Colombier getline(Biobuf *b) 429223a736eSDavid du Colombier { 430223a736eSDavid du Colombier int i, c; 431223a736eSDavid du Colombier 432223a736eSDavid du Colombier for(i=0; i<sizeof buf; i++){ 433223a736eSDavid du Colombier c = getc(b); 434223a736eSDavid du Colombier if(c == Beof) 435223a736eSDavid du Colombier return nil; 436223a736eSDavid du Colombier buf[i] = c; 437223a736eSDavid du Colombier if(c == '\n'){ 438223a736eSDavid du Colombier buf[i] = '\0'; 439223a736eSDavid du Colombier break; 440223a736eSDavid du Colombier } 441223a736eSDavid du Colombier } 442223a736eSDavid du Colombier return buf; 443223a736eSDavid du Colombier } 444223a736eSDavid du Colombier 445223a736eSDavid du Colombier int 446223a736eSDavid du Colombier getnum(Biobuf *b) 447223a736eSDavid du Colombier { 448223a736eSDavid du Colombier int i, c; 449223a736eSDavid du Colombier 450223a736eSDavid du Colombier i = 0; 451223a736eSDavid du Colombier for(;;){ 452223a736eSDavid du Colombier c = getc(b); 453223a736eSDavid du Colombier if(c<'0' || '9'<c){ 454223a736eSDavid du Colombier ungetc(b); 455223a736eSDavid du Colombier break; 456223a736eSDavid du Colombier } 457223a736eSDavid du Colombier i = i*10 + (c-'0'); 458223a736eSDavid du Colombier } 459223a736eSDavid du Colombier return i; 460223a736eSDavid du Colombier } 461223a736eSDavid du Colombier 462223a736eSDavid du Colombier char* 463223a736eSDavid du Colombier getstr(Biobuf *b) 464223a736eSDavid du Colombier { 465223a736eSDavid du Colombier int i, c; 466223a736eSDavid du Colombier 467223a736eSDavid du Colombier for(i=0; i<sizeof buf; i++){ 468223a736eSDavid du Colombier /* must get bytes not runes */ 469223a736eSDavid du Colombier cno++; 470223a736eSDavid du Colombier c = Bgetc(b); 471223a736eSDavid du Colombier if(c == Beof) 472223a736eSDavid du Colombier return nil; 473223a736eSDavid du Colombier buf[i] = c; 474223a736eSDavid du Colombier if(c == '\n' || c==' ' || c=='\t'){ 475223a736eSDavid du Colombier ungetc(b); 476223a736eSDavid du Colombier buf[i] = '\0'; 477223a736eSDavid du Colombier break; 478223a736eSDavid du Colombier } 479223a736eSDavid du Colombier } 480223a736eSDavid du Colombier return buf; 481223a736eSDavid du Colombier } 482223a736eSDavid du Colombier 483223a736eSDavid du Colombier int 484223a736eSDavid du Colombier setnum(Biobuf *b, char *name, int min, int max) 485223a736eSDavid du Colombier { 486223a736eSDavid du Colombier int i; 487223a736eSDavid du Colombier 488223a736eSDavid du Colombier i = getnum(b); 489223a736eSDavid du Colombier if(debug > 2) 490223a736eSDavid du Colombier fprint(2, "set %s = %d\n", name, i); 491223a736eSDavid du Colombier if(min<=i && i<max) 492223a736eSDavid du Colombier return i; 493223a736eSDavid du Colombier sysfatal("value of %s is %d; min %d max %d at %s:#%d", name, i, min, max, filename, cno); 494223a736eSDavid du Colombier return i; 495223a736eSDavid du Colombier } 496223a736eSDavid du Colombier 497223a736eSDavid du Colombier void 498223a736eSDavid du Colombier xcmd(Biobuf *b) 499223a736eSDavid du Colombier { 500*0fb05a45SDavid du Colombier char *p, *fld[16], buf[1024]; 501*0fb05a45SDavid du Colombier 502223a736eSDavid du Colombier int i, nfld; 503223a736eSDavid du Colombier 504223a736eSDavid du Colombier p = getline(b); 505223a736eSDavid du Colombier if(p == nil) 506223a736eSDavid du Colombier sysfatal("xcmd error: %r"); 507223a736eSDavid du Colombier if(debug) 508223a736eSDavid du Colombier fprint(2, "x command '%s'\n", p); 509223a736eSDavid du Colombier nfld = tokenize(p, fld, nelem(fld)); 510223a736eSDavid du Colombier if(nfld == 0) 511223a736eSDavid du Colombier return; 512223a736eSDavid du Colombier switch(fld[0][0]){ 513223a736eSDavid du Colombier case 'f': 514223a736eSDavid du Colombier /* mount font */ 515223a736eSDavid du Colombier if(nfld != 3) 516223a736eSDavid du Colombier break; 517223a736eSDavid du Colombier i = atoi(fld[1]); 518223a736eSDavid du Colombier if(i<0 || Nfont<=i) 519223a736eSDavid du Colombier sysfatal("font %d out of range at %s:#%d", i, filename, cno); 520223a736eSDavid du Colombier mountfont(i, fld[2]); 521223a736eSDavid du Colombier return; 522223a736eSDavid du Colombier case 'i': 523223a736eSDavid du Colombier /* init */ 524223a736eSDavid du Colombier return; 525223a736eSDavid du Colombier case 'r': 526223a736eSDavid du Colombier if(nfld<2 || atoi(fld[1])!=res) 527223a736eSDavid du Colombier sysfatal("typesetter has unexpected resolution %s", fld[1]? fld[1] : "<unspecified>"); 528223a736eSDavid du Colombier return; 529223a736eSDavid du Colombier case 's': 530223a736eSDavid du Colombier /* stop */ 531223a736eSDavid du Colombier return; 532223a736eSDavid du Colombier case 't': 533223a736eSDavid du Colombier /* trailer */ 534223a736eSDavid du Colombier return; 535223a736eSDavid du Colombier case 'T': 536223a736eSDavid du Colombier if(nfld!=2 || strcmp(fld[1], "utf")!=0) 537223a736eSDavid du Colombier sysfatal("output for unknown typesetter type %s", fld[1]); 538223a736eSDavid du Colombier return; 539223a736eSDavid du Colombier case 'X': 540223a736eSDavid du Colombier if(nfld<3 || strcmp(fld[1], "html")!=0) 541223a736eSDavid du Colombier break; 542223a736eSDavid du Colombier /* is it a man reference of the form cp(1)? */ 543223a736eSDavid du Colombier /* X manref start/end cp (1) */ 544223a736eSDavid du Colombier if(nfld==6 && strcmp(fld[2], "manref")==0){ 545223a736eSDavid du Colombier /* was the right macro; is it the right form? */ 546223a736eSDavid du Colombier if(strlen(fld[5])>=3 && 547223a736eSDavid du Colombier fld[5][0]=='(' && fld[5][2]==')' && 548223a736eSDavid du Colombier '0'<=fld[5][1] && fld[5][1]<='9'){ 549223a736eSDavid du Colombier if(strcmp(fld[3], "start") == 0){ 550223a736eSDavid du Colombier /* set anchor attribute and remember string */ 551223a736eSDavid du Colombier attr |= (1<<Anchor); 552223a736eSDavid du Colombier snprint(buf, sizeof buf, 553*0fb05a45SDavid du Colombier "<a href=\"/magic/man2html/%c/%s\">", 554223a736eSDavid du Colombier fld[5][1], fld[4]); 555223a736eSDavid du Colombier nanchors++; 556223a736eSDavid du Colombier anchors = erealloc(anchors, nanchors*sizeof(char*)); 557223a736eSDavid du Colombier anchors[nanchors-1] = estrdup(buf); 558223a736eSDavid du Colombier }else if(strcmp(fld[3], "end") == 0) 559223a736eSDavid du Colombier attr &= ~(1<<Anchor); 560223a736eSDavid du Colombier } 561*0fb05a45SDavid du Colombier }else if(strcmp(fld[2], "manPP") == 0){ 562*0fb05a45SDavid du Colombier didP = 1; 563*0fb05a45SDavid du Colombier emitul(Epp); 564223a736eSDavid du Colombier }else if(nfld<4 || strcmp(fld[2], "manref")!=0){ 565223a736eSDavid du Colombier if(nfld>2 && strcmp(fld[2], "<P>")==0){ /* avoid triggering extra <br> */ 566223a736eSDavid du Colombier didP = 1; 567223a736eSDavid du Colombier /* clear all font attributes before paragraph */ 568223a736eSDavid du Colombier emitul(' ' | (attr & ~(0xFFFF|((1<<Italic)|(1<<Bold)|(1<<CW))))); 569223a736eSDavid du Colombier emitstr("<P>"); 570223a736eSDavid du Colombier /* next emittec char will turn font attributes back on */ 571223a736eSDavid du Colombier }else if(nfld>2 && strcmp(fld[2], "<H4>")==0) 572223a736eSDavid du Colombier attr |= (1<<Heading); 573223a736eSDavid du Colombier else if(nfld>2 && strcmp(fld[2], "</H4>")==0) 574223a736eSDavid du Colombier attr &= ~(1<<Heading); 575223a736eSDavid du Colombier else if(debug) 576223a736eSDavid du Colombier fprint(2, "unknown in-line html %s... at %s:%#d\n", 577223a736eSDavid du Colombier fld[2], filename, cno); 578223a736eSDavid du Colombier } 579223a736eSDavid du Colombier return; 580223a736eSDavid du Colombier } 581223a736eSDavid du Colombier if(debug) 582223a736eSDavid du Colombier fprint(2, "unknown or badly formatted x command %s\n", fld[0]); 583223a736eSDavid du Colombier } 584223a736eSDavid du Colombier 585223a736eSDavid du Colombier int 586223a736eSDavid du Colombier lookup(int c, Htmlchar tab[], int ntab) 587223a736eSDavid du Colombier { 588223a736eSDavid du Colombier int low, high, mid; 589223a736eSDavid du Colombier 590223a736eSDavid du Colombier low = 0; 591223a736eSDavid du Colombier high = ntab - 1; 592223a736eSDavid du Colombier while(low <= high){ 593223a736eSDavid du Colombier mid = (low+high)/2; 594223a736eSDavid du Colombier if(c < tab[mid].value) 595223a736eSDavid du Colombier high = mid - 1; 596223a736eSDavid du Colombier else if(c > tab[mid].value) 597223a736eSDavid du Colombier low = mid + 1; 598223a736eSDavid du Colombier else 599223a736eSDavid du Colombier return mid; 600223a736eSDavid du Colombier } 601223a736eSDavid du Colombier return -1; /* no match */ 602223a736eSDavid du Colombier } 603223a736eSDavid du Colombier 604223a736eSDavid du Colombier void 605223a736eSDavid du Colombier emithtmlchar(int r) 606223a736eSDavid du Colombier { 607223a736eSDavid du Colombier static char buf[10]; 608223a736eSDavid du Colombier int i; 609223a736eSDavid du Colombier 610223a736eSDavid du Colombier i = lookup(r, htmlchars, nelem(htmlchars)); 611223a736eSDavid du Colombier if(i >= 0) 612223a736eSDavid du Colombier emitstr(htmlchars[i].name); 613223a736eSDavid du Colombier else 614223a736eSDavid du Colombier emit(r); 615223a736eSDavid du Colombier } 616223a736eSDavid du Colombier 617223a736eSDavid du Colombier char* 618223a736eSDavid du Colombier troffchar(char *s) 619223a736eSDavid du Colombier { 620223a736eSDavid du Colombier int i; 621223a736eSDavid du Colombier 622223a736eSDavid du Colombier for(i=0; troffchars[i].name!=nil; i++) 623223a736eSDavid du Colombier if(strcmp(s, troffchars[i].name) == 0) 624223a736eSDavid du Colombier return troffchars[i].value; 625223a736eSDavid du Colombier return "??"; 626223a736eSDavid du Colombier } 627223a736eSDavid du Colombier 628223a736eSDavid du Colombier void 629223a736eSDavid du Colombier indent(void) 630223a736eSDavid du Colombier { 631223a736eSDavid du Colombier int nind; 632223a736eSDavid du Colombier 633223a736eSDavid du Colombier didP = 0; 634223a736eSDavid du Colombier if(atnewline){ 635223a736eSDavid du Colombier if(hp != prevlineH){ 636223a736eSDavid du Colombier prevlineH = hp; 637223a736eSDavid du Colombier /* these most peculiar numbers appear in the troff -man output */ 638223a736eSDavid du Colombier nind = ((prevlineH-1*res)+323)/324; 639223a736eSDavid du Colombier attr &= ~((1<<Indent1)|(1<<Indent2)|(1<<Indent3)); 640223a736eSDavid du Colombier if(nind >= 1) 641223a736eSDavid du Colombier attr |= (1<<Indent1); 642223a736eSDavid du Colombier if(nind >= 2) 643223a736eSDavid du Colombier attr |= (1<<Indent2); 644*0fb05a45SDavid du Colombier if(nind >= 3) 645223a736eSDavid du Colombier attr |= (1<<Indent3); 646223a736eSDavid du Colombier } 647223a736eSDavid du Colombier atnewline = 0; 648223a736eSDavid du Colombier } 649223a736eSDavid du Colombier } 650223a736eSDavid du Colombier 651223a736eSDavid du Colombier void 652223a736eSDavid du Colombier process(Biobuf *b, char *name) 653223a736eSDavid du Colombier { 654223a736eSDavid du Colombier int c, r, v, i; 655223a736eSDavid du Colombier char *p; 656223a736eSDavid du Colombier 657223a736eSDavid du Colombier cno = 0; 658223a736eSDavid du Colombier prevlineH = res; 659223a736eSDavid du Colombier filename = name; 660223a736eSDavid du Colombier for(;;){ 661223a736eSDavid du Colombier c = getc(b); 662223a736eSDavid du Colombier switch(c){ 663223a736eSDavid du Colombier case Beof: 664223a736eSDavid du Colombier /* go to ground state */ 665223a736eSDavid du Colombier attr = 0; 666223a736eSDavid du Colombier emit('\n'); 667223a736eSDavid du Colombier return; 668223a736eSDavid du Colombier case '\n': 669223a736eSDavid du Colombier break; 670223a736eSDavid du Colombier case '0': case '1': case '2': case '3': case '4': 671223a736eSDavid du Colombier case '5': case '6': case '7': case '8': case '9': 672223a736eSDavid du Colombier v = c-'0'; 673223a736eSDavid du Colombier c = getc(b); 674223a736eSDavid du Colombier if(c<'0' || '9'<c) 675223a736eSDavid du Colombier sysfatal("illegal character motion at %s:#%d", filename, cno); 676223a736eSDavid du Colombier v = v*10 + (c-'0'); 677223a736eSDavid du Colombier hp += v; 678223a736eSDavid du Colombier /* fall through to character case */ 679223a736eSDavid du Colombier case 'c': 680223a736eSDavid du Colombier indent(); 681223a736eSDavid du Colombier r = getc(b); 682223a736eSDavid du Colombier emithtmlchar(r); 683223a736eSDavid du Colombier break; 684b7b24591SDavid du Colombier case 'D': 685b7b24591SDavid du Colombier /* draw line; ignore */ 686b7b24591SDavid du Colombier do 687b7b24591SDavid du Colombier c = getc(b); 688b7b24591SDavid du Colombier while(c!='\n' && c!= Beof); 689b7b24591SDavid du Colombier break; 690223a736eSDavid du Colombier case 'f': 691223a736eSDavid du Colombier v = setnum(b, "font", 0, Nfont); 692223a736eSDavid du Colombier switchfont(v); 693223a736eSDavid du Colombier break; 694223a736eSDavid du Colombier case 'h': 695223a736eSDavid du Colombier v = setnum(b, "hpos", -20000, 20000); 696223a736eSDavid du Colombier /* generate spaces if motion is large and within a line */ 697223a736eSDavid du Colombier if(!atnewline && v>2*72) 698223a736eSDavid du Colombier for(i=0; i<v; i+=72) 699223a736eSDavid du Colombier emitstr(" "); 700223a736eSDavid du Colombier hp += v; 701223a736eSDavid du Colombier break; 702223a736eSDavid du Colombier case 'n': 703223a736eSDavid du Colombier setnum(b, "n1", -10000, 10000); 704223a736eSDavid du Colombier //Bprint(&bout, " N1=%d", v); 705223a736eSDavid du Colombier getc(b); /* space separates */ 706223a736eSDavid du Colombier setnum(b, "n2", -10000, 10000); 707223a736eSDavid du Colombier atnewline = 1; 708223a736eSDavid du Colombier if(!didP && hp < (Wid-1)*res) /* if line is less than 19" long, probably need a line break */ 709223a736eSDavid du Colombier emitstr("<br>"); 710223a736eSDavid du Colombier emit('\n'); 711223a736eSDavid du Colombier break; 712223a736eSDavid du Colombier case 'p': 713223a736eSDavid du Colombier page = setnum(b, "ps", -10000, 10000); 714223a736eSDavid du Colombier break; 715223a736eSDavid du Colombier case 's': 716223a736eSDavid du Colombier ps = setnum(b, "ps", 1, 1000); 717223a736eSDavid du Colombier break; 718223a736eSDavid du Colombier case 'v': 719223a736eSDavid du Colombier vp += setnum(b, "vpos", -10000, 10000); 720223a736eSDavid du Colombier /* BUG: ignore motion */ 721223a736eSDavid du Colombier break; 722223a736eSDavid du Colombier case 'x': 723223a736eSDavid du Colombier xcmd(b); 724223a736eSDavid du Colombier break; 725223a736eSDavid du Colombier case 'w': 726223a736eSDavid du Colombier emit(' '); 727223a736eSDavid du Colombier break; 728223a736eSDavid du Colombier case 'C': 729223a736eSDavid du Colombier indent(); 730223a736eSDavid du Colombier p = getstr(b); 731223a736eSDavid du Colombier emitstr(troffchar(p)); 732223a736eSDavid du Colombier break; 733223a736eSDavid du Colombier case 'H': 734223a736eSDavid du Colombier hp = setnum(b, "hpos", 0, 20000); 735223a736eSDavid du Colombier //Bprint(&bout, " H=%d ", hp); 736223a736eSDavid du Colombier break; 737223a736eSDavid du Colombier case 'V': 738223a736eSDavid du Colombier vp = setnum(b, "vpos", 0, 10000); 739223a736eSDavid du Colombier break; 740223a736eSDavid du Colombier default: 741223a736eSDavid du Colombier fprint(2, "dhtml: unknown directive %c(0x%.2ux) at %s:#%d\n", c, c, filename, cno); 742223a736eSDavid du Colombier return; 743223a736eSDavid du Colombier } 744223a736eSDavid du Colombier } 745223a736eSDavid du Colombier } 746223a736eSDavid du Colombier 747223a736eSDavid du Colombier HTMLfont* 748223a736eSDavid du Colombier htmlfont(char *name) 749223a736eSDavid du Colombier { 750223a736eSDavid du Colombier int i; 751223a736eSDavid du Colombier 752223a736eSDavid du Colombier for(i=0; htmlfonts[i].name!=nil; i++) 753223a736eSDavid du Colombier if(strcmp(name, htmlfonts[i].name) == 0) 754223a736eSDavid du Colombier return &htmlfonts[i]; 755223a736eSDavid du Colombier return &htmlfonts[0]; 756223a736eSDavid du Colombier } 757223a736eSDavid du Colombier 758223a736eSDavid du Colombier void 759223a736eSDavid du Colombier mountfont(int pos, char *name) 760223a736eSDavid du Colombier { 761223a736eSDavid du Colombier if(debug) 762223a736eSDavid du Colombier fprint(2, "mount font %s on %d\n", name, pos); 763223a736eSDavid du Colombier if(font[pos] != nil){ 764223a736eSDavid du Colombier free(font[pos]->name); 765223a736eSDavid du Colombier free(font[pos]); 766223a736eSDavid du Colombier } 767223a736eSDavid du Colombier font[pos] = emalloc(sizeof(Font)); 768223a736eSDavid du Colombier font[pos]->name = estrdup(name); 769223a736eSDavid du Colombier font[pos]->htmlfont = htmlfont(name); 770223a736eSDavid du Colombier } 771223a736eSDavid du Colombier 772223a736eSDavid du Colombier void 773223a736eSDavid du Colombier switchfont(int pos) 774223a736eSDavid du Colombier { 775223a736eSDavid du Colombier HTMLfont *hf; 776223a736eSDavid du Colombier 777223a736eSDavid du Colombier if(debug) 778223a736eSDavid du Colombier fprint(2, "font change from %d (%s) to %d (%s)\n", ft, font[ft]->name, pos, font[pos]->name); 779223a736eSDavid du Colombier if(pos == ft) 780223a736eSDavid du Colombier return; 781223a736eSDavid du Colombier hf = font[ft]->htmlfont; 782223a736eSDavid du Colombier if(hf->bit != 0) 783223a736eSDavid du Colombier attr &= ~(1<<hf->bit); 784223a736eSDavid du Colombier ft = pos; 785223a736eSDavid du Colombier hf = font[ft]->htmlfont; 786223a736eSDavid du Colombier if(hf->bit != 0) 787223a736eSDavid du Colombier attr |= (1<<hf->bit); 788223a736eSDavid du Colombier } 789