1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 5 enum 6 { 7 SSIZE = 10, 8 9 Maxnh= 8, /* highest NH level */ 10 HH= 4, /* heading level used for SH and NH */ 11 Maxmstack= 10, /* deepest macro/string nesting */ 12 Narg= 20, /* max args to a macro */ 13 Maxsstack= 5, /* deepest nesting of .so's */ 14 Nline= 1024, 15 Maxget= 10, 16 Maxif = 20, 17 18 /* list types */ 19 Lordered = 1, 20 Lunordered, 21 Ldef, 22 Lother, 23 }; 24 25 int quiet; 26 float indent; /* from .in */ 27 Biobuf bout; 28 int isup; 29 int isdown; 30 int debug; 31 32 int nh[Maxnh]; 33 int ifwastrue[Maxif]; 34 35 int list, listnum, example; 36 int hangingau, hangingdt, hanginghead; 37 int indirective, paragraph, sol, titleseen, ignore_nl, weBref; 38 39 typedef struct Goobie Goobie; 40 typedef struct Goobieif Goobieif; 41 struct Goobie 42 { 43 char *name; 44 void (*f)(int, char**); 45 }; 46 47 typedef void F(int, char**); 48 typedef void Fif(char*, char*); 49 50 struct Goobieif 51 { 52 char *name; 53 Fif *f; 54 }; 55 56 /* if, ie */ 57 Fif g_as, g_ds, g_el, g_ie, g_if; 58 Goobieif gtabif[] = { 59 { "as", g_as }, 60 { "ds", g_ds }, 61 { "if", g_if }, 62 { "ie", g_ie }, 63 { "el", g_el }, 64 { nil, nil }, 65 }; 66 67 /* pseudo ops */ 68 F g_notyet, g_ignore, g_hrule, g_startgif; 69 70 /* ms macros */ 71 F g_AU, g_B, g_BI, g_CW, g_I, g_IP, g_LP, g_PP, g_SH, g_NH; 72 F g_P1, g_P2, g_TL, g_R, g_AB, g_AE, g_EQ, g_TS, g_TE, g_FS, g_FE; 73 F g_PY, g_IH, g_MH, g_HO, g_BX, g_QS, g_QE, g_RS, g_RE; 74 75 /* pictures macro */ 76 F g_BP; 77 78 /* real troff */ 79 F g_br, g_ft, g_sp, g_de, g_lf, g_so, g_rm, g_in; 80 F g_nr, g_ig, g_RT, g_BS, g_BE, g_LB, g_ta; 81 82 /* macros to include ML in output */ 83 F g__H, g__T; 84 85 Goobie gtab[] = 86 { 87 { "_T", g__T, }, 88 { "_H", g__H, }, 89 { "1C", g_ignore, }, 90 { "2C", g_ignore, }, 91 { "AB", g_AB, }, 92 { "AE", g_AE, }, 93 { "AI", g_ignore, }, 94 { "AU", g_AU, }, 95 { "B", g_B, }, 96 { "B1", g_hrule, }, 97 { "B2", g_hrule, }, 98 { "BI", g_BI, }, 99 { "BP", g_BP, }, 100 { "BT", g_ignore, }, 101 { "BX", g_BX, }, 102 { "CW", g_CW, }, 103 { "CT", g_ignore, }, 104 { "DA", g_ignore, }, 105 { "DE", g_P2, }, 106 { "DS", g_P1, }, 107 { "EG", g_ignore, }, 108 { "EN", g_ignore, }, 109 { "EQ", g_startgif, }, 110 { "FE", g_FE, }, 111 { "FP", g_ignore, }, 112 { "FS", g_FS, }, 113 { "HO", g_HO, }, 114 { "I", g_I, }, 115 { "IH", g_IH, }, 116 { "IM", g_ignore, }, 117 { "IP", g_IP, }, 118 { "KE", g_ignore, }, 119 { "KF", g_ignore, }, 120 { "KS", g_ignore, }, 121 { "LG", g_ignore, }, 122 { "LP", g_LP, }, 123 { "LT", g_ignore, }, 124 { "MF", g_ignore, }, 125 { "MH", g_MH, }, 126 { "MR", g_ignore, }, 127 { "ND", g_ignore, }, 128 { "NH", g_NH, }, 129 { "NL", g_ignore, }, 130 { "P1", g_P1, }, 131 { "P2", g_P2, }, 132 { "PE", g_ignore, }, 133 { "PF", g_ignore, }, 134 { "PP", g_PP, }, 135 { "PS", g_startgif, }, 136 { "PY", g_PY, }, 137 { "QE", g_QE, }, 138 { "QP", g_QS, }, 139 { "QS", g_QS, }, 140 { "R", g_R, }, 141 { "RE", g_RE, }, 142 { "RP", g_ignore, }, 143 { "RS", g_RS, }, 144 { "SG", g_ignore, }, 145 { "SH", g_SH, }, 146 { "SM", g_ignore, }, 147 { "TA", g_ignore, }, 148 { "TE", g_ignore, }, 149 { "TH", g_TL, }, 150 { "TL", g_TL, }, 151 { "TM", g_ignore, }, 152 { "TR", g_ignore, }, 153 { "TS", g_startgif, }, 154 { "UL", g_I, }, 155 { "UX", g_ignore, }, 156 { "WH", g_ignore, }, 157 { "RT", g_RT, }, 158 159 { "br", g_br, }, 160 { "ti", g_br, }, 161 { "nf", g_P1, }, 162 { "fi", g_P2, }, 163 { "ft", g_ft, }, 164 { "sp", g_sp, }, 165 { "rm", g_rm, }, 166 { "de", g_de, }, 167 { "am", g_de, }, 168 { "lf", g_lf, }, 169 { "so", g_so, }, 170 { "ps", g_ignore }, 171 { "vs", g_ignore }, 172 { "nr", g_nr }, 173 { "in", g_in }, 174 { "ne", g_ignore }, 175 { "ig", g_ig }, 176 { "BS", g_BS }, 177 { "BE", g_BE }, 178 { "LB", g_LB }, 179 { nil, nil }, 180 }; 181 182 typedef struct Entity Entity; 183 struct Entity 184 { 185 char *name; 186 int value; 187 }; 188 189 Entity entity[] = 190 { 191 { "&#SPACE;", L' ', }, 192 { "&#RS;", L'\n', }, 193 { "&#RE;", L'\r', }, 194 { """, L'"', }, 195 { "Æ", L'Æ', }, 196 { "Á", L'Á', }, 197 { "Â", L'Â', }, 198 { "À", L'À', }, 199 { "Å", L'Å', }, 200 { "Ã", L'Ã', }, 201 { "Ä", L'Ä', }, 202 { "Ç", L'Ç', }, 203 { "Ð", L'Ð', }, 204 { "É", L'É', }, 205 { "Ê", L'Ê', }, 206 { "È", L'È', }, 207 { "Ë", L'Ë', }, 208 { "Í", L'Í', }, 209 { "Î", L'Î', }, 210 { "Ì", L'Ì', }, 211 { "Ï", L'Ï', }, 212 { "Ñ", L'Ñ', }, 213 { "Ó", L'Ó', }, 214 { "Ô", L'Ô', }, 215 { "Ò", L'Ò', }, 216 { "Ø", L'Ø', }, 217 { "Õ", L'Õ', }, 218 { "Ö", L'Ö', }, 219 { "Þ", L'Þ', }, 220 { "Ú", L'Ú', }, 221 { "Û", L'Û', }, 222 { "Ù", L'Ù', }, 223 { "Ü", L'Ü', }, 224 { "Ý", L'Ý', }, 225 { "á", L'á', }, 226 { "â", L'â', }, 227 { "æ", L'æ', }, 228 { "à", L'à', }, 229 { "&", L'&', }, 230 { "å", L'å', }, 231 { "ã", L'ã', }, 232 { "ä", L'ä', }, 233 { "ç", L'ç', }, 234 { "é", L'é', }, 235 { "ê", L'ê', }, 236 { "è", L'è', }, 237 { "ð", L'ð', }, 238 { "ë", L'ë', }, 239 { ">", L'>', }, 240 { "í", L'í', }, 241 { "î", L'î', }, 242 { "ì", L'ì', }, 243 { "ï", L'ï', }, 244 { "<", L'<', }, 245 { "ñ", L'ñ', }, 246 { "ó", L'ó', }, 247 { "ô", L'ô', }, 248 { "ò", L'ò', }, 249 { "ø", L'ø', }, 250 { "õ", L'õ', }, 251 { "ö", L'ö', }, 252 { "ß", L'ß', }, 253 { "þ", L'þ', }, 254 { "ú", L'ú', }, 255 { "û", L'û', }, 256 { "ù", L'ù', }, 257 { "ü", L'ü', }, 258 { "ý", L'ý', }, 259 { "ÿ", L'ÿ', }, 260 { "¡", L'¡', }, 261 { "¢", L'¢', }, 262 { "£", L'£', }, 263 { "¤", L'¤', }, 264 { "¥", L'¥', }, 265 { "¦", L'¦', }, 266 { "§", L'§', }, 267 { "¨", L'¨', }, 268 { "©", L'©', }, 269 { "ª", L'ª', }, 270 { "«", L'«', }, 271 { "¬", L'¬', }, 272 { "­", L'', }, 273 { "®", L'®', }, 274 { "¯", L'¯', }, 275 { "°", L'°', }, 276 { "±", L'±', }, 277 { "²", L'²', }, 278 { "³", L'³', }, 279 { "´", L'´', }, 280 { "µ", L'µ', }, 281 { "¶", L'¶', }, 282 { "·", L'·', }, 283 { "¸", L'¸', }, 284 { "¹", L'¹', }, 285 { "º", L'º', }, 286 { "»", L'»', }, 287 { "¼", L'¼', }, 288 { "½", L'½', }, 289 { "¾", L'¾', }, 290 { "¿", L'¿', }, 291 292 { "*", L'•', }, 293 { "¤", L'□', }, 294 { "º", L'◊', }, 295 { "(tm)", L'™', }, 296 297 { "CAP-DELTA", L'Δ', }, 298 { "ALPHA", L'α', }, 299 { "BETA", L'β', }, 300 { "DELTA", L'δ', }, 301 { "EPSILON", L'ε', }, 302 { "THETA", L'θ', }, 303 { "MU", L'μ', }, 304 { "PI", L'π', }, 305 { "TAU", L'τ', }, 306 { "CHI", L'χ', }, 307 308 { "CYRILLIC XYZZY", L'й', }, 309 { "CYRILLIC XYZZY", L'ъ', }, 310 { "CYRILLIC Y", L'ь', }, 311 { "CYRILLIC YA", L'я', }, 312 { "CYRILLIC YA", L'ё', }, 313 { "¿", L'ℱ', }, 314 315 { "<-", L'←', }, 316 { "^", L'↑', }, 317 { "->", L'→', }, 318 { "v", L'↓', }, 319 { "!=", L'≠', }, 320 { "<=", L'≤', }, 321 { nil, 0 }, 322 }; 323 324 typedef struct Troffspec Troffspec; 325 struct Troffspec 326 { 327 char *name; 328 char *value; 329 }; 330 331 Troffspec tspec[] = 332 { 333 { "A*", "Å", }, 334 { "o\"", "ö", }, 335 { "ff", "ff", }, 336 { "fi", "fi", }, 337 { "fl", "fl", }, 338 { "Fi", "ffi", }, 339 { "ru", "_", }, 340 { "em", "­", }, 341 { "14", "¼", }, 342 { "12", "½", }, 343 { "co", "©", }, 344 { "de", "°", }, 345 { "dg", "¡", }, 346 { "fm", "´", }, 347 { "rg", "®", }, 348 { "bu", "*", }, 349 { "sq", "¤", }, 350 { "hy", "-", }, 351 { "pl", "+", }, 352 { "mi", "-", }, 353 { "mu", "×", }, 354 { "di", "÷", }, 355 { "eq", "=", }, 356 { "==", "==", }, 357 { ">=", ">=", }, 358 { "<=", "<=", }, 359 { "!=", "!=", }, 360 { "+-", "±", }, 361 { "no", "¬", }, 362 { "sl", "/", }, 363 { "ap", "&", }, 364 { "~=", "~=", }, 365 { "pt", "oc", }, 366 { "gr", "GRAD", }, 367 { "->", "->", }, 368 { "<-", "<-", }, 369 { "ua", "^", }, 370 { "da", "v", }, 371 { "is", "Integral", }, 372 { "pd", "DIV", }, 373 { "if", "oo", }, 374 { "sr", "-/", }, 375 { "sb", "(~", }, 376 { "sp", "~)", }, 377 { "cu", "U", }, 378 { "ca", "(^)", }, 379 { "ib", "(=", }, 380 { "ip", "=)", }, 381 { "mo", "C", }, 382 { "es", "Ø", }, 383 { "aa", "´", }, 384 { "ga", "`", }, 385 { "ci", "O", }, 386 { "L1", "DEATHSTAR", }, 387 { "sc", "§", }, 388 { "dd", "++", }, 389 { "lh", "<=", }, 390 { "rh", "=>", }, 391 { "lt", "(", }, 392 { "rt", ")", }, 393 { "lc", "|", }, 394 { "rc", "|", }, 395 { "lb", "(", }, 396 { "rb", ")", }, 397 { "lf", "|", }, 398 { "rf", "|", }, 399 { "lk", "|", }, 400 { "rk", "|", }, 401 { "bv", "|", }, 402 { "ts", "s", }, 403 { "br", "|", }, 404 { "or", "|", }, 405 { "ul", "_", }, 406 { "rn", " ", }, 407 { "**", "*", }, 408 { nil, nil, }, 409 }; 410 411 typedef struct Font Font; 412 struct Font 413 { 414 char *start; 415 char *end; 416 }; 417 Font bfont = { "<B>", "</B>" }; 418 Font ifont = { "<I>", "</I>" }; 419 Font bifont = { "<B><I>", "</I></B>" }; 420 Font cwfont = { "<TT>", "</TT>" }; 421 Font *prevfont; 422 Font *curfont; 423 424 typedef struct String String; 425 struct String 426 { 427 String *next; 428 char *name; 429 char *val; 430 }; 431 String *numregs, *strings; 432 char *strstack[Maxmstack]; 433 char *mustfree[Maxmstack]; 434 int strsp = -1; 435 int elsetop = -1; 436 437 typedef struct Mstack Mstack; 438 struct Mstack 439 { 440 char *ptr; 441 char *argv[Narg+1]; 442 }; 443 String *macros; 444 Mstack mstack[Maxmstack]; 445 int msp = -1; 446 447 typedef struct Srcstack Srcstack; 448 struct Srcstack 449 { 450 char filename[256]; 451 int fd; 452 int lno; 453 int rlno; 454 Biobuf in; 455 }; 456 Srcstack sstack[Maxsstack]; 457 Srcstack *ssp = &sstack[-1]; 458 459 char token[128]; 460 461 void closel(void); 462 void closefont(void); 463 464 void* 465 emalloc(uint n) 466 { 467 void *p; 468 469 p = mallocz(n, 1); 470 if(p == nil){ 471 fprint(2, "ms2html: malloc failed: %r\n"); 472 exits("malloc"); 473 } 474 return p; 475 } 476 477 478 /* define a string variable */ 479 void 480 dsnr(char *name, char *val, String **l) 481 { 482 String *s; 483 484 for(s = *l; s != nil; s = *l){ 485 if(strcmp(s->name, name) == 0) 486 break; 487 l = &s->next; 488 } 489 if(s == nil){ 490 s = emalloc(sizeof(String)); 491 *l = s; 492 s->name = strdup(name); 493 } else 494 free(s->val); 495 s->val = strdup(val); 496 } 497 498 void 499 ds(char *name, char *val) 500 { 501 dsnr(name, val, &strings); 502 } 503 504 /* look up a defined string */ 505 char* 506 getds(char *name) 507 { 508 String *s; 509 510 for(s = strings; s != nil; s = s->next) 511 if(strcmp(name, s->name) == 0) 512 break; 513 if(s != nil) 514 return s->val; 515 return ""; 516 } 517 518 char * 519 getnr(char *name) 520 { 521 String *s; 522 523 for(s = numregs; s != nil; s = s->next) 524 if(strcmp(name, s->name) == 0) 525 break; 526 if(s != nil) 527 return s->val; 528 return "0"; 529 } 530 531 void 532 pushstr(char *p) 533 { 534 if(p == nil) 535 return; 536 if(strsp >= Maxmstack - 1) 537 return; 538 strstack[++strsp] = p; 539 } 540 541 542 /* lookup a defined macro */ 543 char* 544 getmacro(char *name) 545 { 546 String *s; 547 548 for(s = macros; s != nil; s = s->next) 549 if(strcmp(name, s->name) == 0) 550 return s->val; 551 return nil; 552 } 553 554 enum 555 { 556 Dstring, 557 Macro, 558 Input, 559 }; 560 int lastsrc; 561 562 void 563 pushsrc(char *name) 564 { 565 Dir *d; 566 int fd; 567 568 if(ssp == &sstack[Maxsstack-1]){ 569 fprint(2, "ms2html: .so's too deep\n"); 570 return; 571 } 572 d = nil; 573 if(name == nil){ 574 d = dirfstat(0); 575 if(d == nil){ 576 fprint(2, "ms2html: can't stat %s: %r\n", name); 577 return; 578 } 579 name = d->name; 580 fd = 0; 581 } else { 582 fd = open(name, OREAD); 583 if(fd < 0){ 584 fprint(2, "ms2html: can't open %s: %r\n", name); 585 return; 586 } 587 } 588 ssp++; 589 ssp->fd = fd; 590 Binit(&ssp->in, fd, OREAD); 591 snprint(ssp->filename, sizeof(ssp->filename), "%s", name); 592 ssp->lno = ssp->rlno = 1; 593 free(d); 594 } 595 596 /* get next logical byte. from stdin or a defined string */ 597 int 598 getrune(void) 599 { 600 int i; 601 Rune r; 602 int c; 603 Mstack *m; 604 605 while(strsp >= 0){ 606 i = chartorune(&r, strstack[strsp]); 607 if(r != 0){ 608 strstack[strsp] += i; 609 lastsrc = Dstring; 610 return r; 611 } 612 if (mustfree[strsp]) { 613 free(mustfree[strsp]); 614 mustfree[strsp] = nil; 615 } 616 strsp--; 617 } 618 while(msp >= 0){ 619 m = &mstack[msp]; 620 i = chartorune(&r, m->ptr); 621 if(r != 0){ 622 m->ptr += i; 623 lastsrc = Macro; 624 return r; 625 } 626 for(i = 0; m->argv[i] != nil; i++) 627 free(m->argv[i]); 628 msp--; 629 } 630 631 lastsrc = Input; 632 do { 633 if(ssp < sstack) 634 return -1; 635 c = Bgetrune(&ssp->in); 636 if(c >= 0){ 637 r = c; 638 break; 639 } 640 close(ssp->fd); 641 ssp--; 642 } while(r < 0); 643 644 return r; 645 } 646 647 void 648 ungetrune(void) 649 { 650 switch(lastsrc){ 651 case Dstring: 652 if(strsp >= 0) 653 strstack[strsp]--; 654 break; 655 case Macro: 656 if(msp >= 0) 657 mstack[msp].ptr--; 658 break; 659 case Input: 660 if(ssp >= sstack) 661 Bungetrune(&ssp->in); 662 break; 663 } 664 } 665 666 int vert; 667 668 char* 669 changefont(Font *f) 670 { 671 token[0] = 0; 672 if(curfont != nil) 673 strcpy(token, curfont->end); 674 if(f != nil) 675 strcat(token, f->start); 676 prevfont = curfont; 677 curfont = f; 678 return token; 679 } 680 681 /* get next logical character. expand it with escapes */ 682 char* 683 getnext(void) 684 { 685 int r; 686 Entity *e; 687 Troffspec *t; 688 Rune R; 689 char str[4]; 690 691 r = getrune(); 692 if(r < 0) 693 return nil; 694 if(r > 128 || r == '<' || r == '>'){ 695 for(e = entity; e->name; e++) 696 if(e->value == r) 697 return e->name; 698 return "¿"; 699 } 700 701 switch(r){ 702 case '\\': 703 r = getrune(); 704 if(r < 0) 705 return nil; 706 switch(r){ 707 case ' ': 708 return " "; 709 710 /* chars to ignore */ 711 case '&': 712 case '|': 713 case '%': 714 return ""; 715 716 /* small space in troff, nothing in nroff */ 717 case '^': 718 return getnext(); 719 720 /* ignore arg */ 721 case 'k': 722 getrune(); 723 return getnext(); 724 725 /* comment */ 726 case '"': 727 while(getrune() != '\n') 728 ; 729 return "\n"; 730 /* ignore line */ 731 case '!': 732 while(getrune() != '\n') 733 ; 734 ungetrune(); 735 return getnext(); 736 737 /* defined strings */ 738 case '*': 739 r = getrune(); 740 if(r == '('){ 741 str[0] = getrune(); 742 str[1] = getrune(); 743 str[2] = 0; 744 } else { 745 str[0] = r; 746 str[1] = 0; 747 } 748 pushstr(getds(str)); 749 return getnext(); 750 751 /* macro args */ 752 case '$': 753 r = getrune(); 754 if(r < '1' || r > '9'){ 755 token[0] = '\\'; 756 token[1] = '$'; 757 token[2] = r; 758 token[3] = 0; 759 return token; 760 } 761 r -= '0'; 762 if(msp >= 0) 763 pushstr(mstack[msp].argv[r]); 764 return getnext(); 765 766 /* special chars */ 767 case '(': 768 token[0] = getrune(); 769 token[1] = getrune(); 770 token[2] = 0; 771 for(t = tspec; t->name; t++) 772 if(strcmp(token, t->name) == 0) 773 return t->value; 774 return "¿"; 775 776 /* ignore immediately following newline */ 777 case 'c': 778 r = getrune(); 779 if (r == '\n') { 780 sol = ignore_nl = 1; 781 if (indirective) 782 break; 783 } 784 else 785 ungetrune(); 786 return getnext(); 787 788 /* escape backslash */ 789 case 'e': 790 return "\\"; 791 break; 792 793 /* font change */ 794 case 'f': 795 r = getrune(); 796 switch(r){ 797 case '(': 798 str[0] = getrune(); 799 str[1] = getrune(); 800 str[2] = 0; 801 token[0] = 0; 802 if(strcmp("BI", str) == 0) 803 return changefont(&bifont); 804 else if(strcmp("CW", str) == 0) 805 return changefont(&cwfont); 806 else 807 return changefont(nil); 808 case '3': 809 case 'B': 810 return changefont(&bfont); 811 case '2': 812 case 'I': 813 return changefont(&ifont); 814 case '4': 815 return changefont(&bifont); 816 case '5': 817 return changefont(&cwfont); 818 case 'P': 819 return changefont(prevfont); 820 case 'R': 821 default: 822 return changefont(nil); 823 } 824 825 /* number register */ 826 case 'n': 827 r = getrune(); 828 if (r == '(') /*)*/ { 829 r = getrune(); 830 if (r < 0) 831 return nil; 832 str[0] = r; 833 r = getrune(); 834 if (r < 0) 835 return nil; 836 str[1] = r; 837 str[2] = 0; 838 } 839 else { 840 str[0] = r; 841 str[1] = 0; 842 } 843 pushstr(getnr(str)); 844 return getnext(); 845 846 /* font size */ 847 case 's': 848 getnext(); /* ignore size change */ 849 return getnext(); 850 851 /* vertical movement */ 852 case 'v': 853 r = getrune(); 854 if(r != '\''){ 855 ungetrune(); 856 return getnext(); 857 } 858 r = getrune(); 859 if(r != '-') 860 vert--; 861 else 862 vert++; 863 while(r != '\'' && r != '\n') 864 r = getrune(); 865 if(r != '\'') 866 ungetrune(); 867 868 if(vert > 0) 869 return "^"; 870 return getnext(); 871 872 873 /* horizontal line */ 874 case 'l': 875 r = getrune(); 876 if(r != '\''){ 877 ungetrune(); 878 return "<HR>"; 879 } 880 while(getrune() != '\'') 881 ; 882 return "<HR>"; 883 884 /* character height and slant */ 885 case 'S': 886 case 'H': 887 r = getrune(); 888 if(r != '\''){ 889 ungetrune(); 890 return "<HR>"; 891 } 892 while(getrune() != '\'') 893 ; 894 return getnext(); 895 896 /* digit-width space */ 897 case '0': 898 return " "; 899 900 /*for .if, .ie, .el */ 901 case '{': 902 return "\\{"; /*}*/ 903 case '}': 904 return ""; 905 /* up and down */ 906 case 'u': 907 if (isdown) { 908 isdown = 0; 909 return "</sub>"; 910 } 911 isup = 1; 912 return "<sup>"; 913 case 'd': 914 if (isup) { 915 isup = 0; 916 return "</sup>"; 917 } 918 isdown = 1; 919 return "<sub>"; 920 } 921 break; 922 case '&': 923 if(msp >= 0 || strsp >= 0) 924 return "&"; 925 return "&"; 926 case '<': 927 if(msp >= 0 || strsp >= 0) 928 return "<"; 929 return "<"; 930 case '>': 931 if(msp >= 0 || strsp >= 0) 932 return ">"; 933 return ">"; 934 } 935 if (r < Runeself) { 936 token[0] = r; 937 token[1] = 0; 938 } 939 else { 940 R = r; 941 token[runetochar(token,&R)] = 0; 942 } 943 return token; 944 } 945 946 char* 947 copyline(char *p, char *e, int arg0) 948 { 949 int c; 950 Rune r; 951 char *p1; 952 953 while((c = getrune()) == ' ' || c == '\t') 954 ; 955 for(indirective = 1; p < e; c = getrune()) { 956 if (c < 0) 957 goto done; 958 switch(c) { 959 case '\\': 960 break; 961 case '\n': 962 if (arg0) 963 ungetrune(); 964 goto done; 965 case ' ': 966 case '\t': 967 if (arg0) 968 goto done; 969 default: 970 r = c; 971 p += runetochar(p,&r); 972 continue; 973 } 974 ungetrune(); 975 p1 = getnext(); 976 if (p1 == nil) 977 goto done; 978 if (*p1 == '\n') { 979 if (arg0) 980 ungetrune(); 981 break; 982 } 983 while((*p = *p1++) && p < e) 984 p++; 985 } 986 done: 987 indirective = 0; 988 *p++ = 0; 989 return p; 990 } 991 992 char* 993 copyarg(char *p, char *e, int *nullarg) 994 { 995 int c, quoted; 996 Rune r; 997 char *p1; 998 999 *nullarg = 0; 1000 quoted = 0; 1001 do{ 1002 c = getrune(); 1003 } while(c == ' ' || c == '\t'); 1004 1005 if(c == '"'){ 1006 quoted = 1; 1007 *nullarg = 1; 1008 c = getrune(); 1009 } 1010 1011 if(c == '\n') 1012 goto done; 1013 1014 for(; p < e; c = getrune()) { 1015 if (c < 0) 1016 break; 1017 switch(c) { 1018 case '\\': 1019 break; 1020 case '\n': 1021 ungetrune(); 1022 goto done; 1023 case ' ': 1024 case '\t': 1025 if(!quoted) 1026 goto done; 1027 r = c; 1028 p += runetochar(p,&r); 1029 continue; 1030 case '"': 1031 if(quoted) 1032 goto done; 1033 r = c; 1034 p += runetochar(p,&r); 1035 continue; 1036 default: 1037 r = c; 1038 p += runetochar(p,&r); 1039 continue; 1040 } 1041 ungetrune(); 1042 p1 = getnext(); 1043 if(p1 == nil) 1044 break; 1045 if(*p1 == '\n') 1046 break; 1047 while((*p = *p1++) && p < e) 1048 p++; 1049 } 1050 done: 1051 *p++ = 0; 1052 return p; 1053 1054 } 1055 1056 int 1057 parseargs(char *p, char *e, char **argv) 1058 { 1059 int argc; 1060 char *np; 1061 int nullarg; 1062 1063 indirective = 1; 1064 *p++ = 0; 1065 for(argc = 1; argc < Narg; argc++){ 1066 np = copyarg(p, e, &nullarg); 1067 if(nullarg==0 && np == p+1) 1068 break; 1069 argv[argc] = p; 1070 p = np; 1071 } 1072 argv[argc] = nil; 1073 indirective = 0; 1074 1075 1076 return argc; 1077 } 1078 1079 void 1080 dodirective(void) 1081 { 1082 char *p, *e; 1083 Goobie *g; 1084 Goobieif *gif; 1085 char line[Nline], *line1; 1086 int i, argc; 1087 char *argv[Narg]; 1088 Mstack *m; 1089 1090 /* read line, translate special bytes */ 1091 e = line + sizeof(line) - UTFmax - 1; 1092 line1 = copyline(line, e, 1); 1093 if (!line[0]) 1094 return; 1095 argv[0] = line; 1096 1097 /* first look through user defined macros */ 1098 p = getmacro(argv[0]); 1099 if(p != nil){ 1100 if(msp == Maxmstack-1){ 1101 fprint(2, "ms2html: macro stack overflow\n"); 1102 return; 1103 } 1104 argc = parseargs(line1, e, argv); 1105 m = &mstack[++msp]; 1106 m->ptr = p; 1107 memset(m->argv, 0, sizeof(m->argv)); 1108 for(i = 0; i < argc; i++) 1109 m->argv[i] = strdup(argv[i]); 1110 return; 1111 } 1112 1113 /* check for .if or .ie */ 1114 for(gif = gtabif; gif->name; gif++) 1115 if(strcmp(gif->name, argv[0]) == 0){ 1116 (*gif->f)(line1, e); 1117 return; 1118 } 1119 1120 argc = parseargs(line1, e, argv); 1121 1122 /* try standard ms macros */ 1123 for(g = gtab; g->name; g++) 1124 if(strcmp(g->name, argv[0]) == 0){ 1125 (*g->f)(argc, argv); 1126 return; 1127 } 1128 1129 if(debug) 1130 fprint(2, "stdin %d(%s:%d): unknown directive %s\n", 1131 ssp->lno, ssp->filename, ssp->rlno, line); 1132 } 1133 1134 void 1135 printarg(char *a) 1136 { 1137 char *e, *p; 1138 1139 e = a + strlen(a); 1140 pushstr(a); 1141 while(strsp >= 0 && strstack[strsp] >= a && strstack[strsp] < e){ 1142 p = getnext(); 1143 if(p == nil) 1144 return; 1145 Bprint(&bout, "%s", p); 1146 } 1147 } 1148 1149 void 1150 printargs(int argc, char **argv) 1151 { 1152 argc--; 1153 argv++; 1154 while(--argc > 0){ 1155 printarg(*argv++); 1156 Bprint(&bout, " "); 1157 } 1158 if(argc == 0) 1159 printarg(*argv); 1160 } 1161 1162 void 1163 dohangingdt(void) 1164 { 1165 switch(hangingdt){ 1166 case 3: 1167 hangingdt--; 1168 break; 1169 case 2: 1170 Bprint(&bout, "<dd>"); 1171 hangingdt = 0; 1172 break; 1173 } 1174 1175 } 1176 1177 void 1178 dohangingau(void) 1179 { 1180 if(hangingau == 0) 1181 return; 1182 Bprint(&bout, "</I></DL>\n"); 1183 hangingau = 0; 1184 } 1185 1186 void 1187 dohanginghead(void) 1188 { 1189 if(hanginghead == 0) 1190 return; 1191 Bprint(&bout, "</H%d>\n", hanginghead); 1192 hanginghead = 0; 1193 } 1194 1195 /* 1196 * convert a man page to html and output 1197 */ 1198 void 1199 doconvert(void) 1200 { 1201 char c, *p; 1202 Tm *t; 1203 1204 pushsrc(nil); 1205 1206 sol = 1; 1207 Bprint(&bout, "<html>\n"); 1208 Bflush(&bout); 1209 for(;;){ 1210 p = getnext(); 1211 if(p == nil) 1212 break; 1213 c = *p; 1214 if(c == '.' && sol){ 1215 dodirective(); 1216 dohangingdt(); 1217 ssp->lno++; 1218 ssp->rlno++; 1219 sol = 1; 1220 } else if(c == '\n'){ 1221 if (ignore_nl) 1222 ignore_nl = 0; 1223 else { 1224 if(hangingau) 1225 Bprint(&bout, "<br>\n"); 1226 else 1227 Bprint(&bout, "%s", p); 1228 dohangingdt(); 1229 } 1230 ssp->lno++; 1231 ssp->rlno++; 1232 sol = 1; 1233 } else{ 1234 Bprint(&bout, "%s", p); 1235 ignore_nl = sol = 0; 1236 } 1237 } 1238 dohanginghead(); 1239 dohangingdt(); 1240 closel(); 1241 if(curfont) 1242 Bprint(&bout, "%s", curfont->end); 1243 Bprint(&bout, "<br> <br>\n"); 1244 Bprint(&bout, "<A href=http://www.lucent.com/copyright.html>\n"); 1245 t = localtime(time(nil)); 1246 Bprint(&bout, "Copyright</A> © %d Lucent Technologies Inc. All rights reserved.\n", 1247 t->year+1900); 1248 Bprint(&bout, "</body></html>\n"); 1249 } 1250 1251 void 1252 main(int argc, char **argv) 1253 { 1254 quiet = 1; 1255 if(argc > 1) 1256 if(strcmp(argv[1], "-v") == 0) 1257 quiet = 0; 1258 1259 Binit(&bout, 1, OWRITE); 1260 1261 ds("R", "®"); 1262 1263 doconvert(); 1264 exits(nil); 1265 } 1266 1267 void 1268 g_notyet(int, char **argv) 1269 { 1270 fprint(2, "ms2html: .%s not yet supported\n", argv[0]); 1271 } 1272 1273 void 1274 g_ignore(int, char **argv) 1275 { 1276 if(quiet) 1277 return; 1278 fprint(2, "ms2html: line %d: ignoring .%s\n", ssp->lno, argv[0]); 1279 } 1280 1281 void 1282 g_PP(int, char**) 1283 { 1284 dohanginghead(); 1285 closel(); 1286 closefont(); 1287 Bprint(&bout, "<P>\n"); 1288 paragraph = 1; 1289 } 1290 1291 void 1292 g_LP(int, char**) 1293 { 1294 dohanginghead(); 1295 closel(); 1296 closefont(); 1297 Bprint(&bout, "<br> <br>\n"); 1298 } 1299 1300 /* close a list */ 1301 void 1302 closel(void) 1303 { 1304 g_P2(1, nil); 1305 dohangingau(); 1306 if(paragraph){ 1307 Bprint(&bout, "</P>\n"); 1308 paragraph = 0; 1309 } 1310 switch(list){ 1311 case Lordered: 1312 Bprint(&bout, "</ol>\n"); 1313 break; 1314 case Lunordered: 1315 Bprint(&bout, "</ul>\n"); 1316 break; 1317 case Lother: 1318 case Ldef: 1319 Bprint(&bout, "</dl>\n"); 1320 break; 1321 } 1322 list = 0; 1323 1324 } 1325 1326 1327 void 1328 g_IP(int argc, char **argv) 1329 { 1330 switch(list){ 1331 default: 1332 closel(); 1333 if(argc > 1){ 1334 if(strcmp(argv[1], "1") == 0){ 1335 list = Lordered; 1336 listnum = 1; 1337 Bprint(&bout, "<OL>\n"); 1338 } else if(strcmp(argv[1], "\\(bu") == 0){ 1339 list = Lunordered; 1340 Bprint(&bout, "<UL>\n"); 1341 } else { 1342 list = Lother; 1343 Bprint(&bout, "<DL COMPACT>\n"); 1344 } 1345 } else { 1346 list = Lother; 1347 Bprint(&bout, "<DL>\n"); 1348 } 1349 break; 1350 case Lother: 1351 case Lordered: 1352 case Lunordered: 1353 break; 1354 } 1355 1356 switch(list){ 1357 case Lother: 1358 Bprint(&bout, "<DT>"); 1359 if(argc > 1) 1360 printarg(argv[1]); 1361 else 1362 Bprint(&bout, "<DT> "); 1363 Bprint(&bout, "<DD>\n"); 1364 break; 1365 case Lordered: 1366 case Lunordered: 1367 Bprint(&bout, "<LI>\n"); 1368 break; 1369 } 1370 } 1371 1372 /* 1373 * .5i is one <DL><DT><DD> 1374 */ 1375 void 1376 g_in(int argc, char **argv) 1377 { 1378 float f; 1379 int delta, x; 1380 char *p; 1381 1382 f = indent/0.5; 1383 delta = f; 1384 if(argc <= 1){ 1385 indent = 0.0; 1386 } else { 1387 f = strtod(argv[1], &p); 1388 switch(*p){ 1389 case 'i': 1390 break; 1391 case 'c': 1392 f = f / 2.54; 1393 break; 1394 case 'P': 1395 f = f / 6; 1396 break; 1397 default: 1398 case 'u': 1399 case 'm': 1400 f = f * (12 / 72); 1401 break; 1402 case 'n': 1403 f = f * (6 / 72); 1404 break; 1405 case 'p': 1406 f = f / 72.0; 1407 break; 1408 } 1409 switch(argv[1][0]){ 1410 case '+': 1411 case '-': 1412 indent += f; 1413 break; 1414 default: 1415 indent = f; 1416 break; 1417 } 1418 } 1419 if(indent < 0.0) 1420 indent = 0.0; 1421 f = (indent/0.5); 1422 x = f; 1423 delta = x - delta; 1424 while(delta < 0){ 1425 Bprint(&bout, "</DL>\n"); 1426 delta++; 1427 } 1428 while(delta > 0){ 1429 Bprint(&bout, "<DL><DT><DD>\n"); 1430 delta--; 1431 } 1432 } 1433 1434 void 1435 g_HP(int, char**) 1436 { 1437 switch(list){ 1438 default: 1439 closel(); 1440 list = Ldef; 1441 hangingdt = 1; 1442 Bprint(&bout, "<DL><DT>\n"); 1443 break; 1444 case Ldef: 1445 if(hangingdt) 1446 Bprint(&bout, "<DD>"); 1447 Bprint(&bout, "<DT>"); 1448 hangingdt = 1; 1449 break; 1450 } 1451 } 1452 1453 void 1454 g_SH(int, char**) 1455 { 1456 dohanginghead(); 1457 closel(); 1458 closefont(); 1459 Bprint(&bout, "<H%d>", HH); 1460 hanginghead = HH; 1461 } 1462 1463 void 1464 g_NH(int argc, char **argv) 1465 { 1466 int i, level; 1467 1468 closel(); 1469 closefont(); 1470 1471 if(argc == 1) 1472 level = 0; 1473 else { 1474 level = atoi(argv[1])-1; 1475 if(level < 0 || level >= Maxnh) 1476 level = Maxnh - 1; 1477 } 1478 nh[level]++; 1479 1480 Bprint(&bout, "<H%d>", HH); 1481 hanginghead = HH; 1482 1483 Bprint(&bout, "%d", nh[0]); 1484 for(i = 1; i <= level; i++) 1485 Bprint(&bout, ".%d", nh[i]); 1486 Bprint(&bout, " "); 1487 1488 for(i = level+1; i < Maxnh; i++) 1489 nh[i] = 0; 1490 } 1491 1492 void 1493 g_TL(int, char**) 1494 { 1495 char *p, *np; 1496 char name[128]; 1497 1498 closefont(); 1499 1500 if(!titleseen){ 1501 /* get base part of filename */ 1502 p = strrchr(ssp->filename, '/'); 1503 if(p == nil) 1504 p = ssp->filename; 1505 else 1506 p++; 1507 strncpy(name, p, sizeof(name)); 1508 name[sizeof(name)-1] = 0; 1509 1510 /* dump any extensions */ 1511 np = strchr(name, '.'); 1512 if(np) 1513 *np = 0; 1514 1515 Bprint(&bout, "<title>\n"); 1516 Bprint(&bout, "%s\n", p); 1517 Bprint(&bout, "</title>\n"); 1518 Bprint(&bout, "<body BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#330088\" ALINK=\"#FF0044\">\n"); 1519 titleseen = 1; 1520 } 1521 1522 Bprint(&bout, "<H%d>", 1); 1523 hanginghead = 1; 1524 } 1525 1526 void 1527 g_AU(int, char**) 1528 { 1529 closel(); 1530 dohanginghead(); 1531 Bprint(&bout, "<DL><DD><I>"); 1532 hangingau = 1; 1533 } 1534 1535 void 1536 setfont(Font *f) 1537 { 1538 if(curfont != nil) 1539 Bprint(&bout, "%s", curfont->end); 1540 prevfont = curfont; 1541 if(f != nil) 1542 Bprint(&bout, "%s", f->start); 1543 curfont = f; 1544 } 1545 1546 /* 1547 * for 3 args print arg3 \fxarg1\fP arg2 1548 * for 2 args print arg1 \fxarg2\fP 1549 * for 1 args print \fxarg1\fP 1550 */ 1551 void 1552 font(Font *f, int argc, char **argv) 1553 { 1554 Font *prev; 1555 1556 if(argc == 1){ 1557 setfont(nil); 1558 return; 1559 } 1560 if(argc > 3) 1561 printarg(argv[3]); 1562 prev = prevfont; 1563 setfont(f); 1564 printarg(argv[1]); 1565 setfont(prevfont); 1566 prevfont = prev; 1567 if(argc > 2) 1568 printarg(argv[2]); 1569 Bprint(&bout, "\n"); 1570 } 1571 1572 void 1573 closefont(void) 1574 { 1575 if(curfont != nil) 1576 Bprint(&bout, "%s", curfont->end); 1577 curfont = nil; 1578 prevfont = nil; 1579 } 1580 1581 void 1582 g_B(int argc, char **argv) 1583 { 1584 font(&bfont, argc, argv); 1585 } 1586 1587 void 1588 g_R(int argc, char **argv) 1589 { 1590 font(nil, argc, argv); 1591 } 1592 1593 void 1594 g_BI(int argc, char **argv) 1595 { 1596 font(&bifont, argc, argv); 1597 } 1598 1599 void 1600 g_CW(int argc, char **argv) 1601 { 1602 font(&cwfont, argc, argv); 1603 } 1604 1605 char* 1606 lower(char *p) 1607 { 1608 char *x; 1609 1610 for(x = p; *x; x++) 1611 if(*x >= 'A' && *x <= 'Z') 1612 *x -= 'A' - 'a'; 1613 return p; 1614 } 1615 1616 void 1617 g_I(int argc, char **argv) 1618 { 1619 int anchor; 1620 char *p; 1621 1622 anchor = 0; 1623 if(argc > 2){ 1624 p = argv[2]; 1625 if(p[0] == '(') 1626 if(p[1] >= '0' && p[1] <= '9') 1627 if(p[2] == ')'){ 1628 anchor = 1; 1629 Bprint(&bout, "<A href=\"/magic/man2html/%c/%s\">", 1630 p[1], lower(argv[1])); 1631 } 1632 } 1633 font(&ifont, argc, argv); 1634 if(anchor) 1635 Bprint(&bout, "</A>"); 1636 } 1637 1638 void 1639 g_br(int, char**) 1640 { 1641 if(hangingdt){ 1642 Bprint(&bout, "<dd>"); 1643 hangingdt = 0; 1644 }else 1645 Bprint(&bout, "<br>\n"); 1646 } 1647 1648 void 1649 g_P1(int, char**) 1650 { 1651 if(example == 0){ 1652 example = 1; 1653 Bprint(&bout, "<DL><DT><DD><TT><PRE>\n"); 1654 } 1655 } 1656 1657 void 1658 g_P2(int, char**) 1659 { 1660 if(example){ 1661 example = 0; 1662 Bprint(&bout, "</PRE></TT></DL>\n"); 1663 } 1664 } 1665 1666 void 1667 g_SM(int, char **argv) 1668 { 1669 Bprint(&bout, "%s", argv[1]); 1670 } 1671 1672 void 1673 g_ft(int argc, char **argv) 1674 { 1675 if(argc < 2){ 1676 setfont(nil); 1677 return; 1678 } 1679 1680 switch(argv[1][0]){ 1681 case '3': 1682 case 'B': 1683 setfont(&bfont); 1684 break; 1685 case '2': 1686 case 'I': 1687 setfont(&ifont); 1688 break; 1689 case '4': 1690 setfont(&bifont); 1691 break; 1692 case '5': 1693 setfont(&cwfont); 1694 break; 1695 case 'P': 1696 setfont(prevfont); 1697 break; 1698 case 'R': 1699 default: 1700 setfont(nil); 1701 break; 1702 } 1703 } 1704 1705 void 1706 g_sp(int argc, char **argv) 1707 { 1708 int n; 1709 1710 n = 1; 1711 if(argc > 1){ 1712 n = atoi(argv[1]); 1713 if(n < 1) 1714 n = 1; 1715 if(argv[1][strlen(argv[1])-1] == 'i') 1716 n *= 4; 1717 } 1718 if(n > 5){ 1719 Bprint(&bout, "<br> <br>\n"); 1720 Bprint(&bout, "<HR>\n"); 1721 Bprint(&bout, "<br> <br>\n"); 1722 } else 1723 for(; n > 0; n--) 1724 Bprint(&bout, "<br> <br>\n"); 1725 } 1726 1727 void 1728 rm_loop(char *name, String **l) 1729 { 1730 String *s; 1731 for(s = *l; s != nil; s = *l){ 1732 if(strcmp(name, s->name) == 0){ 1733 *l = s->next; 1734 free(s->name); 1735 free(s->val); 1736 free(s); 1737 break; 1738 } 1739 l = &s->next; 1740 } 1741 } 1742 1743 void 1744 g_rm(int argc, char **argv) 1745 { 1746 Goobie *g; 1747 char *name; 1748 int i; 1749 1750 for(i = 1; i < argc; i++) { 1751 name = argv[i]; 1752 rm_loop(name, &strings); 1753 rm_loop(name, ¯os); 1754 for(g = gtab; g->name; g++) 1755 if (strcmp(g->name, name) == 0) { 1756 g->f = g_ignore; 1757 break; 1758 } 1759 } 1760 } 1761 1762 void 1763 g_AB(int, char**) 1764 { 1765 closel(); 1766 Bprint(&bout, "<DL><DD><H4>ABSTRACT</H4>\n"); 1767 } 1768 1769 void 1770 g_AE(int, char**) 1771 { 1772 Bprint(&bout, "</DL>\n"); 1773 } 1774 1775 void 1776 g_FS(int, char **) 1777 { 1778 char *argv[3]; 1779 1780 argv[0] = "IP"; 1781 argv[1] = nil; 1782 argv[2] = nil; 1783 g_IP(1, argv); 1784 Bprint(&bout, "NOTE:<I> "); 1785 } 1786 1787 void 1788 g_FE(int, char **) 1789 { 1790 Bprint(&bout, "</I><DT> <DD>"); 1791 closel(); 1792 Bprint(&bout, "<br>\n"); 1793 } 1794 1795 void 1796 g_de(int argc, char **argv) 1797 { 1798 int r; 1799 char *p, *cp; 1800 String *m; 1801 int len; 1802 1803 if(argc < 2) 1804 return; 1805 1806 m = nil; 1807 len = 0; 1808 if(strcmp(argv[0], "am") == 0){ 1809 for(m = macros; m != nil; m = m->next) 1810 if(strcmp(argv[1], m->name) == 0){ 1811 len = strlen(m->val); 1812 break; 1813 } 1814 1815 if(m == nil){ 1816 /* nothing to append to */ 1817 for(;;){ 1818 p = Brdline(&ssp->in, '\n'); 1819 if(p == nil) 1820 break; 1821 p[Blinelen(&ssp->in)-1] = 0; 1822 if(strcmp(p, "..") == 0) 1823 break; 1824 } 1825 return; 1826 } 1827 } 1828 1829 if(m == nil){ 1830 m = emalloc(sizeof(*m)); 1831 m->next = macros; 1832 macros = m; 1833 m->name = strdup(argv[1]); 1834 m->val = nil; 1835 len = 0; 1836 } 1837 1838 /* read up to a .. removing double backslashes */ 1839 for(;;){ 1840 p = Brdline(&ssp->in, '\n'); 1841 if(p == nil) 1842 break; 1843 p[Blinelen(&ssp->in)-1] = 0; 1844 if(strcmp(p, "..") == 0) 1845 break; 1846 m->val = realloc(m->val, len + Blinelen(&ssp->in)+1); 1847 cp = m->val + len; 1848 while(*p){ 1849 r = *p++; 1850 if(r == '\\' && *p == '\\') 1851 p++; 1852 *cp++ = r; 1853 } 1854 *cp++ = '\n'; 1855 len = cp - m->val; 1856 *cp = 0; 1857 } 1858 } 1859 1860 void 1861 g_hrule(int, char**) 1862 { 1863 Bprint(&bout, "<HR>\n"); 1864 } 1865 1866 void 1867 g_BX(int argc, char **argv) 1868 { 1869 Bprint(&bout, "<HR>\n"); 1870 printargs(argc, argv); 1871 Bprint(&bout, "<HR>\n"); 1872 } 1873 1874 void 1875 g_IH(int, char**) 1876 { 1877 Bprint(&bout, "Bell Laboratories, Naperville, Illinois, 60540\n"); 1878 } 1879 1880 void 1881 g_MH(int, char**) 1882 { 1883 Bprint(&bout, "Bell Laboratories, Murray Hill, NJ, 07974\n"); 1884 } 1885 1886 void 1887 g_PY(int, char**) 1888 { 1889 Bprint(&bout, "Bell Laboratories, Piscataway, NJ, 08854\n"); 1890 } 1891 1892 void 1893 g_HO(int, char**) 1894 { 1895 Bprint(&bout, "Bell Laboratories, Holmdel, NJ, 07733\n"); 1896 } 1897 1898 void 1899 g_QS(int, char**) 1900 { 1901 Bprint(&bout, "<BLOCKQUOTE>\n"); 1902 } 1903 1904 void 1905 g_QE(int, char**) 1906 { 1907 Bprint(&bout, "</BLOCKQUOTE>\n"); 1908 } 1909 1910 void 1911 g_RS(int, char**) 1912 { 1913 Bprint(&bout, "<DL><DD>\n"); 1914 } 1915 1916 void 1917 g_RE(int, char**) 1918 { 1919 Bprint(&bout, "</DL>\n"); 1920 } 1921 1922 int gif; 1923 1924 void 1925 g_startgif(int, char **argv) 1926 { 1927 int fd; 1928 int pfd[2]; 1929 char *e, *p; 1930 char name[32]; 1931 Dir *d; 1932 1933 if(strcmp(argv[0], "EQ") == 0) 1934 e = ".EN"; 1935 else if(strcmp(argv[0], "TS") == 0) 1936 e = ".TE"; 1937 else if(strcmp(argv[0], "PS") == 0) 1938 e = ".PE"; 1939 else 1940 return; 1941 1942 p = strrchr(sstack[0].filename, '/'); 1943 if(p != nil) 1944 p++; 1945 else 1946 p = sstack[0].filename; 1947 snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); 1948 fd = create(name, OWRITE, 0664); 1949 if(fd < 0){ 1950 fprint(2, "ms2html: can't create %s: %r\n", name); 1951 return; 1952 } 1953 1954 if(pipe(pfd) < 0){ 1955 fprint(2, "ms2html: can't create pipe: %r\n"); 1956 close(fd); 1957 return; 1958 } 1959 switch(rfork(RFFDG|RFPROC)){ 1960 case -1: 1961 fprint(2, "ms2html: can't fork: %r\n"); 1962 close(fd); 1963 return; 1964 case 0: 1965 dup(fd, 1); 1966 close(fd); 1967 dup(pfd[0], 0); 1968 close(pfd[0]); 1969 close(pfd[1]); 1970 execl("/bin/troff2gif", "troff2gif", 0); 1971 fprint(2, "ms2html: couldn't exec troff2gif: %r\n"); 1972 _exits(nil); 1973 default: 1974 close(fd); 1975 close(pfd[0]); 1976 fprint(pfd[1], ".ll 7i\n"); 1977 for(;;){ 1978 p = Brdline(&ssp->in, '\n'); 1979 if(p == nil) 1980 break; 1981 ssp->lno++; 1982 ssp->rlno++; 1983 if(strncmp(p, e, 3) == 0) 1984 break; 1985 if(write(pfd[1], p, Blinelen(&ssp->in)) < 0) 1986 break; 1987 } 1988 close(pfd[1]); 1989 waitpid(); 1990 d = dirstat(name); 1991 if(d == nil) 1992 break; 1993 if(d->length == 0){ 1994 remove(name); 1995 free(d); 1996 break; 1997 } 1998 free(d); 1999 fprint(2, "ms2html: created auxiliary file %s\n", name); 2000 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2001 break; 2002 } 2003 } 2004 2005 void 2006 g_lf(int argc, char **argv) 2007 { 2008 if(argc > 2) 2009 snprint(ssp->filename, sizeof(ssp->filename), argv[2]); 2010 if(argc > 1) 2011 ssp->rlno = atoi(argv[1]); 2012 } 2013 2014 void 2015 g_so(int argc, char **argv) 2016 { 2017 ssp->lno++; 2018 ssp->rlno++; 2019 if(argc > 1) 2020 pushsrc(argv[1]); 2021 } 2022 2023 2024 void 2025 g_BP(int argc, char **argv) 2026 { 2027 int fd; 2028 char *p, *ext; 2029 char name[32]; 2030 Dir *d; 2031 2032 if(argc < 2) 2033 return; 2034 2035 p = strrchr(argv[1], '/'); 2036 if(p != nil) 2037 p++; 2038 else 2039 p = argv[1]; 2040 2041 2042 ext = strrchr(p, '.'); 2043 if(ext){ 2044 if(strcmp(ext, ".jpeg") == 0 2045 || strcmp(ext, ".gif") == 0){ 2046 Bprint(&bout, "<br><img src=\"%s\"><br>\n", argv[1]); 2047 return; 2048 } 2049 } 2050 2051 2052 snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); 2053 fd = create(name, OWRITE, 0664); 2054 if(fd < 0){ 2055 fprint(2, "ms2html: can't create %s: %r\n", name); 2056 return; 2057 } 2058 2059 switch(rfork(RFFDG|RFPROC)){ 2060 case -1: 2061 fprint(2, "ms2html: can't fork: %r\n"); 2062 close(fd); 2063 return; 2064 case 0: 2065 dup(fd, 1); 2066 close(fd); 2067 execl("/bin/ps2gif", "ps2gif", argv[1], 0); 2068 fprint(2, "ms2html: couldn't exec ps2gif: %r\n"); 2069 _exits(nil); 2070 default: 2071 close(fd); 2072 waitpid(); 2073 d = dirstat(name); 2074 if(d == nil) 2075 break; 2076 if(d->length == 0){ 2077 remove(name); 2078 free(d); 2079 break; 2080 } 2081 free(d); 2082 fprint(2, "ms2html: created auxiliary file %s\n", name); 2083 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2084 break; 2085 } 2086 } 2087 2088 /* insert straight HTML into output */ 2089 void 2090 g__H(int argc, char **argv) 2091 { 2092 int i; 2093 2094 for(i = 1; i < argc; i++) 2095 Bprint(&bout, "%s ", argv[i]); 2096 Bprint(&bout, "\n"); 2097 } 2098 2099 /* HTML page title */ 2100 void 2101 g__T(int argc, char **argv) 2102 { 2103 if(titleseen) 2104 return; 2105 2106 Bprint(&bout, "<title>\n"); 2107 printargs(argc, argv); 2108 Bprint(&bout, "</title></head><body>\n"); 2109 titleseen = 1; 2110 } 2111 2112 void 2113 g_nr(int argc, char **argv) 2114 { 2115 char *val; 2116 2117 if (argc > 1) { 2118 if (argc == 2) 2119 val = "0"; 2120 else 2121 val = argv[2]; 2122 dsnr(argv[1], val, &numregs); 2123 } 2124 } 2125 2126 void 2127 zerodivide(void) 2128 { 2129 fprint(2, "stdin %d(%s:%d): division by 0\n", 2130 ssp->lno, ssp->filename, ssp->rlno); 2131 } 2132 2133 int 2134 numval(char **pline, int recur) 2135 { 2136 char *p; 2137 int neg, x, y; 2138 2139 x = neg = 0; 2140 p = *pline; 2141 while(*p == '-') { 2142 neg = 1 - neg; 2143 p++; 2144 } 2145 if (*p == '(') { 2146 p++; 2147 x = numval(&p, 1); 2148 if (*p != ')') 2149 goto done; 2150 p++; 2151 } 2152 else while(*p >= '0' && *p <= '9') 2153 x = 10*x + *p++ - '0'; 2154 if (neg) 2155 x = -x; 2156 if (recur) 2157 for(;;) { 2158 switch(*p++) { 2159 case '+': 2160 x += numval(&p, 0); 2161 continue; 2162 case '-': 2163 x -= numval(&p, 0); 2164 continue; 2165 case '*': 2166 x *= numval(&p, 0); 2167 continue; 2168 case '/': 2169 y = numval(&p, 0); 2170 if (y == 0) { 2171 zerodivide(); 2172 x = 0; 2173 goto done; 2174 } 2175 x /= y; 2176 continue; 2177 case '<': 2178 if (*p == '=') { 2179 p++; 2180 x = x <= numval(&p, 0); 2181 continue; 2182 } 2183 x = x < numval(&p, 0); 2184 continue; 2185 case '>': 2186 if (*p == '=') { 2187 p++; 2188 x = x >= numval(&p, 0); 2189 continue; 2190 } 2191 x = x > numval(&p, 0); 2192 continue; 2193 case '=': 2194 if (*p == '=') 2195 p++; 2196 x = x == numval(&p, 0); 2197 continue; 2198 case '&': 2199 x &= numval(&p, 0); 2200 continue; 2201 case ':': 2202 x |= numval(&p, 0); 2203 continue; 2204 case '%': 2205 y = numval(&p, 0); 2206 if (!y) { 2207 zerodivide(); 2208 goto done; 2209 } 2210 x %= y; 2211 continue; 2212 } 2213 --p; 2214 break; 2215 } 2216 done: 2217 *pline = p; 2218 return x; 2219 } 2220 2221 int 2222 iftest(char *p, char **bp) 2223 { 2224 char *p1; 2225 int c, neg, rv; 2226 2227 rv = neg = 0; 2228 if (*p == '!') { 2229 neg = 1; 2230 p++; 2231 } 2232 c = *p; 2233 if (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '('/*)*/) { 2234 if (numval(&p,1) >= 1) 2235 rv = 1; 2236 goto done; 2237 } 2238 switch(c) { 2239 case 't': 2240 case 'o': 2241 rv = 1; 2242 case 'n': 2243 case 'e': 2244 p++; 2245 goto done; 2246 } 2247 for(p1 = ++p; *p != c; p++) 2248 if (!*p) 2249 goto done; 2250 for(p++;;) { 2251 if (*p != *p1++) { 2252 while(*p && *p++ != c); 2253 goto done; 2254 } 2255 if (*p++ == c) 2256 break; 2257 } 2258 rv = 1; 2259 done: 2260 if (neg) 2261 rv = 1 - rv; 2262 while(*p == ' ' || *p == '\t') 2263 p++; 2264 *bp = p; 2265 return rv; 2266 } 2267 2268 void 2269 scanline(char *p, char *e, int wantnl) 2270 { 2271 int c; 2272 Rune r; 2273 2274 while((c = getrune()) == ' ' || c == '\t') ; 2275 while(p < e) { 2276 if (c < 0) 2277 break; 2278 if (c < Runeself) { 2279 if (c == '\n') { 2280 if (wantnl) 2281 *p++ = c; 2282 break; 2283 } 2284 *p++ = c; 2285 } 2286 else { 2287 r = c; 2288 p += runetochar(p, &r); 2289 } 2290 c = getrune(); 2291 } 2292 *p = 0; 2293 } 2294 2295 void 2296 pushbody(char *line) 2297 { 2298 char *b; 2299 2300 if (line[0] == '\\' && line[1] == '{' /*}*/ ) 2301 line += 2; 2302 if (strsp < Maxmstack - 1) { 2303 pushstr(b = strdup(line)); 2304 mustfree[strsp] = b; 2305 } 2306 } 2307 2308 void 2309 skipbody(char *line) 2310 { 2311 int c, n; 2312 2313 if (line[0] != '\\' || line[1] != '{' /*}*/ ) 2314 return; 2315 for(n = 1;;) { 2316 while((c = getrune()) != '\\') 2317 if (c < 0) 2318 return; 2319 c = getrune(); 2320 if (c == '{') 2321 n++; 2322 else if ((c == '}' && (c = getrune()) == '\n' && !--n) 2323 || c < 0) 2324 return; 2325 } 2326 } 2327 2328 int 2329 ifstart(char *line, char *e, char **bp) 2330 { 2331 int it; 2332 char *b; 2333 2334 b = copyline(line, e, 1); 2335 ungetrune(); 2336 b[-1] = getrune(); 2337 scanline(b, e, 1); 2338 it = iftest(line, bp); 2339 return it; 2340 } 2341 2342 void 2343 g_ie(char *line, char *e) 2344 { 2345 char *b; 2346 2347 if (elsetop >= Maxif-1) { 2348 fprint(2, "ms2html: .ie's too deep\n"); 2349 return; 2350 } 2351 if (ifwastrue[++elsetop] = ifstart(line, e, &b)) 2352 pushbody(b); 2353 else 2354 skipbody(b); 2355 } 2356 2357 void 2358 g_if(char *line, char *e) 2359 { 2360 char *b; 2361 2362 if (ifstart(line, e, &b)) 2363 pushbody(b); 2364 else 2365 skipbody(b); 2366 } 2367 2368 void 2369 g_el(char *line, char *e) 2370 { 2371 if (elsetop < 0) 2372 return; 2373 scanline(line, e, 1); 2374 if (ifwastrue[elsetop--]) 2375 skipbody(line); 2376 else 2377 pushbody(line); 2378 } 2379 2380 void 2381 g_ig(int argc, char **argv) 2382 { 2383 char *p, *s; 2384 2385 s = ".."; 2386 if (argc > 1) 2387 s = argv[1]; 2388 for(;;) { 2389 p = Brdline(&ssp->in, '\n'); 2390 if(p == nil) 2391 break; 2392 p[Blinelen(&ssp->in)-1] = 0; 2393 if(strcmp(p, s) == 0) 2394 break; 2395 } 2396 } 2397 2398 void 2399 g_ds(char *line, char *e) 2400 { 2401 char *b; 2402 2403 b = copyline(line, e, 1); 2404 if (b > line) { 2405 copyline(b, e, 0); 2406 if (*b == '"') 2407 b++; 2408 ds(line, b); 2409 } 2410 } 2411 2412 void 2413 g_as(char *line, char *e) 2414 { 2415 String *s; 2416 char *b; 2417 2418 b = copyline(line, e, 1); 2419 if (b == line) 2420 return; 2421 copyline(b, e, 0); 2422 if (*b == '"') 2423 b++; 2424 for(s = strings; s != nil; s = s->next) 2425 if(strcmp(line, s->name) == 0) 2426 break; 2427 2428 if(s == nil){ 2429 ds(line, b); 2430 return; 2431 } 2432 2433 s->val = realloc(s->val, strlen(s->val) + strlen(b) + 1); 2434 strcat(s->val, b); 2435 } 2436 2437 void 2438 g_BS(int argc, char **argv) 2439 { 2440 int i; 2441 2442 if (argc > 1 && !weBref) { 2443 Bprint(&bout, "<a href=\"%s\"", argv[1]); 2444 for(i = 2; i < argc; i++) 2445 Bprint(&bout, " %s", argv[i]); 2446 Bprint(&bout, ">"); 2447 weBref = 1; 2448 } 2449 } 2450 2451 void 2452 g_BE(int, char**) 2453 { 2454 if (weBref) { 2455 Bprint(&bout, "</a>"); 2456 weBref = 0; 2457 } 2458 } 2459 2460 void 2461 g_LB(int argc, char **argv) 2462 { 2463 if (argc > 1) { 2464 if (weBref) 2465 g_BE(0,nil); 2466 Bprint(&bout, "<a name=\"%s\"></a>", argv[1]); 2467 } 2468 } 2469 2470 void 2471 g_RT(int, char**) 2472 { 2473 g_BE(0,nil); 2474 dohanginghead(); 2475 closel(); 2476 closefont(); 2477 } 2478