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