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 if(name == nil){ 573 dirfstat(0, &d); 574 name = d.name; 575 fd = 0; 576 } else { 577 fd = open(name, OREAD); 578 if(fd < 0){ 579 fprint(2, "ms2html: .can't open %s: %r\n", name); 580 return; 581 } 582 } 583 ssp++; 584 ssp->fd = fd; 585 Binit(&ssp->in, fd, OREAD); 586 snprint(ssp->filename, sizeof(ssp->filename), "%s", name); 587 ssp->lno = ssp->rlno = 1; 588 } 589 590 /* get next logical byte. from stdin or a defined string */ 591 int 592 getrune(void) 593 { 594 int i; 595 Rune r; 596 int c; 597 Mstack *m; 598 599 while(strsp >= 0){ 600 i = chartorune(&r, strstack[strsp]); 601 if(r != 0){ 602 strstack[strsp] += i; 603 lastsrc = Dstring; 604 return r; 605 } 606 if (mustfree[strsp]) { 607 free(mustfree[strsp]); 608 mustfree[strsp] = nil; 609 } 610 strsp--; 611 } 612 while(msp >= 0){ 613 m = &mstack[msp]; 614 i = chartorune(&r, m->ptr); 615 if(r != 0){ 616 m->ptr += i; 617 lastsrc = Macro; 618 return r; 619 } 620 for(i = 0; m->argv[i] != nil; i++) 621 free(m->argv[i]); 622 msp--; 623 } 624 625 lastsrc = Input; 626 do { 627 if(ssp < sstack) 628 return -1; 629 c = Bgetrune(&ssp->in); 630 if(c >= 0){ 631 r = c; 632 break; 633 } 634 close(ssp->fd); 635 ssp--; 636 } while(r < 0); 637 638 return r; 639 } 640 641 void 642 ungetrune(void) 643 { 644 switch(lastsrc){ 645 case Dstring: 646 if(strsp >= 0) 647 strstack[strsp]--; 648 break; 649 case Macro: 650 if(msp >= 0) 651 mstack[msp].ptr--; 652 break; 653 case Input: 654 if(ssp >= sstack) 655 Bungetrune(&ssp->in); 656 break; 657 } 658 } 659 660 int vert; 661 662 char* 663 changefont(Font *f) 664 { 665 token[0] = 0; 666 if(curfont != nil) 667 strcpy(token, curfont->end); 668 if(f != nil) 669 strcat(token, f->start); 670 prevfont = curfont; 671 curfont = f; 672 return token; 673 } 674 675 /* get next logical byteacter. expand it with escapes */ 676 char* 677 getnext(void) 678 { 679 int r, mult, size; 680 Entity *e; 681 Troffspec *t; 682 Rune R; 683 char str[4]; 684 685 r = getrune(); 686 if(r < 0) 687 return nil; 688 if(r > 128){ 689 for(e = entity; e->name; e++) 690 if(e->value == r) 691 return e->name; 692 return "¿"; 693 } 694 695 switch(r){ 696 case '\\': 697 r = getrune(); 698 if(r < 0) 699 return nil; 700 switch(r){ 701 case ' ': 702 return " "; 703 704 /* chars to ignore */ 705 case '&': 706 case '|': 707 case '%': 708 return ""; 709 710 /* small space in troff, nothing in nroff */ 711 case '^': 712 return getnext(); 713 714 /* ignore arg */ 715 case 'k': 716 getrune(); 717 return getnext(); 718 719 /* comment */ 720 case '"': 721 while(getrune() != '\n') 722 ; 723 return "\n"; 724 /* ignore line */ 725 case '!': 726 while(getrune() != '\n') 727 ; 728 ungetrune(); 729 return getnext(); 730 731 /* defined strings */ 732 case '*': 733 r = getrune(); 734 if(r == '('){ 735 str[0] = getrune(); 736 str[1] = getrune(); 737 str[2] = 0; 738 } else { 739 str[0] = r; 740 str[1] = 0; 741 } 742 pushstr(getds(str)); 743 return getnext(); 744 745 /* macro args */ 746 case '$': 747 r = getrune(); 748 if(r < '1' || r > '9'){ 749 token[0] = '\\'; 750 token[1] = '$'; 751 token[2] = r; 752 token[3] = 0; 753 return token; 754 } 755 r -= '0'; 756 if(msp >= 0) 757 pushstr(mstack[msp].argv[r]); 758 return getnext(); 759 760 /* special chars */ 761 case '(': 762 token[0] = getrune(); 763 token[1] = getrune(); 764 token[2] = 0; 765 for(t = tspec; t->name; t++) 766 if(strcmp(token, t->name) == 0) 767 return t->value; 768 return "¿"; 769 770 /* ignore immediately following newline */ 771 case 'c': 772 r = getrune(); 773 if (r == '\n') { 774 sol = ignore_nl = 1; 775 if (indirective) 776 break; 777 } 778 else 779 ungetrune(); 780 return getnext(); 781 782 /* escape backslash */ 783 case 'e': 784 return "\\"; 785 break; 786 787 /* font change */ 788 case 'f': 789 r = getrune(); 790 switch(r){ 791 case '(': 792 str[0] = getrune(); 793 str[1] = getrune(); 794 str[2] = 0; 795 token[0] = 0; 796 if(strcmp("BI", str) == 0) 797 return changefont(&bifont); 798 else if(strcmp("CW", str) == 0) 799 return changefont(&cwfont); 800 else 801 return changefont(nil); 802 case '3': 803 case 'B': 804 return changefont(&bfont); 805 case '2': 806 case 'I': 807 return changefont(&ifont); 808 case '4': 809 return changefont(&bifont); 810 case '5': 811 return changefont(&cwfont); 812 case 'P': 813 return changefont(prevfont); 814 case 'R': 815 default: 816 return changefont(nil); 817 } 818 819 /* number register */ 820 case 'n': 821 r = getrune(); 822 if (r == '(') /*)*/ { 823 r = getrune(); 824 if (r < 0) 825 return nil; 826 str[0] = r; 827 r = getrune(); 828 if (r < 0) 829 return nil; 830 str[1] = r; 831 str[2] = 0; 832 } 833 else { 834 str[0] = r; 835 str[1] = 0; 836 } 837 pushstr(getnr(str)); 838 return getnext(); 839 840 /* font size */ 841 case 's': 842 mult = 1; 843 size = 0; 844 for(;;){ 845 r = getrune(); 846 if(r < 0) 847 return nil; 848 if(r == '+' || r == '(') 849 ; 850 else if(r == '-') 851 mult *= -1; 852 else if(r >= '0' && r <= '9') 853 size = size*10 + (r-'0'); 854 else{ 855 ungetrune(); 856 return getnext(); 857 } 858 } 859 break; 860 861 /* vertical movement */ 862 case 'v': 863 r = getrune(); 864 if(r != '\''){ 865 ungetrune(); 866 return getnext(); 867 } 868 r = getrune(); 869 if(r != '-') 870 vert--; 871 else 872 vert++; 873 while(r != '\'' && r != '\n') 874 r = getrune(); 875 if(r != '\'') 876 ungetrune(); 877 878 if(vert > 0) 879 return "^"; 880 return getnext(); 881 882 883 /* horizontal line */ 884 case 'l': 885 r = getrune(); 886 if(r != '\''){ 887 ungetrune(); 888 return "<HR>"; 889 } 890 while(getrune() != '\'') 891 ; 892 return "<HR>"; 893 894 /* character height and slant */ 895 case 'S': 896 case 'H': 897 r = getrune(); 898 if(r != '\''){ 899 ungetrune(); 900 return "<HR>"; 901 } 902 while(getrune() != '\'') 903 ; 904 return getnext(); 905 906 /* digit-width space */ 907 case '0': 908 return " "; 909 910 /*for .if, .ie, .el */ 911 case '{': 912 return "\\{"; /*}*/ 913 case '}': 914 return ""; 915 /* up and down */ 916 case 'u': 917 if (isdown) { 918 isdown = 0; 919 return "</sub>"; 920 } 921 isup = 1; 922 return "<sup>"; 923 case 'd': 924 if (isup) { 925 isup = 0; 926 return "</sup>"; 927 } 928 isdown = 1; 929 return "<sub>"; 930 } 931 break; 932 case '&': 933 if(msp >= 0 || strsp >= 0) 934 return "&"; 935 return "&"; 936 case '<': 937 if(msp >= 0 || strsp >= 0) 938 return "<"; 939 return "<"; 940 case '>': 941 if(msp >= 0 || strsp >= 0) 942 return ">"; 943 return ">"; 944 } 945 if (r < Runeself) { 946 token[0] = r; 947 token[1] = 0; 948 } 949 else { 950 R = r; 951 token[runetochar(token,&R)] = 0; 952 } 953 return token; 954 } 955 956 char* 957 copyline(char *p, char *e, int arg0) 958 { 959 int c; 960 Rune r; 961 char *p1; 962 963 while((c = getrune()) == ' ' || c == '\t') 964 ; 965 for(indirective = 1; p < e; c = getrune()) { 966 if (c < 0) 967 goto done; 968 switch(c) { 969 case '\\': 970 break; 971 case '\n': 972 if (arg0) 973 ungetrune(); 974 goto done; 975 case ' ': 976 case '\t': 977 if (arg0) 978 goto done; 979 default: 980 r = c; 981 p += runetochar(p,&r); 982 continue; 983 } 984 ungetrune(); 985 p1 = getnext(); 986 if (p1 == nil) 987 goto done; 988 if (*p1 == '\n') { 989 if (arg0) 990 ungetrune(); 991 break; 992 } 993 while((*p = *p1++) && p < e) 994 p++; 995 } 996 done: 997 indirective = 0; 998 *p++ = 0; 999 return p; 1000 } 1001 1002 char* 1003 copyarg(char *p, char *e, int *nullarg) 1004 { 1005 int c, quoted; 1006 Rune r; 1007 char *p1; 1008 1009 *nullarg = 0; 1010 quoted = 0; 1011 do{ 1012 c = getrune(); 1013 } while(c == ' ' || c == '\t'); 1014 1015 if(c == '"'){ 1016 quoted = 1; 1017 *nullarg = 1; 1018 c = getrune(); 1019 } 1020 1021 if(c == '\n') 1022 goto done; 1023 1024 for(; p < e; c = getrune()) { 1025 if (c < 0) 1026 break; 1027 switch(c) { 1028 case '\\': 1029 break; 1030 case '\n': 1031 ungetrune(); 1032 goto done; 1033 case ' ': 1034 case '\t': 1035 if(!quoted) 1036 goto done; 1037 r = c; 1038 p += runetochar(p,&r); 1039 continue; 1040 case '"': 1041 if(quoted) 1042 goto done; 1043 r = c; 1044 p += runetochar(p,&r); 1045 continue; 1046 default: 1047 r = c; 1048 p += runetochar(p,&r); 1049 continue; 1050 } 1051 ungetrune(); 1052 p1 = getnext(); 1053 if(p1 == nil) 1054 break; 1055 if(*p1 == '\n') 1056 break; 1057 while((*p = *p1++) && p < e) 1058 p++; 1059 } 1060 done: 1061 *p++ = 0; 1062 return p; 1063 1064 } 1065 1066 int 1067 parseargs(char *p, char *e, char **argv) 1068 { 1069 int argc; 1070 char *np; 1071 int nullarg; 1072 1073 indirective = 1; 1074 *p++ = 0; 1075 for(argc = 1; argc < Narg; argc++){ 1076 np = copyarg(p, e, &nullarg); 1077 if(nullarg==0 && np == p+1) 1078 break; 1079 argv[argc] = p; 1080 p = np; 1081 } 1082 argv[argc] = nil; 1083 indirective = 0; 1084 1085 1086 return argc; 1087 } 1088 1089 void 1090 dodirective(void) 1091 { 1092 char *p, *e; 1093 Goobie *g; 1094 Goobieif *gif; 1095 char line[Nline], *line1; 1096 int i, argc; 1097 char *argv[Narg]; 1098 Mstack *m; 1099 1100 /* read line, translate special bytes */ 1101 e = line + sizeof(line) - UTFmax - 1; 1102 line1 = copyline(line, e, 1); 1103 if (!line[0]) 1104 return; 1105 argv[0] = line; 1106 1107 /* first look through user defined macros */ 1108 p = getmacro(argv[0]); 1109 if(p != nil){ 1110 if(msp == Maxmstack-1){ 1111 fprint(2, "ms2html: macro stack overflow\n"); 1112 return; 1113 } 1114 argc = parseargs(line1, e, argv); 1115 m = &mstack[++msp]; 1116 m->ptr = p; 1117 memset(m->argv, 0, sizeof(m->argv)); 1118 for(i = 0; i < argc; i++) 1119 m->argv[i] = strdup(argv[i]); 1120 return; 1121 } 1122 1123 /* check for .if or .ie */ 1124 for(gif = gtabif; gif->name; gif++) 1125 if(strcmp(gif->name, argv[0]) == 0){ 1126 (*gif->f)(line1, e); 1127 return; 1128 } 1129 1130 argc = parseargs(line1, e, argv); 1131 1132 /* try standard ms macros */ 1133 for(g = gtab; g->name; g++) 1134 if(strcmp(g->name, argv[0]) == 0){ 1135 (*g->f)(argc, argv); 1136 return; 1137 } 1138 1139 if(debug) 1140 fprint(2, "stdin %d(%s:%d): unknown directive %s\n", 1141 ssp->lno, ssp->filename, ssp->rlno, line); 1142 } 1143 1144 void 1145 printarg(char *a) 1146 { 1147 char *e, *p; 1148 1149 e = a + strlen(a); 1150 pushstr(a); 1151 while(strsp >= 0 && strstack[strsp] >= a && strstack[strsp] < e){ 1152 p = getnext(); 1153 if(p == nil) 1154 return; 1155 Bprint(&bout, "%s", p); 1156 } 1157 } 1158 1159 void 1160 printargs(int argc, char **argv) 1161 { 1162 argc--; 1163 argv++; 1164 while(--argc > 0){ 1165 printarg(*argv++); 1166 Bprint(&bout, " "); 1167 } 1168 if(argc == 0) 1169 printarg(*argv); 1170 } 1171 1172 void 1173 dohangingdt(void) 1174 { 1175 switch(hangingdt){ 1176 case 3: 1177 hangingdt--; 1178 break; 1179 case 2: 1180 Bprint(&bout, "<dd>"); 1181 hangingdt = 0; 1182 break; 1183 } 1184 1185 } 1186 1187 void 1188 dohangingau(void) 1189 { 1190 if(hangingau == 0) 1191 return; 1192 Bprint(&bout, "</I></DL>\n"); 1193 hangingau = 0; 1194 } 1195 1196 void 1197 dohanginghead(void) 1198 { 1199 if(hanginghead == 0) 1200 return; 1201 Bprint(&bout, "</H%d>\n", hanginghead); 1202 hanginghead = 0; 1203 } 1204 1205 /* 1206 * convert a man page to html and output 1207 */ 1208 void 1209 doconvert(void) 1210 { 1211 char c, *p; 1212 Tm *t; 1213 1214 pushsrc(nil); 1215 1216 sol = 1; 1217 Bprint(&bout, "<html>\n"); 1218 Bflush(&bout); 1219 for(;;){ 1220 p = getnext(); 1221 if(p == nil) 1222 break; 1223 c = *p; 1224 if(c == '.' && sol){ 1225 dodirective(); 1226 dohangingdt(); 1227 ssp->lno++; 1228 ssp->rlno++; 1229 sol = 1; 1230 } else if(c == '\n'){ 1231 if (ignore_nl) 1232 ignore_nl = 0; 1233 else { 1234 if(hangingau) 1235 Bprint(&bout, "<br>\n"); 1236 else 1237 Bprint(&bout, "%s", p); 1238 dohangingdt(); 1239 } 1240 ssp->lno++; 1241 ssp->rlno++; 1242 sol = 1; 1243 } else{ 1244 Bprint(&bout, "%s", p); 1245 ignore_nl = sol = 0; 1246 } 1247 } 1248 dohanginghead(); 1249 dohangingdt(); 1250 closel(); 1251 if(curfont) 1252 Bprint(&bout, "%s", curfont->end); 1253 Bprint(&bout, "<br> <br>\n"); 1254 Bprint(&bout, "<A href=http://www.lucent.com/copyright.html>\n"); 1255 t = localtime(time(nil)); 1256 Bprint(&bout, "Copyright</A> © %d Lucent Technologies Inc. All rights reserved.\n", 1257 t->year+1900); 1258 Bprint(&bout, "</body></html>\n"); 1259 } 1260 1261 void 1262 main(int argc, char **argv) 1263 { 1264 quiet = 1; 1265 if(argc > 1) 1266 if(strcmp(argv[1], "-v") == 0) 1267 quiet = 0; 1268 1269 Binit(&bout, 1, OWRITE); 1270 1271 ds("R", "®"); 1272 1273 doconvert(); 1274 exits(nil); 1275 } 1276 1277 void 1278 g_notyet(int, char **argv) 1279 { 1280 fprint(2, "ms2html: .%s not yet supported\n", argv[0]); 1281 } 1282 1283 void 1284 g_ignore(int, char **argv) 1285 { 1286 if(quiet) 1287 return; 1288 fprint(2, "ms2html: line %d: ignoring .%s\n", ssp->lno, argv[0]); 1289 } 1290 1291 void 1292 g_PP(int, char**) 1293 { 1294 dohanginghead(); 1295 closel(); 1296 closefont(); 1297 Bprint(&bout, "<P>\n"); 1298 paragraph = 1; 1299 } 1300 1301 void 1302 g_LP(int, char**) 1303 { 1304 dohanginghead(); 1305 closel(); 1306 closefont(); 1307 Bprint(&bout, "<br> <br>\n"); 1308 } 1309 1310 /* close a list */ 1311 void 1312 closel(void) 1313 { 1314 g_P2(1, nil); 1315 dohangingau(); 1316 if(paragraph){ 1317 Bprint(&bout, "</P>\n"); 1318 paragraph = 0; 1319 } 1320 switch(list){ 1321 case Lordered: 1322 Bprint(&bout, "</ol>\n"); 1323 break; 1324 case Lunordered: 1325 Bprint(&bout, "</ul>\n"); 1326 break; 1327 case Lother: 1328 case Ldef: 1329 Bprint(&bout, "</dl>\n"); 1330 break; 1331 } 1332 list = 0; 1333 1334 } 1335 1336 1337 void 1338 g_IP(int argc, char **argv) 1339 { 1340 switch(list){ 1341 default: 1342 closel(); 1343 if(argc > 1){ 1344 if(strcmp(argv[1], "1") == 0){ 1345 list = Lordered; 1346 listnum = 1; 1347 Bprint(&bout, "<OL>\n"); 1348 } else if(strcmp(argv[1], "\\(bu") == 0){ 1349 list = Lunordered; 1350 Bprint(&bout, "<UL>\n"); 1351 } else { 1352 list = Lother; 1353 Bprint(&bout, "<DL COMPACT>\n"); 1354 } 1355 } else { 1356 list = Lother; 1357 Bprint(&bout, "<DL>\n"); 1358 } 1359 break; 1360 case Lother: 1361 case Lordered: 1362 case Lunordered: 1363 break; 1364 } 1365 1366 switch(list){ 1367 case Lother: 1368 Bprint(&bout, "<DT>"); 1369 if(argc > 1) 1370 printarg(argv[1]); 1371 else 1372 Bprint(&bout, "<DT> "); 1373 Bprint(&bout, "<DD>\n"); 1374 break; 1375 case Lordered: 1376 case Lunordered: 1377 Bprint(&bout, "<LI>\n"); 1378 break; 1379 } 1380 } 1381 1382 /* 1383 * .5i is one <DL><DT><DD> 1384 */ 1385 void 1386 g_in(int argc, char **argv) 1387 { 1388 float f; 1389 int delta, x; 1390 char *p; 1391 1392 f = indent/0.5; 1393 delta = f; 1394 if(argc <= 1){ 1395 indent = 0.0; 1396 } else { 1397 f = strtod(argv[1], &p); 1398 switch(*p){ 1399 case 'i': 1400 break; 1401 case 'c': 1402 f = f / 2.54; 1403 break; 1404 case 'P': 1405 f = f / 6; 1406 break; 1407 default: 1408 case 'u': 1409 case 'm': 1410 f = f * (12 / 72); 1411 break; 1412 case 'n': 1413 f = f * (6 / 72); 1414 break; 1415 case 'p': 1416 f = f / 72.0; 1417 break; 1418 } 1419 switch(argv[1][0]){ 1420 case '+': 1421 case '-': 1422 indent += f; 1423 break; 1424 default: 1425 indent = f; 1426 break; 1427 } 1428 } 1429 if(indent < 0.0) 1430 indent = 0.0; 1431 f = (indent/0.5); 1432 x = f; 1433 delta = x - delta; 1434 while(delta < 0){ 1435 Bprint(&bout, "</DL>\n"); 1436 delta++; 1437 } 1438 while(delta > 0){ 1439 Bprint(&bout, "<DL><DT><DD>\n"); 1440 delta--; 1441 } 1442 } 1443 1444 void 1445 g_HP(int, char**) 1446 { 1447 switch(list){ 1448 default: 1449 closel(); 1450 list = Ldef; 1451 hangingdt = 1; 1452 Bprint(&bout, "<DL><DT>\n"); 1453 break; 1454 case Ldef: 1455 if(hangingdt) 1456 Bprint(&bout, "<DD>"); 1457 Bprint(&bout, "<DT>"); 1458 hangingdt = 1; 1459 break; 1460 } 1461 } 1462 1463 void 1464 g_SH(int, char**) 1465 { 1466 dohanginghead(); 1467 closel(); 1468 closefont(); 1469 Bprint(&bout, "<H%d>", HH); 1470 hanginghead = HH; 1471 } 1472 1473 void 1474 g_NH(int argc, char **argv) 1475 { 1476 int i, level; 1477 1478 closel(); 1479 closefont(); 1480 1481 if(argc == 1) 1482 level = 0; 1483 else { 1484 level = atoi(argv[1])-1; 1485 if(level < 0 || level >= Maxnh) 1486 level = Maxnh - 1; 1487 } 1488 nh[level]++; 1489 1490 Bprint(&bout, "<H%d>", HH); 1491 hanginghead = HH; 1492 1493 Bprint(&bout, "%d", nh[0]); 1494 for(i = 1; i <= level; i++) 1495 Bprint(&bout, ".%d", nh[i]); 1496 Bprint(&bout, " "); 1497 1498 for(i = level+1; i < Maxnh; i++) 1499 nh[i] = 0; 1500 } 1501 1502 void 1503 g_TL(int, char**) 1504 { 1505 char *p, *np; 1506 char name[128]; 1507 1508 closefont(); 1509 1510 if(!titleseen){ 1511 /* get base part of filename */ 1512 p = strrchr(ssp->filename, '/'); 1513 if(p == nil) 1514 p = ssp->filename; 1515 else 1516 p++; 1517 strncpy(name, p, sizeof(name)); 1518 name[sizeof(name)-1] = 0; 1519 1520 /* dump any extensions */ 1521 np = strchr(name, '.'); 1522 if(np) 1523 *np = 0; 1524 1525 Bprint(&bout, "<title>\n"); 1526 Bprint(&bout, "%s\n", p); 1527 Bprint(&bout, "</title>\n"); 1528 Bprint(&bout, "<body BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#330088\" ALINK=\"#FF0044\">\n"); 1529 titleseen = 1; 1530 } 1531 1532 Bprint(&bout, "<H%d>", 1); 1533 hanginghead = 1; 1534 } 1535 1536 void 1537 g_AU(int, char**) 1538 { 1539 closel(); 1540 dohanginghead(); 1541 Bprint(&bout, "<DL><DD><I>"); 1542 hangingau = 1; 1543 } 1544 1545 void 1546 setfont(Font *f) 1547 { 1548 if(curfont != nil) 1549 Bprint(&bout, "%s", curfont->end); 1550 prevfont = curfont; 1551 if(f != nil) 1552 Bprint(&bout, "%s", f->start); 1553 curfont = f; 1554 } 1555 1556 /* 1557 * for 3 args print arg3 \fxarg1\fP arg2 1558 * for 2 args print arg1 \fxarg2\fP 1559 * for 1 args print \fxarg1\fP 1560 */ 1561 void 1562 font(Font *f, int argc, char **argv) 1563 { 1564 Font *prev; 1565 1566 if(argc == 1){ 1567 setfont(nil); 1568 return; 1569 } 1570 if(argc > 3) 1571 printarg(argv[3]); 1572 prev = prevfont; 1573 setfont(f); 1574 printarg(argv[1]); 1575 setfont(prevfont); 1576 prevfont = prev; 1577 if(argc > 2) 1578 printarg(argv[2]); 1579 Bprint(&bout, "\n"); 1580 } 1581 1582 void 1583 closefont(void) 1584 { 1585 if(curfont != nil) 1586 Bprint(&bout, "%s", curfont->end); 1587 curfont = nil; 1588 prevfont = nil; 1589 } 1590 1591 void 1592 g_B(int argc, char **argv) 1593 { 1594 font(&bfont, argc, argv); 1595 } 1596 1597 void 1598 g_R(int argc, char **argv) 1599 { 1600 font(nil, argc, argv); 1601 } 1602 1603 void 1604 g_BI(int argc, char **argv) 1605 { 1606 font(&bifont, argc, argv); 1607 } 1608 1609 void 1610 g_CW(int argc, char **argv) 1611 { 1612 font(&cwfont, argc, argv); 1613 } 1614 1615 char* 1616 lower(char *p) 1617 { 1618 char *x; 1619 1620 for(x = p; *x; x++) 1621 if(*x >= 'A' && *x <= 'Z') 1622 *x -= 'A' - 'a'; 1623 return p; 1624 } 1625 1626 void 1627 g_I(int argc, char **argv) 1628 { 1629 int anchor; 1630 char *p; 1631 1632 anchor = 0; 1633 if(argc > 2){ 1634 p = argv[2]; 1635 if(p[0] == '(') 1636 if(p[1] >= '0' && p[1] <= '9') 1637 if(p[2] == ')'){ 1638 anchor = 1; 1639 Bprint(&bout, "<A href=\"/magic/man2html/%c/%s\">", 1640 p[1], lower(argv[1])); 1641 } 1642 } 1643 font(&ifont, argc, argv); 1644 if(anchor) 1645 Bprint(&bout, "</A>"); 1646 } 1647 1648 void 1649 g_br(int, char**) 1650 { 1651 if(hangingdt){ 1652 Bprint(&bout, "<dd>"); 1653 hangingdt = 0; 1654 }else 1655 Bprint(&bout, "<br>\n"); 1656 } 1657 1658 void 1659 g_P1(int, char**) 1660 { 1661 if(example == 0){ 1662 example = 1; 1663 Bprint(&bout, "<DL><DT><DD><TT><PRE>\n"); 1664 } 1665 } 1666 1667 void 1668 g_P2(int, char**) 1669 { 1670 if(example){ 1671 example = 0; 1672 Bprint(&bout, "</PRE></TT></DL>\n"); 1673 } 1674 } 1675 1676 void 1677 g_SM(int, char **argv) 1678 { 1679 Bprint(&bout, "%s", argv[1]); 1680 } 1681 1682 void 1683 g_ft(int argc, char **argv) 1684 { 1685 if(argc < 2){ 1686 setfont(nil); 1687 return; 1688 } 1689 1690 switch(argv[1][0]){ 1691 case '3': 1692 case 'B': 1693 setfont(&bfont); 1694 break; 1695 case '2': 1696 case 'I': 1697 setfont(&ifont); 1698 break; 1699 case '4': 1700 setfont(&bifont); 1701 break; 1702 case '5': 1703 setfont(&cwfont); 1704 break; 1705 case 'P': 1706 setfont(prevfont); 1707 break; 1708 case 'R': 1709 default: 1710 setfont(nil); 1711 break; 1712 } 1713 } 1714 1715 void 1716 g_sp(int argc, char **argv) 1717 { 1718 int n; 1719 1720 n = 1; 1721 if(argc > 1){ 1722 n = atoi(argv[1]); 1723 if(n < 1) 1724 n = 1; 1725 if(argv[1][strlen(argv[1])-1] == 'i') 1726 n *= 4; 1727 } 1728 if(n > 5){ 1729 Bprint(&bout, "<br> <br>\n"); 1730 Bprint(&bout, "<HR>\n"); 1731 Bprint(&bout, "<br> <br>\n"); 1732 } else 1733 for(; n > 0; n--) 1734 Bprint(&bout, "<br> <br>\n"); 1735 } 1736 1737 void 1738 rm_loop(char *name, String **l) 1739 { 1740 String *s; 1741 for(s = *l; s != nil; s = *l){ 1742 if(strcmp(name, s->name) == 0){ 1743 *l = s->next; 1744 free(s->name); 1745 free(s->val); 1746 free(s); 1747 break; 1748 } 1749 l = &s->next; 1750 } 1751 } 1752 1753 void 1754 g_rm(int argc, char **argv) 1755 { 1756 Goobie *g; 1757 char *name; 1758 int i; 1759 1760 for(i = 1; i < argc; i++) { 1761 name = argv[i]; 1762 rm_loop(name, &strings); 1763 rm_loop(name, ¯os); 1764 for(g = gtab; g->name; g++) 1765 if (strcmp(g->name, name) == 0) { 1766 g->f = g_ignore; 1767 break; 1768 } 1769 } 1770 } 1771 1772 void 1773 g_AB(int, char**) 1774 { 1775 closel(); 1776 Bprint(&bout, "<DL><DD><H4>ABSTRACT</H4>\n"); 1777 } 1778 1779 void 1780 g_AE(int, char**) 1781 { 1782 Bprint(&bout, "</DL>\n"); 1783 } 1784 1785 void 1786 g_FS(int, char **) 1787 { 1788 char *argv[3]; 1789 1790 argv[0] = "IP"; 1791 argv[1] = nil; 1792 argv[2] = nil; 1793 g_IP(1, argv); 1794 Bprint(&bout, "NOTE:<I> "); 1795 } 1796 1797 void 1798 g_FE(int, char **) 1799 { 1800 Bprint(&bout, "</I><DT> <DD>"); 1801 closel(); 1802 Bprint(&bout, "<br>\n"); 1803 } 1804 1805 void 1806 g_de(int argc, char **argv) 1807 { 1808 int r; 1809 char *p, *cp; 1810 String *m; 1811 int len; 1812 1813 if(argc < 2) 1814 return; 1815 1816 m = nil; 1817 len = 0; 1818 if(strcmp(argv[0], "am") == 0){ 1819 for(m = macros; m != nil; m = m->next) 1820 if(strcmp(argv[1], m->name) == 0){ 1821 len = strlen(m->val); 1822 break; 1823 } 1824 1825 if(m == nil){ 1826 /* nothing to append to */ 1827 for(;;){ 1828 p = Brdline(&ssp->in, '\n'); 1829 if(p == nil) 1830 break; 1831 p[Blinelen(&ssp->in)-1] = 0; 1832 if(strcmp(p, "..") == 0) 1833 break; 1834 } 1835 return; 1836 } 1837 } 1838 1839 if(m == nil){ 1840 m = emalloc(sizeof(*m)); 1841 m->next = macros; 1842 macros = m; 1843 m->name = strdup(argv[1]); 1844 m->val = nil; 1845 len = 0; 1846 } 1847 1848 /* read up to a .. removing double backslashes */ 1849 for(;;){ 1850 p = Brdline(&ssp->in, '\n'); 1851 if(p == nil) 1852 break; 1853 p[Blinelen(&ssp->in)-1] = 0; 1854 if(strcmp(p, "..") == 0) 1855 break; 1856 m->val = realloc(m->val, len + Blinelen(&ssp->in)+1); 1857 cp = m->val + len; 1858 while(*p){ 1859 r = *p++; 1860 if(r == '\\' && *p == '\\') 1861 p++; 1862 *cp++ = r; 1863 } 1864 *cp++ = '\n'; 1865 len = cp - m->val; 1866 *cp = 0; 1867 } 1868 } 1869 1870 void 1871 g_hrule(int, char**) 1872 { 1873 Bprint(&bout, "<HR>\n"); 1874 } 1875 1876 void 1877 g_BX(int argc, char **argv) 1878 { 1879 Bprint(&bout, "<HR>\n"); 1880 printargs(argc, argv); 1881 Bprint(&bout, "<HR>\n"); 1882 } 1883 1884 void 1885 g_IH(int, char**) 1886 { 1887 Bprint(&bout, "Bell Laboratories, Naperville, Illinois, 60540\n"); 1888 } 1889 1890 void 1891 g_MH(int, char**) 1892 { 1893 Bprint(&bout, "Bell Laboratories, Murray Hill, NJ, 07974\n"); 1894 } 1895 1896 void 1897 g_PY(int, char**) 1898 { 1899 Bprint(&bout, "Bell Laboratories, Piscataway, NJ, 08854\n"); 1900 } 1901 1902 void 1903 g_HO(int, char**) 1904 { 1905 Bprint(&bout, "Bell Laboratories, Holmdel, NJ, 07733\n"); 1906 } 1907 1908 void 1909 g_QS(int, char**) 1910 { 1911 Bprint(&bout, "<BLOCKQUOTE>\n"); 1912 } 1913 1914 void 1915 g_QE(int, char**) 1916 { 1917 Bprint(&bout, "</BLOCKQUOTE>\n"); 1918 } 1919 1920 void 1921 g_RS(int, char**) 1922 { 1923 Bprint(&bout, "<DL><DD>\n"); 1924 } 1925 1926 void 1927 g_RE(int, char**) 1928 { 1929 Bprint(&bout, "</DL>\n"); 1930 } 1931 1932 int gif; 1933 1934 void 1935 g_startgif(int, char **argv) 1936 { 1937 int fd; 1938 int pfd[2]; 1939 char *e, *p; 1940 char name[32]; 1941 Dir d; 1942 1943 if(strcmp(argv[0], "EQ") == 0) 1944 e = ".EN"; 1945 else if(strcmp(argv[0], "TS") == 0) 1946 e = ".TE"; 1947 else if(strcmp(argv[0], "PS") == 0) 1948 e = ".PE"; 1949 else 1950 return; 1951 1952 p = strrchr(sstack[0].filename, '/'); 1953 if(p != nil) 1954 p++; 1955 else 1956 p = sstack[0].filename; 1957 snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); 1958 fd = create(name, OWRITE, 0664); 1959 if(fd < 0){ 1960 fprint(2, "ms2html: can't create %s: %r\n", name); 1961 return; 1962 } 1963 1964 if(pipe(pfd) < 0){ 1965 fprint(2, "ms2html: can't create pipe: %r\n"); 1966 close(fd); 1967 return; 1968 } 1969 switch(rfork(RFFDG|RFPROC)){ 1970 case -1: 1971 fprint(2, "ms2html: can't fork: %r\n"); 1972 close(fd); 1973 return; 1974 case 0: 1975 dup(fd, 1); 1976 close(fd); 1977 dup(pfd[0], 0); 1978 close(pfd[0]); 1979 close(pfd[1]); 1980 execl("/bin/troff2gif", "troff2gif", 0); 1981 fprint(2, "ms2html: couldn't exec troff2gif: %r\n"); 1982 _exits(nil); 1983 default: 1984 close(fd); 1985 close(pfd[0]); 1986 fprint(pfd[1], ".ll 7i\n"); 1987 for(;;){ 1988 p = Brdline(&ssp->in, '\n'); 1989 if(p == nil) 1990 break; 1991 ssp->lno++; 1992 ssp->rlno++; 1993 if(strncmp(p, e, 3) == 0) 1994 break; 1995 if(write(pfd[1], p, Blinelen(&ssp->in)) < 0) 1996 break; 1997 } 1998 close(pfd[1]); 1999 wait(nil); 2000 if(dirstat(name, &d) < 0) 2001 break; 2002 if(d.length == 0){ 2003 remove(name); 2004 break; 2005 } 2006 fprint(2, "ms2html: created auxiliary file %s\n", name); 2007 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2008 break; 2009 } 2010 } 2011 2012 void 2013 g_lf(int argc, char **argv) 2014 { 2015 if(argc > 2) 2016 snprint(ssp->filename, sizeof(ssp->filename), argv[2]); 2017 if(argc > 1) 2018 ssp->rlno = atoi(argv[1]); 2019 } 2020 2021 void 2022 g_so(int argc, char **argv) 2023 { 2024 ssp->lno++; 2025 ssp->rlno++; 2026 if(argc > 1) 2027 pushsrc(argv[1]); 2028 } 2029 2030 2031 void 2032 g_BP(int argc, char **argv) 2033 { 2034 int fd; 2035 char *p, *ext; 2036 char name[32]; 2037 Dir d; 2038 2039 if(argc < 2) 2040 return; 2041 2042 p = strrchr(argv[1], '/'); 2043 if(p != nil) 2044 p++; 2045 else 2046 p = argv[1]; 2047 2048 2049 ext = strrchr(p, '.'); 2050 if(ext){ 2051 if(strcmp(ext, ".jpeg") == 0 2052 || strcmp(ext, ".gif") == 0){ 2053 Bprint(&bout, "<br><img src=\"%s\"><br>\n", argv[1]); 2054 return; 2055 } 2056 } 2057 2058 2059 snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); 2060 fd = create(name, OWRITE, 0664); 2061 if(fd < 0){ 2062 fprint(2, "ms2html: can't create %s: %r\n", name); 2063 return; 2064 } 2065 2066 switch(rfork(RFFDG|RFPROC)){ 2067 case -1: 2068 fprint(2, "ms2html: can't fork: %r\n"); 2069 close(fd); 2070 return; 2071 case 0: 2072 dup(fd, 1); 2073 close(fd); 2074 execl("/bin/ps2gif", "ps2gif", argv[1], 0); 2075 fprint(2, "ms2html: couldn't exec ps2gif: %r\n"); 2076 _exits(nil); 2077 default: 2078 close(fd); 2079 wait(nil); 2080 if(dirstat(name, &d) < 0) 2081 break; 2082 if(d.length == 0){ 2083 remove(name); 2084 break; 2085 } 2086 fprint(2, "ms2html: created auxiliary file %s\n", name); 2087 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2088 break; 2089 } 2090 } 2091 2092 /* insert straight HTML into output */ 2093 void 2094 g__H(int argc, char **argv) 2095 { 2096 int i; 2097 2098 for(i = 1; i < argc; i++) 2099 Bprint(&bout, "%s ", argv[i]); 2100 Bprint(&bout, "\n"); 2101 } 2102 2103 /* HTML page title */ 2104 void 2105 g__T(int argc, char **argv) 2106 { 2107 if(titleseen) 2108 return; 2109 2110 Bprint(&bout, "<title>\n"); 2111 printargs(argc, argv); 2112 Bprint(&bout, "</title></head><body>\n"); 2113 titleseen = 1; 2114 } 2115 2116 void 2117 g_nr(int argc, char **argv) 2118 { 2119 char *val; 2120 2121 if (argc > 1) { 2122 if (argc == 2) 2123 val = "0"; 2124 else 2125 val = argv[2]; 2126 dsnr(argv[1], val, &numregs); 2127 } 2128 } 2129 2130 void 2131 zerodivide(void) 2132 { 2133 fprint(2, "stdin %d(%s:%d): division by 0\n", 2134 ssp->lno, ssp->filename, ssp->rlno); 2135 } 2136 2137 int 2138 numval(char **pline, int recur) 2139 { 2140 char *p; 2141 int neg, x, y; 2142 2143 x = neg = 0; 2144 p = *pline; 2145 while(*p == '-') { 2146 neg = 1 - neg; 2147 p++; 2148 } 2149 if (*p == '(') { 2150 p++; 2151 x = numval(&p, 1); 2152 if (*p != ')') 2153 goto done; 2154 p++; 2155 } 2156 else while(*p >= '0' && *p <= '9') 2157 x = 10*x + *p++ - '0'; 2158 if (neg) 2159 x = -x; 2160 if (recur) 2161 for(;;) { 2162 switch(*p++) { 2163 case '+': 2164 x += numval(&p, 0); 2165 continue; 2166 case '-': 2167 x -= numval(&p, 0); 2168 continue; 2169 case '*': 2170 x *= numval(&p, 0); 2171 continue; 2172 case '/': 2173 y = numval(&p, 0); 2174 if (y == 0) { 2175 zerodivide(); 2176 x = 0; 2177 goto done; 2178 } 2179 x /= y; 2180 continue; 2181 case '<': 2182 if (*p == '=') { 2183 p++; 2184 x = x <= numval(&p, 0); 2185 continue; 2186 } 2187 x = x < numval(&p, 0); 2188 continue; 2189 case '>': 2190 if (*p == '=') { 2191 p++; 2192 x = x >= numval(&p, 0); 2193 continue; 2194 } 2195 x = x > numval(&p, 0); 2196 continue; 2197 case '=': 2198 if (*p == '=') 2199 p++; 2200 x = x == numval(&p, 0); 2201 continue; 2202 case '&': 2203 x &= numval(&p, 0); 2204 continue; 2205 case ':': 2206 x |= numval(&p, 0); 2207 continue; 2208 case '%': 2209 y = numval(&p, 0); 2210 if (!y) { 2211 zerodivide(); 2212 goto done; 2213 } 2214 x %= y; 2215 continue; 2216 } 2217 --p; 2218 break; 2219 } 2220 done: 2221 *pline = p; 2222 return x; 2223 } 2224 2225 int 2226 iftest(char *p, char **bp) 2227 { 2228 char *p1; 2229 int c, neg, rv; 2230 2231 rv = neg = 0; 2232 if (*p == '!') { 2233 neg = 1; 2234 p++; 2235 } 2236 c = *p; 2237 if (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '('/*)*/) { 2238 if (numval(&p,1) >= 1) 2239 rv = 1; 2240 goto done; 2241 } 2242 switch(c) { 2243 case 't': 2244 case 'o': 2245 rv = 1; 2246 case 'n': 2247 case 'e': 2248 p++; 2249 goto done; 2250 } 2251 for(p1 = ++p; *p != c; p++) 2252 if (!*p) 2253 goto done; 2254 for(p++;;) { 2255 if (*p != *p1++) { 2256 while(*p && *p++ != c); 2257 goto done; 2258 } 2259 if (*p++ == c) 2260 break; 2261 } 2262 rv = 1; 2263 done: 2264 if (neg) 2265 rv = 1 - rv; 2266 while(*p == ' ' || *p == '\t') 2267 p++; 2268 *bp = p; 2269 return rv; 2270 } 2271 2272 void 2273 scanline(char *p, char *e, int wantnl) 2274 { 2275 int c; 2276 Rune r; 2277 2278 while((c = getrune()) == ' ' || c == '\t') ; 2279 while(p < e) { 2280 if (c < 0) 2281 break; 2282 if (c < Runeself) { 2283 if (c == '\n') { 2284 if (wantnl) 2285 *p++ = c; 2286 break; 2287 } 2288 *p++ = c; 2289 } 2290 else { 2291 r = c; 2292 p += runetochar(p, &r); 2293 } 2294 c = getrune(); 2295 } 2296 *p = 0; 2297 } 2298 2299 void 2300 pushbody(char *line) 2301 { 2302 char *b; 2303 2304 if (line[0] == '\\' && line[1] == '{' /*}*/ ) 2305 line += 2; 2306 if (strsp < Maxmstack - 1) { 2307 pushstr(b = strdup(line)); 2308 mustfree[strsp] = b; 2309 } 2310 } 2311 2312 void 2313 skipbody(char *line) 2314 { 2315 int c, n; 2316 2317 if (line[0] != '\\' || line[1] != '{' /*}*/ ) 2318 return; 2319 for(n = 1;;) { 2320 while((c = getrune()) != '\\') 2321 if (c < 0) 2322 return; 2323 c = getrune(); 2324 if (c == '{') 2325 n++; 2326 else if ((c == '}' && (c = getrune()) == '\n' && !--n) 2327 || c < 0) 2328 return; 2329 } 2330 } 2331 2332 int 2333 ifstart(char *line, char *e, char **bp) 2334 { 2335 int it; 2336 char *b; 2337 2338 b = copyline(line, e, 1); 2339 ungetrune(); 2340 b[-1] = getrune(); 2341 scanline(b, e, 1); 2342 it = iftest(line, bp); 2343 return it; 2344 } 2345 2346 void 2347 g_ie(char *line, char *e) 2348 { 2349 char *b; 2350 2351 if (elsetop >= Maxif-1) { 2352 fprint(2, "ms2html: .ie's too deep\n"); 2353 return; 2354 } 2355 if (ifwastrue[++elsetop] = ifstart(line, e, &b)) 2356 pushbody(b); 2357 else 2358 skipbody(b); 2359 } 2360 2361 void 2362 g_if(char *line, char *e) 2363 { 2364 char *b; 2365 2366 if (ifstart(line, e, &b)) 2367 pushbody(b); 2368 else 2369 skipbody(b); 2370 } 2371 2372 void 2373 g_el(char *line, char *e) 2374 { 2375 if (elsetop < 0) 2376 return; 2377 scanline(line, e, 1); 2378 if (ifwastrue[elsetop--]) 2379 skipbody(line); 2380 else 2381 pushbody(line); 2382 } 2383 2384 void 2385 g_ig(int argc, char **argv) 2386 { 2387 char *p, *s; 2388 2389 s = ".."; 2390 if (argc > 1) 2391 s = argv[1]; 2392 for(;;) { 2393 p = Brdline(&ssp->in, '\n'); 2394 if(p == nil) 2395 break; 2396 p[Blinelen(&ssp->in)-1] = 0; 2397 if(strcmp(p, s) == 0) 2398 break; 2399 } 2400 } 2401 2402 void 2403 g_ds(char *line, char *e) 2404 { 2405 char *b; 2406 2407 b = copyline(line, e, 1); 2408 if (b > line) { 2409 copyline(b, e, 0); 2410 if (*b == '"') 2411 b++; 2412 ds(line, b); 2413 } 2414 } 2415 2416 void 2417 g_as(char *line, char *e) 2418 { 2419 String *s; 2420 char *b; 2421 2422 b = copyline(line, e, 1); 2423 if (b == line) 2424 return; 2425 copyline(b, e, 0); 2426 if (*b == '"') 2427 b++; 2428 for(s = strings; s != nil; s = s->next) 2429 if(strcmp(line, s->name) == 0) 2430 break; 2431 2432 if(s == nil){ 2433 ds(line, b); 2434 return; 2435 } 2436 2437 s->val = realloc(s->val, strlen(s->val) + strlen(b) + 1); 2438 strcat(s->val, b); 2439 } 2440 2441 void 2442 g_BS(int argc, char **argv) 2443 { 2444 int i; 2445 2446 if (argc > 1 && !weBref) { 2447 Bprint(&bout, "<a href=\"%s\"", argv[1]); 2448 for(i = 2; i < argc; i++) 2449 Bprint(&bout, " %s", argv[i]); 2450 Bprint(&bout, ">"); 2451 weBref = 1; 2452 } 2453 } 2454 2455 void 2456 g_BE(int, char**) 2457 { 2458 if (weBref) { 2459 Bprint(&bout, "</a>"); 2460 weBref = 0; 2461 } 2462 } 2463 2464 void 2465 g_LB(int argc, char **argv) 2466 { 2467 if (argc > 1) { 2468 if (weBref) 2469 g_BE(0,nil); 2470 Bprint(&bout, "<a name=\"%s\"></a>", argv[1]); 2471 } 2472 } 2473 2474 void 2475 g_RT(int, char**) 2476 { 2477 g_BE(0,nil); 2478 dohanginghead(); 2479 closel(); 2480 closefont(); 2481 } 2482