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 do { 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 } while(r < 0); 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 break; 896 897 /* font change */ 898 case 'f': 899 r = getrune(); 900 switch(r){ 901 case '(': 902 str[0] = getrune(); 903 str[1] = getrune(); 904 str[2] = 0; 905 token[0] = 0; 906 if(strcmp("BI", str) == 0) 907 return changefont(&bifont); 908 else if(strcmp("CW", str) == 0) 909 return changefont(&cwfont); 910 else 911 return changefont(nil); 912 case '3': 913 case 'B': 914 return changefont(&bfont); 915 case '2': 916 case 'I': 917 return changefont(&ifont); 918 case '4': 919 return changefont(&bifont); 920 case '5': 921 return changefont(&cwfont); 922 case 'P': 923 return changebackfont(); 924 case 'R': 925 default: 926 return changefont(nil); 927 } 928 929 /* number register */ 930 case 'n': 931 r = getrune(); 932 if (r == '(') /*)*/ { 933 r = getrune(); 934 if (r < 0) 935 return nil; 936 str[0] = r; 937 r = getrune(); 938 if (r < 0) 939 return nil; 940 str[1] = r; 941 str[2] = 0; 942 } 943 else { 944 str[0] = r; 945 str[1] = 0; 946 } 947 pushstr(getnr(str)); 948 return getnext(); 949 950 /* font size */ 951 case 's': 952 r = getrune(); 953 switch(r){ 954 case '0': 955 return changesize(0); 956 case '-': 957 r = getrune(); 958 if (!isdigit(r)) 959 return getnext(); 960 return changesize(-(r - '0')); 961 case '+': 962 r = getrune(); 963 if (!isdigit(r)) 964 return getnext(); 965 return changesize(r - '0'); 966 } 967 return getnext(); 968 /* vertical movement */ 969 case 'v': 970 r = getrune(); 971 if(r != '\''){ 972 ungetrune(); 973 return getnext(); 974 } 975 r = getrune(); 976 if(r != '-') 977 vert--; 978 else 979 vert++; 980 while(r != '\'' && r != '\n') 981 r = getrune(); 982 if(r != '\'') 983 ungetrune(); 984 985 if(vert > 0) 986 return "^"; 987 return getnext(); 988 989 990 /* horizontal line */ 991 case 'l': 992 r = getrune(); 993 if(r != '\''){ 994 ungetrune(); 995 return "<HR>"; 996 } 997 while(getrune() != '\'') 998 ; 999 return "<HR>"; 1000 1001 /* character height and slant */ 1002 case 'S': 1003 case 'H': 1004 r = getrune(); 1005 if(r != '\''){ 1006 ungetrune(); 1007 return "<HR>"; 1008 } 1009 while(getrune() != '\'') 1010 ; 1011 return getnext(); 1012 1013 /* digit-width space */ 1014 case '0': 1015 return " "; 1016 1017 /*for .if, .ie, .el */ 1018 case '{': 1019 return "\\{"; /*}*/ 1020 case '}': 1021 return ""; 1022 /* up and down */ 1023 case 'u': 1024 if (isdown) { 1025 isdown = 0; 1026 return "</sub>"; 1027 } 1028 isup = 1; 1029 return "<sup>"; 1030 case 'd': 1031 if (isup) { 1032 isup = 0; 1033 return "</sup>"; 1034 } 1035 isdown = 1; 1036 return "<sub>"; 1037 } 1038 break; 1039 case '&': 1040 if(msp >= 0 || strsp >= 0) 1041 return "&"; 1042 return "&"; 1043 case '<': 1044 if(msp >= 0 || strsp >= 0) 1045 return "<"; 1046 return "<"; 1047 case '>': 1048 if(msp >= 0 || strsp >= 0) 1049 return ">"; 1050 return ">"; 1051 } 1052 if (r < Runeself) { 1053 token[0] = r; 1054 token[1] = 0; 1055 } 1056 else { 1057 R = r; 1058 token[runetochar(token,&R)] = 0; 1059 } 1060 return token; 1061 } 1062 1063 /* if arg0 is set, read up to (and expand) to the next whitespace, else to the end of line */ 1064 char* 1065 copyline(char *p, char *e, int arg0) 1066 { 1067 int c; 1068 Rune r; 1069 char *p1; 1070 1071 while((c = getrune()) == ' ' || c == '\t') 1072 ; 1073 for(indirective = 1; p < e; c = getrune()) { 1074 if (c < 0) 1075 goto done; 1076 switch(c) { 1077 case '\\': 1078 break; 1079 case '\n': 1080 if (arg0) 1081 ungetrune(); 1082 goto done; 1083 case ' ': 1084 case '\t': 1085 if (arg0) 1086 goto done; 1087 default: 1088 r = c; 1089 p += runetochar(p,&r); 1090 continue; 1091 } 1092 ungetrune(); 1093 p1 = getnext(); 1094 if (p1 == nil) 1095 goto done; 1096 if (*p1 == '\n') { 1097 if (arg0) 1098 ungetrune(); 1099 break; 1100 } 1101 while((*p = *p1++) && p < e) 1102 p++; 1103 } 1104 done: 1105 indirective = 0; 1106 *p++ = 0; 1107 return p; 1108 } 1109 1110 char* 1111 copyarg(char *p, char *e, int *nullarg) 1112 { 1113 int c, quoted, last; 1114 Rune r; 1115 1116 *nullarg = 0; 1117 quoted = 0; 1118 do{ 1119 c = getrune(); 1120 } while(c == ' ' || c == '\t'); 1121 1122 if(c == '"'){ 1123 quoted = 1; 1124 *nullarg = 1; 1125 c = getrune(); 1126 } 1127 1128 if(c == '\n') 1129 goto done; 1130 1131 last = 0; 1132 for(; p < e; c = getrune()) { 1133 if (c < 0) 1134 break; 1135 switch(c) { 1136 case '\n': 1137 ungetrune(); 1138 goto done; 1139 case '\\': 1140 r = c; 1141 p += runetochar(p,&r); 1142 if(last == '\\') 1143 r = 0; 1144 break; 1145 case ' ': 1146 case '\t': 1147 if(!quoted && last != '\\') 1148 goto done; 1149 r = c; 1150 p += runetochar(p,&r); 1151 break; 1152 case '"': 1153 if(quoted && last != '\\') 1154 goto done; 1155 r = c; 1156 p += runetochar(p,&r); 1157 break; 1158 default: 1159 r = c; 1160 p += runetochar(p,&r); 1161 break; 1162 } 1163 last = r; 1164 } 1165 done: 1166 *p++ = 0; 1167 return p; 1168 1169 } 1170 1171 int 1172 parseargs(char *p, char *e, char **argv) 1173 { 1174 int argc; 1175 char *np; 1176 int nullarg; 1177 1178 indirective = 1; 1179 *p++ = 0; 1180 for(argc = 1; argc < Narg; argc++){ 1181 np = copyarg(p, e, &nullarg); 1182 if(nullarg==0 && np == p+1) 1183 break; 1184 argv[argc] = p; 1185 p = np; 1186 } 1187 argv[argc] = nil; 1188 indirective = 0; 1189 1190 1191 return argc; 1192 } 1193 1194 void 1195 dodirective(void) 1196 { 1197 char *p, *e; 1198 Goobie *g; 1199 Goobieif *gif; 1200 char line[Nline], *line1; 1201 int i, argc; 1202 char *argv[Narg]; 1203 Mstack *m; 1204 1205 /* read line, translate special bytes */ 1206 e = line + sizeof(line) - UTFmax - 1; 1207 line1 = copyline(line, e, 1); 1208 if (!line[0]) 1209 return; 1210 argv[0] = line; 1211 1212 /* first look through user defined macros */ 1213 p = getmacro(argv[0]); 1214 if(p != nil){ 1215 if(msp == Maxmstack-1){ 1216 fprint(2, "ms2html: macro stack overflow\n"); 1217 return; 1218 } 1219 argc = parseargs(line1, e, argv); 1220 m = &mstack[++msp]; 1221 m->ptr = p; 1222 memset(m->argv, 0, sizeof(m->argv)); 1223 for(i = 0; i < argc; i++) 1224 m->argv[i] = strdup(argv[i]); 1225 return; 1226 } 1227 1228 /* check for .if or .ie */ 1229 for(gif = gtabif; gif->name; gif++) 1230 if(strcmp(gif->name, argv[0]) == 0){ 1231 (*gif->f)(line1, e); 1232 return; 1233 } 1234 1235 argc = parseargs(line1, e, argv); 1236 1237 /* try standard ms macros */ 1238 for(g = gtab; g->name; g++) 1239 if(strcmp(g->name, argv[0]) == 0){ 1240 (*g->f)(argc, argv); 1241 return; 1242 } 1243 1244 if(debug) 1245 fprint(2, "stdin %d(%s:%d): unknown directive %s\n", 1246 ssp->lno, ssp->filename, ssp->rlno, line); 1247 } 1248 1249 void 1250 printarg(char *a) 1251 { 1252 char *e, *p; 1253 1254 e = a + strlen(a); 1255 pushstr(a); 1256 while(strsp >= 0 && strstack[strsp] >= a && strstack[strsp] < e){ 1257 p = getnext(); 1258 if(p == nil) 1259 return; 1260 Bprint(&bout, "%s", p); 1261 } 1262 } 1263 1264 void 1265 printargs(int argc, char **argv) 1266 { 1267 argc--; 1268 argv++; 1269 while(--argc > 0){ 1270 printarg(*argv++); 1271 Bprint(&bout, " "); 1272 } 1273 if(argc == 0) 1274 printarg(*argv); 1275 } 1276 1277 void 1278 dohangingdt(void) 1279 { 1280 switch(hangingdt){ 1281 case 3: 1282 hangingdt--; 1283 break; 1284 case 2: 1285 Bprint(&bout, "<dd>"); 1286 hangingdt = 0; 1287 break; 1288 } 1289 1290 } 1291 1292 void 1293 dohangingau(void) 1294 { 1295 if(hangingau == 0) 1296 return; 1297 Bprint(&bout, "</I></DL>\n"); 1298 hangingau = 0; 1299 } 1300 1301 void 1302 dohanginghead(void) 1303 { 1304 if(hanginghead == 0) 1305 return; 1306 Bprint(&bout, "</H%d>\n", hanginghead); 1307 hanginghead = 0; 1308 } 1309 1310 /* 1311 * convert a man page to html and output 1312 */ 1313 void 1314 doconvert(void) 1315 { 1316 char c, *p; 1317 Tm *t; 1318 1319 pushsrc(nil); 1320 1321 sol = 1; 1322 Bprint(&bout, "<html>\n"); 1323 Bflush(&bout); 1324 for(;;){ 1325 p = getnext(); 1326 if(p == nil) 1327 break; 1328 c = *p; 1329 if(c == '.' && sol){ 1330 dodirective(); 1331 dohangingdt(); 1332 ssp->lno++; 1333 ssp->rlno++; 1334 sol = 1; 1335 } else if(c == '\n'){ 1336 if (ignore_nl) 1337 ignore_nl = 0; 1338 else { 1339 if(hangingau) 1340 Bprint(&bout, "<br>\n"); 1341 else 1342 Bprint(&bout, "%s", p); 1343 dohangingdt(); 1344 } 1345 ssp->lno++; 1346 ssp->rlno++; 1347 sol = 1; 1348 } else{ 1349 Bprint(&bout, "%s", p); 1350 ignore_nl = sol = 0; 1351 } 1352 } 1353 dohanginghead(); 1354 dohangingdt(); 1355 closel(); 1356 if(fsp >= 0 && fstack[fsp]) 1357 Bprint(&bout, "%s", fstack[fsp]->end); 1358 Bprint(&bout, "<br> <br>\n"); 1359 Bprint(&bout, "<A href=http://www.lucent.com/copyright.html>\n"); 1360 t = localtime(time(nil)); 1361 Bprint(&bout, "Copyright</A> © %d Lucent Technologies Inc. All rights reserved.\n", 1362 t->year+1900); 1363 Bprint(&bout, "</body></html>\n"); 1364 } 1365 1366 static void 1367 usage(void) 1368 { 1369 sysfatal("usage: ms2html [-q] [-b basename] [-d '$$'] [-t title]\n"); 1370 } 1371 1372 void 1373 main(int argc, char **argv) 1374 { 1375 quiet = 1; 1376 ARGBEGIN { 1377 case 't': 1378 title = EARGF(usage()); 1379 break; 1380 case 'b': 1381 basename = EARGF(usage()); 1382 break; 1383 case 'q': 1384 quiet = 0; 1385 break; 1386 case 'd': 1387 delim = EARGF(usage()); 1388 break; 1389 case '?': 1390 default: 1391 usage(); 1392 } ARGEND; 1393 1394 Binit(&bout, 1, OWRITE); 1395 1396 ds("R", "®"); 1397 1398 doconvert(); 1399 exits(nil); 1400 } 1401 1402 void 1403 g_notyet(int, char **argv) 1404 { 1405 fprint(2, "ms2html: .%s not yet supported\n", argv[0]); 1406 } 1407 1408 void 1409 g_ignore(int, char **argv) 1410 { 1411 if(quiet) 1412 return; 1413 fprint(2, "ms2html: line %d: ignoring .%s\n", ssp->lno, argv[0]); 1414 } 1415 1416 void 1417 g_PP(int, char**) 1418 { 1419 dohanginghead(); 1420 closel(); 1421 closefont(); 1422 Bprint(&bout, "<P>\n"); 1423 paragraph = 1; 1424 } 1425 1426 void 1427 g_LP(int, char**) 1428 { 1429 dohanginghead(); 1430 closel(); 1431 closefont(); 1432 Bprint(&bout, "<br> <br>\n"); 1433 } 1434 1435 /* close a list */ 1436 void 1437 closel(void) 1438 { 1439 g_P2(1, nil); 1440 dohangingau(); 1441 if(paragraph){ 1442 Bprint(&bout, "</P>\n"); 1443 paragraph = 0; 1444 } 1445 switch(list){ 1446 case Lordered: 1447 Bprint(&bout, "</ol>\n"); 1448 break; 1449 case Lunordered: 1450 Bprint(&bout, "</ul>\n"); 1451 break; 1452 case Lother: 1453 case Ldef: 1454 Bprint(&bout, "</dl>\n"); 1455 break; 1456 } 1457 list = 0; 1458 1459 } 1460 1461 1462 void 1463 g_IP(int argc, char **argv) 1464 { 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 dohangingcenter(); 1608 if(argc == 1) 1609 level = 0; 1610 else { 1611 level = atoi(argv[1])-1; 1612 if(level < 0 || level >= Maxnh) 1613 level = Maxnh - 1; 1614 } 1615 nh[level]++; 1616 1617 Bprint(&bout, "<H%d>", HH); 1618 hanginghead = HH; 1619 1620 Bprint(&bout, "%d", nh[0]); 1621 for(i = 1; i <= level; i++) 1622 Bprint(&bout, ".%d", nh[i]); 1623 Bprint(&bout, " "); 1624 1625 for(i = level+1; i < Maxnh; i++) 1626 nh[i] = 0; 1627 } 1628 1629 void 1630 g_TL(int, char**) 1631 { 1632 char *p, *np; 1633 char name[128]; 1634 1635 closefont(); 1636 1637 if(!titleseen){ 1638 if(!title){ 1639 /* get base part of filename */ 1640 p = strrchr(ssp->filename, '/'); 1641 if(p == nil) 1642 p = ssp->filename; 1643 else 1644 p++; 1645 strncpy(name, p, sizeof(name)); 1646 name[sizeof(name)-1] = 0; 1647 1648 /* dump any extensions */ 1649 np = strchr(name, '.'); 1650 if(np) 1651 *np = 0; 1652 title = p; 1653 } 1654 Bprint(&bout, "<title>\n"); 1655 Bprint(&bout, "%s\n", title); 1656 Bprint(&bout, "</title>\n"); 1657 Bprint(&bout, "<body BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#330088\" ALINK=\"#FF0044\">\n"); 1658 titleseen = 1; 1659 } 1660 1661 Bprint(&bout, "<center>"); 1662 hangingcenter = 1; 1663 Bprint(&bout, "<H%d>", 1); 1664 hanginghead = 1; 1665 } 1666 1667 void 1668 dohangingcenter(void) 1669 { 1670 if(hangingcenter){ 1671 Bprint(&bout, "</center>"); 1672 hangingcenter = 1; 1673 } 1674 } 1675 1676 void 1677 g_AU(int, char**) 1678 { 1679 closel(); 1680 dohanginghead(); 1681 Bprint(&bout, "<DL><DD><I>"); 1682 hangingau = 1; 1683 } 1684 1685 void 1686 pushfont(Font *f) 1687 { 1688 if(fsp == Maxfsp) 1689 return; 1690 if(fsp >= 0 && fstack[fsp]) 1691 Bprint(&bout, "%s", fstack[fsp]->end); 1692 if(f != nil) 1693 Bprint(&bout, "%s", f->start); 1694 fstack[++fsp] = f; 1695 } 1696 1697 void 1698 popfont(void) 1699 { 1700 if(fsp >= 0){ 1701 if(fstack[fsp]) 1702 Bprint(&bout, "%s", fstack[fsp]->end); 1703 fsp--; 1704 } 1705 } 1706 1707 /* 1708 * for 3 args print arg3 \fxarg1\fP arg2 1709 * for 2 args print arg1 \fxarg2\fP 1710 * for 1 args print \fxarg1\fP 1711 */ 1712 void 1713 font(Font *f, int argc, char **argv) 1714 { 1715 if(argc == 1){ 1716 pushfont(nil); 1717 return; 1718 } 1719 if(argc > 3) 1720 printarg(argv[3]); 1721 pushfont(f); 1722 printarg(argv[1]); 1723 popfont(); 1724 if(argc > 2) 1725 printarg(argv[2]); 1726 Bprint(&bout, "\n"); 1727 } 1728 1729 void 1730 closefont(void) 1731 { 1732 if(fsp >= 0 && fstack[fsp]) 1733 Bprint(&bout, "%s", fstack[fsp]->end); 1734 fsp = -1; 1735 } 1736 1737 void 1738 g_B(int argc, char **argv) 1739 { 1740 font(&bfont, argc, argv); 1741 } 1742 1743 void 1744 g_R(int argc, char **argv) 1745 { 1746 font(nil, argc, argv); 1747 } 1748 1749 void 1750 g_BI(int argc, char **argv) 1751 { 1752 font(&bifont, argc, argv); 1753 } 1754 1755 void 1756 g_CW(int argc, char **argv) 1757 { 1758 font(&cwfont, argc, argv); 1759 } 1760 1761 char* 1762 lower(char *p) 1763 { 1764 char *x; 1765 1766 for(x = p; *x; x++) 1767 if(*x >= 'A' && *x <= 'Z') 1768 *x -= 'A' - 'a'; 1769 return p; 1770 } 1771 1772 void 1773 g_I(int argc, char **argv) 1774 { 1775 int anchor; 1776 char *p; 1777 1778 anchor = 0; 1779 if(argc > 2){ 1780 p = argv[2]; 1781 if(p[0] == '(') 1782 if(p[1] >= '0' && p[1] <= '9') 1783 if(p[2] == ')'){ 1784 anchor = 1; 1785 Bprint(&bout, "<A href=\"/magic/man2html/%c/%s\">", 1786 p[1], lower(argv[1])); 1787 } 1788 } 1789 font(&ifont, argc, argv); 1790 if(anchor) 1791 Bprint(&bout, "</A>"); 1792 } 1793 1794 void 1795 g_br(int, char**) 1796 { 1797 if(hangingdt){ 1798 Bprint(&bout, "<dd>"); 1799 hangingdt = 0; 1800 }else 1801 Bprint(&bout, "<br>\n"); 1802 } 1803 1804 void 1805 g_P1(int, char**) 1806 { 1807 if(example == 0){ 1808 example = 1; 1809 Bprint(&bout, "<DL><DT><DD><TT><PRE>\n"); 1810 } 1811 } 1812 1813 void 1814 g_P2(int, char**) 1815 { 1816 if(example){ 1817 example = 0; 1818 Bprint(&bout, "</PRE></TT></DL>\n"); 1819 } 1820 } 1821 1822 void 1823 g_SM(int, char **argv) 1824 { 1825 Bprint(&bout, "%s", argv[1]); 1826 } 1827 1828 void 1829 g_ft(int argc, char **argv) 1830 { 1831 if(argc < 2){ 1832 pushfont(nil); 1833 return; 1834 } 1835 1836 switch(argv[1][0]){ 1837 case '3': 1838 case 'B': 1839 pushfont(&bfont); 1840 break; 1841 case '2': 1842 case 'I': 1843 pushfont(&ifont); 1844 break; 1845 case '4': 1846 pushfont(&bifont); 1847 break; 1848 case '5': 1849 pushfont(&cwfont); 1850 break; 1851 case 'P': 1852 popfont(); 1853 break; 1854 case 'R': 1855 default: 1856 pushfont(nil); 1857 break; 1858 } 1859 } 1860 1861 void 1862 g_sp(int argc, char **argv) 1863 { 1864 int n; 1865 1866 n = 1; 1867 if(argc > 1){ 1868 n = atoi(argv[1]); 1869 if(n < 1) 1870 n = 1; 1871 if(argv[1][strlen(argv[1])-1] == 'i') 1872 n *= 4; 1873 } 1874 if(n > 5){ 1875 Bprint(&bout, "<br> <br>\n"); 1876 Bprint(&bout, "<HR>\n"); 1877 Bprint(&bout, "<br> <br>\n"); 1878 } else 1879 for(; n > 0; n--) 1880 Bprint(&bout, "<br> <br>\n"); 1881 } 1882 1883 void 1884 rm_loop(char *name, String **l) 1885 { 1886 String *s; 1887 for(s = *l; s != nil; s = *l){ 1888 if(strcmp(name, s->name) == 0){ 1889 *l = s->next; 1890 free(s->name); 1891 free(s->val); 1892 free(s); 1893 break; 1894 } 1895 l = &s->next; 1896 } 1897 } 1898 1899 void 1900 g_rm(int argc, char **argv) 1901 { 1902 Goobie *g; 1903 char *name; 1904 int i; 1905 1906 for(i = 1; i < argc; i++) { 1907 name = argv[i]; 1908 rm_loop(name, &strings); 1909 rm_loop(name, ¯os); 1910 for(g = gtab; g->name; g++) 1911 if (strcmp(g->name, name) == 0) { 1912 g->f = g_ignore; 1913 break; 1914 } 1915 } 1916 } 1917 1918 void 1919 g_AB(int, char**) 1920 { 1921 closel(); 1922 dohangingcenter(); 1923 Bprint(&bout, "<center><H4>ABSTRACT</H4></center><DL><DD>\n"); 1924 } 1925 1926 void 1927 g_AE(int, char**) 1928 { 1929 Bprint(&bout, "</DL>\n"); 1930 } 1931 1932 void 1933 g_FS(int, char **) 1934 { 1935 char *argv[3]; 1936 1937 argv[0] = "IP"; 1938 argv[1] = nil; 1939 argv[2] = nil; 1940 g_IP(1, argv); 1941 Bprint(&bout, "NOTE:<I> "); 1942 } 1943 1944 void 1945 g_FE(int, char **) 1946 { 1947 Bprint(&bout, "</I><DT> <DD>"); 1948 closel(); 1949 Bprint(&bout, "<br>\n"); 1950 } 1951 1952 void 1953 g_de(int argc, char **argv) 1954 { 1955 int r; 1956 char *p, *cp; 1957 String *m; 1958 int len; 1959 1960 if(argc < 2) 1961 return; 1962 1963 m = nil; 1964 len = 0; 1965 if(strcmp(argv[0], "am") == 0){ 1966 for(m = macros; m != nil; m = m->next) 1967 if(strcmp(argv[1], m->name) == 0){ 1968 len = strlen(m->val); 1969 break; 1970 } 1971 1972 if(m == nil){ 1973 /* nothing to append to */ 1974 for(;;){ 1975 p = Brdline(&ssp->in, '\n'); 1976 if(p == nil) 1977 break; 1978 p[Blinelen(&ssp->in)-1] = 0; 1979 if(strcmp(p, "..") == 0) 1980 break; 1981 } 1982 return; 1983 } 1984 } 1985 1986 if(m == nil){ 1987 m = emalloc(sizeof(*m)); 1988 m->next = macros; 1989 macros = m; 1990 m->name = strdup(argv[1]); 1991 m->val = nil; 1992 len = 0; 1993 } 1994 1995 /* read up to a .. removing double backslashes */ 1996 for(;;){ 1997 p = Brdline(&ssp->in, '\n'); 1998 if(p == nil) 1999 break; 2000 p[Blinelen(&ssp->in)-1] = 0; 2001 if(strcmp(p, "..") == 0) 2002 break; 2003 m->val = realloc(m->val, len + Blinelen(&ssp->in)+1); 2004 cp = m->val + len; 2005 while(*p){ 2006 r = *p++; 2007 if(r == '\\' && *p == '\\') 2008 p++; 2009 *cp++ = r; 2010 } 2011 *cp++ = '\n'; 2012 len = cp - m->val; 2013 *cp = 0; 2014 } 2015 } 2016 2017 void 2018 g_hrule(int, char**) 2019 { 2020 Bprint(&bout, "<HR>\n"); 2021 } 2022 2023 void 2024 g_BX(int argc, char **argv) 2025 { 2026 Bprint(&bout, "<HR>\n"); 2027 printargs(argc, argv); 2028 Bprint(&bout, "<HR>\n"); 2029 } 2030 2031 void 2032 g_IH(int, char**) 2033 { 2034 Bprint(&bout, "Bell Laboratories, Naperville, Illinois, 60540\n"); 2035 } 2036 2037 void 2038 g_MH(int, char**) 2039 { 2040 Bprint(&bout, "Bell Laboratories, Murray Hill, NJ, 07974\n"); 2041 } 2042 2043 void 2044 g_PY(int, char**) 2045 { 2046 Bprint(&bout, "Bell Laboratories, Piscataway, NJ, 08854\n"); 2047 } 2048 2049 void 2050 g_HO(int, char**) 2051 { 2052 Bprint(&bout, "Bell Laboratories, Holmdel, NJ, 07733\n"); 2053 } 2054 2055 void 2056 g_QS(int, char**) 2057 { 2058 Bprint(&bout, "<BLOCKQUOTE>\n"); 2059 } 2060 2061 void 2062 g_QE(int, char**) 2063 { 2064 Bprint(&bout, "</BLOCKQUOTE>\n"); 2065 } 2066 2067 void 2068 g_RS(int, char**) 2069 { 2070 Bprint(&bout, "<DL><DD>\n"); 2071 } 2072 2073 void 2074 g_RE(int, char**) 2075 { 2076 Bprint(&bout, "</DL>\n"); 2077 } 2078 2079 int gif; 2080 2081 void 2082 g_startgif(int, char **argv) 2083 { 2084 int fd; 2085 int pfd[2]; 2086 char *e, *p; 2087 char name[32]; 2088 Dir *d; 2089 2090 if(strcmp(argv[0], "EQ") == 0) 2091 e = ".EN"; 2092 else if(strcmp(argv[0], "TS") == 0) 2093 e = ".TE"; 2094 else if(strcmp(argv[0], "PS") == 0) 2095 e = ".PE"; 2096 else 2097 return; 2098 2099 if(basename) 2100 p = basename; 2101 else{ 2102 p = strrchr(sstack[0].filename, '/'); 2103 if(p != nil) 2104 p++; 2105 else 2106 p = sstack[0].filename; 2107 } 2108 snprint(name, sizeof(name), "%s.%d.gif", p, gif++); 2109 fd = create(name, OWRITE, 0664); 2110 if(fd < 0){ 2111 fprint(2, "ms2html: can't create %s: %r\n", name); 2112 return; 2113 } 2114 2115 if(pipe(pfd) < 0){ 2116 fprint(2, "ms2html: can't create pipe: %r\n"); 2117 close(fd); 2118 return; 2119 } 2120 switch(rfork(RFFDG|RFPROC)){ 2121 case -1: 2122 fprint(2, "ms2html: can't fork: %r\n"); 2123 close(fd); 2124 return; 2125 case 0: 2126 dup(fd, 1); 2127 close(fd); 2128 dup(pfd[0], 0); 2129 close(pfd[0]); 2130 close(pfd[1]); 2131 execl("/bin/troff2gif", "troff2gif", nil); 2132 fprint(2, "ms2html: couldn't exec troff2gif: %r\n"); 2133 _exits(nil); 2134 default: 2135 close(fd); 2136 close(pfd[0]); 2137 fprint(pfd[1], ".ll 7i\n"); 2138 /* fprint(pfd[1], ".EQ\ndelim %s\n.EN\n", delim); */ 2139 /* fprint(pfd[1], ".%s\n", argv[0]); */ 2140 for(;;){ 2141 p = Brdline(&ssp->in, '\n'); 2142 if(p == nil) 2143 break; 2144 ssp->lno++; 2145 ssp->rlno++; 2146 if(write(pfd[1], p, Blinelen(&ssp->in)) < 0) 2147 break; 2148 if(strncmp(p, e, 3) == 0) 2149 break; 2150 } 2151 close(pfd[1]); 2152 waitpid(); 2153 d = dirstat(name); 2154 if(d == nil) 2155 break; 2156 if(d->length == 0){ 2157 remove(name); 2158 free(d); 2159 break; 2160 } 2161 free(d); 2162 fprint(2, "ms2html: created auxiliary file %s\n", name); 2163 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2164 break; 2165 } 2166 } 2167 2168 void 2169 g_lf(int argc, char **argv) 2170 { 2171 if(argc > 2) 2172 snprint(ssp->filename, sizeof(ssp->filename), argv[2]); 2173 if(argc > 1) 2174 ssp->rlno = atoi(argv[1]); 2175 } 2176 2177 void 2178 g_so(int argc, char **argv) 2179 { 2180 ssp->lno++; 2181 ssp->rlno++; 2182 if(argc > 1) 2183 pushsrc(argv[1]); 2184 } 2185 2186 2187 void 2188 g_BP(int argc, char **argv) 2189 { 2190 int fd; 2191 char *p, *ext; 2192 char name[32]; 2193 Dir *d; 2194 2195 if(argc < 2) 2196 return; 2197 2198 p = strrchr(argv[1], '/'); 2199 if(p != nil) 2200 p++; 2201 else 2202 p = argv[1]; 2203 2204 2205 ext = strrchr(p, '.'); 2206 if(ext){ 2207 if(strcmp(ext, ".jpeg") == 0 2208 || strcmp(ext, ".gif") == 0){ 2209 Bprint(&bout, "<br><img src=\"%s\"><br>\n", argv[1]); 2210 return; 2211 } 2212 } 2213 2214 2215 snprint(name, sizeof(name), "%s.%d%d.gif", p, getpid(), gif++); 2216 fd = create(name, OWRITE, 0664); 2217 if(fd < 0){ 2218 fprint(2, "ms2html: can't create %s: %r\n", name); 2219 return; 2220 } 2221 2222 switch(rfork(RFFDG|RFPROC)){ 2223 case -1: 2224 fprint(2, "ms2html: can't fork: %r\n"); 2225 close(fd); 2226 return; 2227 case 0: 2228 dup(fd, 1); 2229 close(fd); 2230 execl("/bin/ps2gif", "ps2gif", argv[1], nil); 2231 fprint(2, "ms2html: couldn't exec ps2gif: %r\n"); 2232 _exits(nil); 2233 default: 2234 close(fd); 2235 waitpid(); 2236 d = dirstat(name); 2237 if(d == nil) 2238 break; 2239 if(d->length == 0){ 2240 remove(name); 2241 free(d); 2242 break; 2243 } 2244 free(d); 2245 fprint(2, "ms2html: created auxiliary file %s\n", name); 2246 Bprint(&bout, "<br><img src=\"%s\"><br>\n", name); 2247 break; 2248 } 2249 } 2250 2251 /* insert straight HTML into output */ 2252 void 2253 g__H(int argc, char **argv) 2254 { 2255 int i; 2256 2257 for(i = 1; i < argc; i++) 2258 Bprint(&bout, "%s ", argv[i]); 2259 Bprint(&bout, "\n"); 2260 } 2261 2262 /* HTML page title */ 2263 void 2264 g__T(int argc, char **argv) 2265 { 2266 if(titleseen) 2267 return; 2268 2269 Bprint(&bout, "<title>\n"); 2270 printargs(argc, argv); 2271 Bprint(&bout, "</title></head><body>\n"); 2272 titleseen = 1; 2273 } 2274 2275 void 2276 g_nr(int argc, char **argv) 2277 { 2278 char *val; 2279 2280 if (argc > 1) { 2281 if (argc == 2) 2282 val = "0"; 2283 else 2284 val = argv[2]; 2285 dsnr(argv[1], val, &numregs); 2286 } 2287 } 2288 2289 void 2290 zerodivide(void) 2291 { 2292 fprint(2, "stdin %d(%s:%d): division by 0\n", 2293 ssp->lno, ssp->filename, ssp->rlno); 2294 } 2295 2296 int 2297 numval(char **pline, int recur) 2298 { 2299 char *p; 2300 int neg, x, y; 2301 2302 x = neg = 0; 2303 p = *pline; 2304 while(*p == '-') { 2305 neg = 1 - neg; 2306 p++; 2307 } 2308 if (*p == '(') { 2309 p++; 2310 x = numval(&p, 1); 2311 if (*p != ')') 2312 goto done; 2313 p++; 2314 } 2315 else while(*p >= '0' && *p <= '9') 2316 x = 10*x + *p++ - '0'; 2317 if (neg) 2318 x = -x; 2319 if (recur) 2320 for(;;) { 2321 switch(*p++) { 2322 case '+': 2323 x += numval(&p, 0); 2324 continue; 2325 case '-': 2326 x -= numval(&p, 0); 2327 continue; 2328 case '*': 2329 x *= numval(&p, 0); 2330 continue; 2331 case '/': 2332 y = numval(&p, 0); 2333 if (y == 0) { 2334 zerodivide(); 2335 x = 0; 2336 goto done; 2337 } 2338 x /= y; 2339 continue; 2340 case '<': 2341 if (*p == '=') { 2342 p++; 2343 x = x <= numval(&p, 0); 2344 continue; 2345 } 2346 x = x < numval(&p, 0); 2347 continue; 2348 case '>': 2349 if (*p == '=') { 2350 p++; 2351 x = x >= numval(&p, 0); 2352 continue; 2353 } 2354 x = x > numval(&p, 0); 2355 continue; 2356 case '=': 2357 if (*p == '=') 2358 p++; 2359 x = x == numval(&p, 0); 2360 continue; 2361 case '&': 2362 x &= numval(&p, 0); 2363 continue; 2364 case ':': 2365 x |= numval(&p, 0); 2366 continue; 2367 case '%': 2368 y = numval(&p, 0); 2369 if (!y) { 2370 zerodivide(); 2371 goto done; 2372 } 2373 x %= y; 2374 continue; 2375 } 2376 --p; 2377 break; 2378 } 2379 done: 2380 *pline = p; 2381 return x; 2382 } 2383 2384 int 2385 iftest(char *p, char **bp) 2386 { 2387 char *p1; 2388 int c, neg, rv; 2389 2390 rv = neg = 0; 2391 if (*p == '!') { 2392 neg = 1; 2393 p++; 2394 } 2395 c = *p; 2396 if (c >= '0' && c <= '9' || c == '+' || c == '-' || c == '('/*)*/) { 2397 if (numval(&p,1) >= 1) 2398 rv = 1; 2399 goto done; 2400 } 2401 switch(c) { 2402 case 't': 2403 case 'o': 2404 rv = 1; 2405 case 'n': 2406 case 'e': 2407 p++; 2408 goto done; 2409 } 2410 for(p1 = ++p; *p != c; p++) 2411 if (!*p) 2412 goto done; 2413 for(p++;;) { 2414 if (*p != *p1++) { 2415 while(*p && *p++ != c); 2416 goto done; 2417 } 2418 if (*p++ == c) 2419 break; 2420 } 2421 rv = 1; 2422 done: 2423 if (neg) 2424 rv = 1 - rv; 2425 while(*p == ' ' || *p == '\t') 2426 p++; 2427 *bp = p; 2428 return rv; 2429 } 2430 2431 void 2432 scanline(char *p, char *e, int wantnl) 2433 { 2434 int c; 2435 Rune r; 2436 2437 while((c = getrune()) == ' ' || c == '\t') ; 2438 while(p < e) { 2439 if (c < 0) 2440 break; 2441 if (c < Runeself) { 2442 if (c == '\n') { 2443 if (wantnl) 2444 *p++ = c; 2445 break; 2446 } 2447 *p++ = c; 2448 } 2449 else { 2450 r = c; 2451 p += runetochar(p, &r); 2452 } 2453 c = getrune(); 2454 } 2455 *p = 0; 2456 } 2457 2458 void 2459 pushbody(char *line) 2460 { 2461 char *b; 2462 2463 if (line[0] == '\\' && line[1] == '{' /*}*/ ) 2464 line += 2; 2465 if (strsp < Maxmstack - 1) { 2466 pushstr(b = strdup(line)); 2467 mustfree[strsp] = b; 2468 } 2469 } 2470 2471 void 2472 skipbody(char *line) 2473 { 2474 int c, n; 2475 2476 if (line[0] != '\\' || line[1] != '{' /*}*/ ) 2477 return; 2478 for(n = 1;;) { 2479 while((c = getrune()) != '\\') 2480 if (c < 0) 2481 return; 2482 c = getrune(); 2483 if (c == '{') 2484 n++; 2485 else if ((c == '}' && (c = getrune()) == '\n' && !--n) 2486 || c < 0) 2487 return; 2488 } 2489 } 2490 2491 int 2492 ifstart(char *line, char *e, char **bp) 2493 { 2494 int it; 2495 char *b; 2496 2497 b = copyline(line, e, 1); 2498 ungetrune(); 2499 b[-1] = getrune(); 2500 scanline(b, e, 1); 2501 it = iftest(line, bp); 2502 return it; 2503 } 2504 2505 void 2506 g_ie(char *line, char *e) 2507 { 2508 char *b; 2509 2510 if (elsetop >= Maxif-1) { 2511 fprint(2, "ms2html: .ie's too deep\n"); 2512 return; 2513 } 2514 if (ifwastrue[++elsetop] = ifstart(line, e, &b)) 2515 pushbody(b); 2516 else 2517 skipbody(b); 2518 } 2519 2520 void 2521 g_if(char *line, char *e) 2522 { 2523 char *b; 2524 2525 if (ifstart(line, e, &b)) 2526 pushbody(b); 2527 else 2528 skipbody(b); 2529 } 2530 2531 void 2532 g_el(char *line, char *e) 2533 { 2534 if (elsetop < 0) 2535 return; 2536 scanline(line, e, 1); 2537 if (ifwastrue[elsetop--]) 2538 skipbody(line); 2539 else 2540 pushbody(line); 2541 } 2542 2543 void 2544 g_ig(int argc, char **argv) 2545 { 2546 char *p, *s; 2547 2548 s = ".."; 2549 if (argc > 1) 2550 s = argv[1]; 2551 for(;;) { 2552 p = Brdline(&ssp->in, '\n'); 2553 if(p == nil) 2554 break; 2555 p[Blinelen(&ssp->in)-1] = 0; 2556 if(strcmp(p, s) == 0) 2557 break; 2558 } 2559 } 2560 2561 void 2562 g_ds(char *line, char *e) 2563 { 2564 char *b; 2565 2566 b = copyline(line, e, 1); 2567 if (b > line) { 2568 copyline(b, e, 0); 2569 if (*b == '"') 2570 b++; 2571 ds(line, b); 2572 } 2573 } 2574 2575 void 2576 g_as(char *line, char *e) 2577 { 2578 String *s; 2579 char *b; 2580 2581 b = copyline(line, e, 1); 2582 if (b == line) 2583 return; 2584 copyline(b, e, 0); 2585 if (*b == '"') 2586 b++; 2587 for(s = strings; s != nil; s = s->next) 2588 if(strcmp(line, s->name) == 0) 2589 break; 2590 2591 if(s == nil){ 2592 ds(line, b); 2593 return; 2594 } 2595 2596 s->val = realloc(s->val, strlen(s->val) + strlen(b) + 1); 2597 strcat(s->val, b); 2598 } 2599 2600 void 2601 g_BS(int argc, char **argv) 2602 { 2603 int i; 2604 2605 if (argc > 1 && !weBref) { 2606 Bprint(&bout, "<a href=\"%s\"", argv[1]); 2607 for(i = 2; i < argc; i++) 2608 Bprint(&bout, " %s", argv[i]); 2609 Bprint(&bout, ">"); 2610 weBref = 1; 2611 } 2612 } 2613 2614 void 2615 g_BE(int, char**) 2616 { 2617 if (weBref) { 2618 Bprint(&bout, "</a>"); 2619 weBref = 0; 2620 } 2621 } 2622 2623 void 2624 g_LB(int argc, char **argv) 2625 { 2626 if (argc > 1) { 2627 if (weBref) 2628 g_BE(0,nil); 2629 Bprint(&bout, "<a name=\"%s\"></a>", argv[1]); 2630 } 2631 } 2632 2633 void 2634 g_RT(int, char**) 2635 { 2636 g_BE(0,nil); 2637 dohanginghead(); 2638 closel(); 2639 closefont(); 2640 } 2641