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