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