1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include "httpd.h" 5 6 enum 7 { 8 SSIZE = 10, 9 10 /* list types */ 11 Lordered = 1, 12 Lunordered, 13 Ldef, 14 Lother, 15 16 }; 17 18 static Biobuf bin; 19 static Hio houtb; 20 static Hio *hout; 21 static Connect *connect; 22 static char section[32]; 23 static char onelinefont[32]; 24 25 static Biobuf in; 26 static int sol; 27 static char me[] = "/magic/man2html/"; 28 29 static int list, listnum, indents, example, hangingdt; 30 31 typedef struct Goobie Goobie; 32 struct Goobie 33 { 34 char *name; 35 void (*f)(int, char**); 36 }; 37 38 typedef void F(int, char**); 39 F g_1C, g_2C, g_B, g_BI, g_BR, g_DT, g_EE, g_EX, g_HP, g_I; 40 F g_IB, g_IP, g_IR, g_L, g_LP, g_LR, g_PD, g_PP, g_RB, g_RE, g_RI; 41 F g_RL, g_RS, g_SH, g_SM, g_SS, g_TF, g_TH, g_TP, g_br, g_ft, g_nf, g_fi; 42 43 F g_notyet, g_ignore; 44 45 static Goobie gtab[] = 46 { 47 { "1C", g_ignore, }, 48 { "2C", g_ignore, }, 49 { "B", g_B, }, 50 { "BI", g_BI, }, 51 { "BR", g_BR, }, 52 { "DT", g_ignore, }, 53 { "EE", g_EE, }, 54 { "EX", g_EX, }, 55 { "HP", g_HP, }, 56 { "I", g_I, }, 57 { "IB", g_IB, }, 58 { "IP", g_IP, }, 59 { "IR", g_IR, }, 60 { "L", g_L, }, 61 { "LP", g_LP, }, 62 { "LR", g_LR, }, 63 { "PD", g_ignore, }, 64 { "PP", g_PP, }, 65 { "RB", g_RB, }, 66 { "RE", g_RE, }, 67 { "RI", g_RI, }, 68 { "RL", g_RL, }, 69 { "RS", g_RS, }, 70 { "SH", g_SH, }, 71 { "SM", g_SM, }, 72 { "SS", g_SS, }, 73 { "TF", g_ignore, }, 74 { "TH", g_TH, }, 75 { "TP", g_TP, }, 76 77 { "br", g_br, }, 78 { "ti", g_br, }, 79 { "nf", g_nf, }, 80 { "fi", g_fi, }, 81 { "ft", g_ft, }, 82 { nil, nil }, 83 }; 84 85 86 typedef struct Troffspec Troffspec; 87 struct Troffspec 88 { 89 char *name; 90 char *value; 91 }; 92 93 static Troffspec tspec[] = 94 { 95 { "ff", "ff", }, 96 { "fi", "fi", }, 97 { "fl", "fl", }, 98 { "Fi", "ffi", }, 99 { "ru", "_", }, 100 { "em", "­", }, 101 { "14", "¼", }, 102 { "12", "½", }, 103 { "co", "©", }, 104 { "de", "°", }, 105 { "dg", "¡", }, 106 { "fm", "´", }, 107 { "rg", "®", }, 108 { "bu", "*", }, 109 { "sq", "¤", }, 110 { "hy", "-", }, 111 { "pl", "+", }, 112 { "mi", "-", }, 113 { "mu", "×", }, 114 { "di", "÷", }, 115 { "eq", "=", }, 116 { "==", "==", }, 117 { ">=", ">=", }, 118 { "<=", "<=", }, 119 { "!=", "!=", }, 120 { "+-", "±", }, 121 { "no", "¬", }, 122 { "sl", "/", }, 123 { "ap", "&", }, 124 { "~=", "~=", }, 125 { "pt", "oc", }, 126 { "gr", "GRAD", }, 127 { "->", "->", }, 128 { "<-", "<-", }, 129 { "ua", "^", }, 130 { "da", "v", }, 131 { "is", "Integral", }, 132 { "pd", "DIV", }, 133 { "if", "oo", }, 134 { "sr", "-/", }, 135 { "sb", "(~", }, 136 { "sp", "~)", }, 137 { "cu", "U", }, 138 { "ca", "(^)", }, 139 { "ib", "(=", }, 140 { "ip", "=)", }, 141 { "mo", "C", }, 142 { "es", "Ø", }, 143 { "aa", "´", }, 144 { "ga", "`", }, 145 { "ci", "O", }, 146 { "L1", "DEATHSTAR", }, 147 { "sc", "§", }, 148 { "dd", "++", }, 149 { "lh", "<=", }, 150 { "rh", "=>", }, 151 { "lt", "(", }, 152 { "rt", ")", }, 153 { "lc", "|", }, 154 { "rc", "|", }, 155 { "lb", "(", }, 156 { "rb", ")", }, 157 { "lf", "|", }, 158 { "rf", "|", }, 159 { "lk", "|", }, 160 { "rk", "|", }, 161 { "bv", "|", }, 162 { "ts", "s", }, 163 { "br", "|", }, 164 { "or", "|", }, 165 { "ul", "_", }, 166 { "rn", " ", }, 167 { "**", "*", }, 168 { nil, nil, }, 169 }; 170 171 static char *curfont; 172 static char token[128]; 173 static int lastc = '\n'; 174 175 void closel(void); 176 void closeall(void); 177 void doconvert(char*, int, int); 178 179 /* get next logical character. expand it with escapes */ 180 char* 181 getnext(void) 182 { 183 int r, mult, size; 184 Rune rr; 185 Htmlesc *e; 186 Troffspec *t; 187 char buf[32]; 188 189 if(lastc == '\n') 190 sol = 1; 191 else 192 sol = 0; 193 r = Bgetrune(&in); 194 if(r < 0) 195 return nil; 196 lastc = r; 197 if(r > 128){ 198 for(e = htmlesc; e->name; e++) 199 if(e->value == r) 200 return e->name; 201 rr = r; 202 runetochar(buf, &rr); 203 for(r = 0; r < runelen(rr); r++) 204 snprint(token + 3*r, sizeof(token)-3*r, "%%%2.2ux", buf[r]); 205 return token; 206 } 207 switch(r){ 208 case '\\': 209 r = Bgetrune(&in); 210 if(r < 0) 211 return nil; 212 lastc = r; 213 switch(r){ 214 /* chars to ignore */ 215 case '|': 216 case '&': 217 return getnext(); 218 219 /* ignore arg */ 220 case 'k': 221 Bgetrune(&in); 222 return getnext(); 223 224 /* defined strings */ 225 case '*': 226 switch(Bgetrune(&in)){ 227 case 'R': 228 return "®"; 229 } 230 return getnext(); 231 232 /* special chars */ 233 case '(': 234 token[0] = Bgetc(&in); 235 token[1] = Bgetc(&in); 236 token[2] = 0; 237 for(t = tspec; t->name; t++) 238 if(strcmp(token, t->name) == 0) 239 return t->value; 240 return "¿"; 241 case 'c': 242 r = Bgetrune(&in); 243 if(r == '\n'){ 244 lastc = r; 245 return getnext(); 246 } 247 break; 248 case 'e': 249 return "\\"; 250 break; 251 case 'f': 252 lastc = r = Bgetrune(&in); 253 switch(r){ 254 case '2': 255 case 'B': 256 strcpy(token, "<TT>"); 257 if(curfont) 258 snprint(token, sizeof(token), "%s<TT>", curfont); 259 curfont = "</TT>"; 260 return token; 261 case '3': 262 case 'I': 263 strcpy(token, "<I>"); 264 if(curfont) 265 snprint(token, sizeof(token), "%s<I>", curfont); 266 curfont = "</I>"; 267 return token; 268 case 'L': 269 strcpy(token, "<TT>"); 270 if(curfont) 271 snprint(token, sizeof(token), "%s<TT>", curfont); 272 curfont = "</TT>"; 273 return token; 274 default: 275 token[0] = 0; 276 if(curfont) 277 strcpy(token, curfont); 278 curfont = nil; 279 return token; 280 } 281 case 's': 282 mult = 1; 283 size = 0; 284 for(;;){ 285 r = Bgetc(&in); 286 if(r < 0) 287 return nil; 288 if(r == '+') 289 ; 290 else if(r == '-') 291 mult *= -1; 292 else if(r >= '0' && r <= '9') 293 size = size*10 + (r-'0'); 294 else{ 295 Bungetc(&in); 296 break; 297 } 298 lastc = r; 299 } 300 break; 301 case ' ': 302 return " "; 303 } 304 break; 305 case '<': 306 return example ? "<" : "<"; 307 break; 308 case '>': 309 return example ? ">" : ">"; 310 break; 311 } 312 token[0] = r; 313 token[1] = 0; 314 return token; 315 } 316 317 enum 318 { 319 Narg = 32, 320 Nline = 1024, 321 Maxget = 10, 322 }; 323 324 void 325 dogoobie(void) 326 { 327 char *p, *np, *e; 328 Goobie *g; 329 char line[Nline]; 330 int argc; 331 char *argv[Narg]; 332 333 /* read line, translate special chars */ 334 e = line + sizeof(line) - Maxget; 335 for(p = line; p < e; ){ 336 np = getnext(); 337 if(np == nil) 338 return; 339 if(np[0] == '\n') 340 break; 341 if(np[1]) { 342 strcpy(p, np); 343 p += strlen(np); 344 } else 345 *p++ = np[0]; 346 } 347 *p = 0; 348 349 /* parse into arguments */ 350 p = line; 351 for(argc = 0; argc < Narg; argc++){ 352 while(*p == ' ' || *p == '\t') 353 *p++ = 0; 354 if(*p == 0) 355 break; 356 if(*p == '"'){ 357 *p++ = 0; 358 argv[argc] = p; 359 while(*p && *p != '"') 360 p++; 361 if(*p == '"') 362 *p++ = 0; 363 } else { 364 argv[argc] = p; 365 while(*p && *p != ' ' && *p != '\t') 366 p++; 367 } 368 } 369 argv[argc] = nil; 370 371 if(argc == 0) 372 return; 373 374 for(g = gtab; g->name; g++) 375 if(strncmp(g->name, argv[0], 2) == 0){ 376 (*g->f)(argc, argv); 377 return; 378 } 379 380 fprint(2, "unknown directive %s\n", line); 381 } 382 383 void 384 printargs(int argc, char **argv) 385 { 386 argc--; 387 argv++; 388 while(--argc > 0) 389 hprint(hout, "%s ", *(argv++)); 390 if(argc == 0) 391 hprint(hout, "%s", *argv); 392 } 393 394 void 395 error(char *title, char *fmt, ...) 396 { 397 va_list arg; 398 char buf[1024], *out; 399 400 va_start(arg, fmt); 401 out = doprint(buf, buf+sizeof(buf), fmt, arg); 402 va_end(arg); 403 *out = 0; 404 405 hprint(hout, "%s 404 %s\n", version, title); 406 hprint(hout, "Date: %D\n", time(nil)); 407 hprint(hout, "Server: Plan9\n"); 408 hprint(hout, "Content-type: text/html\n"); 409 hprint(hout, "\n"); 410 hprint(hout, "<head><title>%s</title></head>\n", title); 411 hprint(hout, "<body><h1>%s</h1></body>\n", title); 412 hprint(hout, "%s\n", buf); 413 exits(nil); 414 } 415 416 typedef struct Hit Hit; 417 struct Hit 418 { 419 Hit *next; 420 char *file; 421 }; 422 423 void 424 lookup(char *object, int section, Hit **list) 425 { 426 int fd; 427 char *p, *f; 428 Biobuf b; 429 char file[4*NAMELEN]; 430 Hit *h; 431 432 while(*list != nil) 433 list = &(*list)->next; 434 435 snprint(file, sizeof(file), "/sys/man/%d/INDEX", section); 436 fd = open(file, OREAD); 437 if(fd > 0){ 438 Binit(&b, fd, OREAD); 439 for(;;){ 440 p = Brdline(&b, '\n'); 441 if(p == nil) 442 break; 443 p[Blinelen(&b)-1] = 0; 444 f = strchr(p, ' '); 445 if(f == nil) 446 continue; 447 *f++ = 0; 448 if(strcmp(p, object) == 0){ 449 h = ezalloc(sizeof *h); 450 *list = h; 451 h->next = nil; 452 snprint(file, sizeof(file), "/%d/%s", section, f); 453 h->file = estrdup(file); 454 close(fd); 455 return; 456 } 457 } 458 close(fd); 459 } 460 snprint(file, sizeof(file), "/sys/man/%d/%s", section, object); 461 if(access(file, 0) == 0){ 462 h = ezalloc(sizeof *h); 463 *list = h; 464 h->next = nil; 465 h->file = estrdup(file+8); 466 } 467 } 468 469 void 470 manindex(int sect, int vermaj) 471 { 472 int i; 473 474 if(vermaj){ 475 okheaders(connect); 476 hprint(hout, "Content-type: text/html\r\n"); 477 hprint(hout, "\r\n"); 478 } 479 480 hprint(hout, "<head><title>plan 9 section index"); 481 if(sect) 482 hprint(hout, "(%d)\n", sect); 483 hprint(hout, "</title></head><body>\n"); 484 hprint(hout, "<H6>Section Index"); 485 if(sect) 486 hprint(hout, "(%d)\n", sect); 487 hprint(hout, "</H6>\n"); 488 489 if(sect) 490 hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n", 491 sect, sect); 492 else for(i = 1; i < 10; i++) 493 hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n", 494 i, i); 495 hprint(hout, "</body>\n"); 496 } 497 498 void 499 man(char *o, int sect, int vermaj) 500 { 501 int i; 502 Hit *list; 503 504 list = nil; 505 506 if(*o == 0){ 507 manindex(sect, vermaj); 508 return; 509 } 510 511 if(sect > 0 && sect < 10) 512 lookup(o, sect, &list); 513 else 514 for(i = 1; i < 9; i++) 515 lookup(o, i, &list); 516 517 if(list != nil && list->next == nil){ 518 doconvert(list->file, vermaj, 0); 519 return; 520 } 521 522 if(vermaj){ 523 okheaders(connect); 524 hprint(hout, "Content-type: text/html\r\n"); 525 hprint(hout, "\r\n"); 526 } 527 528 hprint(hout, "<head><title>plan 9 man %H", o); 529 if(sect) 530 hprint(hout, "(%d)\n", sect); 531 hprint(hout, "</title></head><body>\n"); 532 hprint(hout, "<H6>Search for %H", o); 533 if(sect) 534 hprint(hout, "(%d)\n", sect); 535 hprint(hout, "</H6>\n"); 536 537 for(; list; list = list->next) 538 hprint(hout, "<p><a href=\"/magic/man2html%U\">/magic/man2html%H</a>\n", 539 list->file, list->file); 540 hprint(hout, "</body>\n"); 541 } 542 543 void 544 redirectto(char *uri) 545 { 546 if(connect) 547 moved(connect, uri); 548 else 549 hprint(hout, "Your selection moved to <a href=\"%U\"> here</a>.<p></body>\r\n", uri); 550 } 551 552 void 553 searchfor(char *search) 554 { 555 int i, j, n, fd; 556 char *p, *sp; 557 Biobufhdr *b; 558 char *arg[32]; 559 560 hprint(hout, "<head><title>plan 9 search for %H</title></head>\n", search); 561 hprint(hout, "<body>\n"); 562 563 hprint(hout, "<p>This is a keyword search through Plan 9 man pages.\n"); 564 hprint(hout, "The search is case insensitive; blanks denote \"boolean and\".\n"); 565 hprint(hout, "<FORM METHOD=\"GET\" ACTION=\"/magic/man2html\">\n"); 566 hprint(hout, "<INPUT NAME=\"pat\" TYPE=\"text\" SIZE=\"60\">\n"); 567 hprint(hout, "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n"); 568 hprint(hout, "</FORM>\n"); 569 570 hprint(hout, "<hr><H6>Search for %H</H6>\n", search); 571 n = getfields(search, arg, 32, 1, "+"); 572 for(i = 0; i < n; i++){ 573 for(j = i+1; j < n; j++){ 574 if(strcmp(arg[i], arg[j]) > 0){ 575 sp = arg[j]; 576 arg[j] = arg[i]; 577 arg[i] = sp; 578 } 579 } 580 sp = malloc(strlen(arg[i]) + 2); 581 if(sp != nil){ 582 strcpy(sp+1, arg[i]); 583 sp[0] = ' '; 584 arg[i] = sp; 585 } 586 } 587 588 /* 589 * search index till line starts alphabetically < first token 590 */ 591 fd = open("/sys/man/searchindex", OREAD); 592 if(fd < 0){ 593 hprint(hout, "<body>error: No Plan 9 search index\n"); 594 hprint(hout, "</body>"); 595 return; 596 } 597 p = malloc(32*1024); 598 if(p == nil){ 599 close(fd); 600 return; 601 } 602 b = ezalloc(sizeof *b); 603 Binits(b, fd, OREAD, (uchar*)p, 32*1024); 604 for(;;){ 605 p = Brdline(b, '\n'); 606 if(p == nil) 607 break; 608 p[Blinelen(b)-1] = 0; 609 for(i = 0; i < n; i++){ 610 sp = strstr(p, arg[i]); 611 if(sp == nil) 612 break; 613 p = sp; 614 } 615 if(i < n) 616 continue; 617 sp = strrchr(p, '\t'); 618 if(sp == nil) 619 continue; 620 sp++; 621 hprint(hout, "<p><a href=\"/magic/man2html/%U\">/magic/man2html/%H</a>\n", 622 sp, sp); 623 } 624 hprint(hout, "</body>"); 625 626 Bterm(b); 627 free(b); 628 free(p); 629 close(fd); 630 } 631 632 /* 633 * find man pages mentioning the search string 634 */ 635 void 636 dosearch(int vermaj, char *search) 637 { 638 int sect; 639 char *p; 640 641 if(strncmp(search, "man=", 4) == 0){ 642 sect = 0; 643 search = urlunesc(search+4); 644 p = strchr(search, '&'); 645 if(p != nil){ 646 *p++ = 0; 647 if(strncmp(p, "sect=", 5) == 0) 648 sect = atoi(p+5); 649 } 650 man(search, sect, vermaj); 651 return; 652 } 653 654 if(vermaj){ 655 okheaders(connect); 656 hprint(hout, "Content-type: text/html\r\n"); 657 hprint(hout, "\r\n"); 658 } 659 660 if(strncmp(search, "pat=", 4) == 0){ 661 search = urlunesc(search+4); 662 search = lower(search); 663 searchfor(search); 664 return; 665 } 666 667 hprint(hout, "<head><title>illegal search</title></head>\n"); 668 hprint(hout, "<body><p>Illegally formatted Plan 9 man page search</p>\n"); 669 search = urlunesc(search); 670 hprint(hout, "<body><p>%H</p>\n", search); 671 hprint(hout, "</body>"); 672 } 673 674 void 675 dohangingdt(void) 676 { 677 switch(hangingdt){ 678 case 3: 679 hangingdt--; 680 break; 681 case 2: 682 hprint(hout, "<dd>"); 683 hangingdt = 0; 684 break; 685 } 686 } 687 688 /* 689 * finish any one line font changes 690 */ 691 void 692 dooneliner(void) 693 { 694 if(onelinefont[0] != 0) 695 hprint(hout, "%s", onelinefont); 696 onelinefont[0] = 0; 697 } 698 699 /* 700 * convert a man page to html and output 701 */ 702 void 703 doconvert(char *uri, int vermaj, int stdin) 704 { 705 int fd; 706 char c, *p; 707 char file[256]; 708 Dir d; 709 710 if(stdin){ 711 fd = 0; 712 } else { 713 if(strstr(uri, "..")) 714 error("bad URI", "man page URI cannot contain .."); 715 p = strstr(uri, "/intro"); 716 if(p == nil){ 717 snprint(file, sizeof(file), "/sys/man/%s", uri); 718 if(dirstat(file, &d) >= 0 && (d.qid.path & CHDIR)){ 719 if(*uri == 0 || strcmp(uri, "/") == 0) 720 redirectto("/plan9/vol1.html"); 721 else { 722 snprint(file, sizeof(file), "/plan9/man%s.html", 723 uri+1); 724 redirectto(file); 725 } 726 return; 727 } 728 if(*uri == '/') 729 uri++; 730 snprint(section, sizeof(section), uri); 731 p = strstr(section, "/"); 732 if(p != nil) 733 *p = 0; 734 } else { 735 *p = 0; 736 snprint(file, sizeof(file), "/sys/man/%s/0intro", uri); 737 if(*uri == '/') 738 uri++; 739 snprint(section, sizeof(section), uri); 740 } 741 fd = open(file, OREAD); 742 if(fd < 0) 743 error("non-existent man page", "cannot open %H: %r", file); 744 745 if(vermaj){ 746 okheaders(connect); 747 hprint(hout, "Content-type: text/html\r\n"); 748 hprint(hout, "\r\n"); 749 } 750 751 } 752 753 Binit(&in, fd, OREAD); 754 hprint(hout, "<html>\n<head>\n"); 755 756 for(;;){ 757 p = getnext(); 758 if(p == nil) 759 break; 760 c = *p; 761 if(c == '.' && sol){ 762 dogoobie(); 763 dohangingdt(); 764 } else if(c == '\n'){ 765 dooneliner(); 766 hprint(hout, "%s", p); 767 dohangingdt(); 768 } else 769 hprint(hout, "%s", p); 770 } 771 closeall(); 772 hprint(hout, "<br><font size=1><A href=http://www.lucent.com/copyright.html>\n"); 773 hprint(hout, "Copyright</A> © 2000 Lucent Technologies. All rights reserved.</font>\n"); 774 hprint(hout, "</body></html>\n"); 775 } 776 777 void 778 main(int argc, char **argv) 779 { 780 781 fmtinstall('H', httpconv); 782 fmtinstall('U', urlconv); 783 784 if(argc == 2 && strcmp(argv[1], "-") == 0){ 785 hinit(&houtb, 1, Hwrite); 786 hout = &houtb; 787 doconvert(nil, 0, 1); 788 exits(nil); 789 } 790 close(2); 791 792 connect = init(argc, argv); 793 hout = &connect->hout; 794 httpheaders(connect); 795 796 if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0) 797 unallowed(connect, "GET, HEAD"); 798 if(connect->head.expectother || connect->head.expectcont) 799 fail(connect, ExpectFail, nil); 800 801 anonymous(connect); 802 803 if(connect->req.search != nil) 804 dosearch(connect->req.vermaj, connect->req.search); 805 else 806 doconvert(connect->req.uri, connect->req.vermaj, 0); 807 exits(nil); 808 } 809 810 void 811 g_notyet(int, char **argv) 812 { 813 fprint(2, ".%s not yet supported\n", argv[0]); 814 } 815 816 void 817 g_ignore(int, char**) 818 { 819 } 820 821 void 822 g_PP(int, char**) 823 { 824 closel(); 825 hprint(hout, "<P>\n"); 826 } 827 828 /* close a list */ 829 void 830 closel(void) 831 { 832 switch(list){ 833 case Lordered: 834 hprint(hout, "</ol>\n"); 835 break; 836 case Lunordered: 837 hprint(hout, "</ul>\n"); 838 break; 839 case Lother: 840 case Ldef: 841 hprint(hout, "</dl>\n"); 842 break; 843 } 844 list = 0; 845 846 } 847 848 void 849 closeall(void) 850 { 851 closel(); 852 while(indents > 0){ 853 indents--; 854 hprint(hout, "</DL>\n"); 855 } 856 } 857 858 void 859 g_IP(int argc, char **argv) 860 { 861 switch(list){ 862 default: 863 closel(); 864 if(argc > 1){ 865 if(strcmp(argv[1], "1") == 0){ 866 list = Lordered; 867 listnum = 1; 868 hprint(hout, "<OL>\n"); 869 } else if(strcmp(argv[1], "*") == 0){ 870 list = Lunordered; 871 hprint(hout, "<UL>\n"); 872 } else { 873 list = Lother; 874 hprint(hout, "<DL>\n"); 875 } 876 } else { 877 list = Lother; 878 hprint(hout, "<DL>\n"); 879 } 880 break; 881 case Lother: 882 case Lordered: 883 case Lunordered: 884 break; 885 } 886 887 switch(list){ 888 case Lother: 889 hprint(hout, "<DT>"); 890 printargs(argc, argv); 891 hprint(hout, "<DD>\n"); 892 break; 893 case Lordered: 894 case Lunordered: 895 hprint(hout, "<LI>\n"); 896 break; 897 } 898 } 899 900 void 901 g_TP(int, char**) 902 { 903 switch(list){ 904 default: 905 closel(); 906 list = Ldef; 907 hangingdt = 3; 908 hprint(hout, "<DL><DT>\n"); 909 break; 910 case Ldef: 911 if(hangingdt) 912 hprint(hout, "<DD>"); 913 hprint(hout, "<DT>"); 914 hangingdt = 3; 915 break; 916 } 917 } 918 919 void 920 g_HP(int, char**) 921 { 922 switch(list){ 923 default: 924 closel(); 925 list = Ldef; 926 hangingdt = 1; 927 hprint(hout, "<DL><DT>\n"); 928 break; 929 case Ldef: 930 if(hangingdt) 931 hprint(hout, "<DD>"); 932 hprint(hout, "<DT>"); 933 hangingdt = 1; 934 break; 935 } 936 } 937 938 void 939 g_LP(int argc, char **argv) 940 { 941 g_PP(argc, argv); 942 } 943 944 void 945 g_TH(int argc, char **argv) 946 { 947 if(argc > 1){ 948 hprint(hout, "<title>"); 949 if(argc > 2) 950 hprint(hout, "Plan 9's %s(%s)\n", argv[1], argv[2]); 951 else 952 hprint(hout, "Plan 9's %s()\n", argv[1]); 953 hprint(hout, "</title>\n"); 954 hprint(hout, "</head><body>\n"); 955 hprint(hout, "<B>[<A href=/sys/man/index.html>manual index</A>]</B>"); 956 hprint(hout, "<B>[<A href=/sys/man/%s/INDEX.html>section index</A>]</B>\n", section); 957 } else 958 hprint(hout, "</head><body>\n"); 959 } 960 961 void 962 g_SH(int argc, char **argv) 963 { 964 closeall(); 965 indents++; 966 hprint(hout, "<H4>"); 967 printargs(argc, argv); 968 hprint(hout, "</H4>\n"); 969 hprint(hout, "<DL><DT><DD>\n"); 970 } 971 972 void 973 g_SS(int argc, char **argv) 974 { 975 closeall(); 976 indents++; 977 hprint(hout, "<H5>"); 978 printargs(argc, argv); 979 hprint(hout, "</H5>\n"); 980 hprint(hout, "<DL><DT><DD>\n"); 981 } 982 983 void 984 font(char *f, int argc, char **argv) 985 { 986 if(argc < 2){ 987 hprint(hout, "<%s>", f); 988 sprint(onelinefont, "</%s>", f); 989 } else { 990 hprint(hout, "<%s>", f); 991 printargs(argc, argv); 992 hprint(hout, "</%s>\n", f); 993 } 994 } 995 996 void 997 altfont(char *f1, char *f2, int argc, char **argv) 998 { 999 char *f; 1000 int i; 1001 1002 argc--; 1003 argv++; 1004 for(i = 0; i < argc; i++){ 1005 if(i & 1) 1006 f = f2; 1007 else 1008 f = f1; 1009 if(strcmp(f, "R") == 0) 1010 hprint(hout, "%s", argv[i]); 1011 else 1012 hprint(hout, "<%s>%s</%s>", f, argv[i], f); 1013 } 1014 hprint(hout, "\n"); 1015 } 1016 1017 void 1018 g_B(int argc, char **argv) 1019 { 1020 font("TT", argc, argv); 1021 } 1022 1023 void 1024 g_BI(int argc, char **argv) 1025 { 1026 altfont("TT", "I", argc, argv); 1027 } 1028 1029 void 1030 g_BR(int argc, char **argv) 1031 { 1032 altfont("TT", "R", argc, argv); 1033 } 1034 1035 void 1036 g_RB(int argc, char **argv) 1037 { 1038 altfont("R", "TT", argc, argv); 1039 } 1040 1041 void 1042 g_I(int argc, char **argv) 1043 { 1044 font("I", argc, argv); 1045 } 1046 1047 void 1048 g_IB(int argc, char **argv) 1049 { 1050 altfont("I", "TT", argc, argv); 1051 } 1052 1053 void 1054 g_IR(int argc, char **argv) 1055 { 1056 int anchor; 1057 char *p; 1058 1059 anchor = 0; 1060 if(argc > 2){ 1061 p = argv[2]; 1062 if(p[0] == '(' && p[1] >= '1' && p[1] <= '9' && p[2] == ')') 1063 anchor = 1; 1064 if(anchor) 1065 hprint(hout, "<A href=\"/magic/man2html/%c/%U\">", 1066 p[1], httpunesc(lower(argv[1]))); 1067 } 1068 altfont("I", "R", argc, argv); 1069 if(anchor) 1070 hprint(hout, "</A>"); 1071 } 1072 1073 void 1074 g_RI(int argc, char **argv) 1075 { 1076 altfont("R", "I", argc, argv); 1077 } 1078 1079 void 1080 g_br(int, char**) 1081 { 1082 if(hangingdt){ 1083 hprint(hout, "<dd>"); 1084 hangingdt = 0; 1085 }else 1086 hprint(hout, "<br>\n"); 1087 } 1088 1089 void 1090 g_nf(int, char**) 1091 { 1092 example = 1; 1093 hprint(hout, "<PRE>\n"); 1094 } 1095 1096 void 1097 g_fi(int, char**) 1098 { 1099 example = 0; 1100 hprint(hout, "</PRE>\n"); 1101 } 1102 1103 void 1104 g_EX(int, char**) 1105 { 1106 example = 1; 1107 hprint(hout, "<TT><XMP>\n"); 1108 } 1109 1110 void 1111 g_EE(int, char**) 1112 { 1113 example = 0; 1114 hprint(hout, "</XMP></TT>\n"); 1115 } 1116 1117 void 1118 g_L(int argc, char **argv) 1119 { 1120 font("TT", argc, argv); 1121 } 1122 1123 void 1124 g_LR(int argc, char **argv) 1125 { 1126 altfont("TT", "R", argc, argv); 1127 } 1128 1129 void 1130 g_RL(int argc, char **argv) 1131 { 1132 altfont("R", "TT", argc, argv); 1133 } 1134 1135 void 1136 g_RS(int, char**) 1137 { 1138 hprint(hout, "<DL><DT><DD>\n"); 1139 } 1140 1141 void 1142 g_RE(int, char**) 1143 { 1144 hprint(hout, "</DL>\n"); 1145 } 1146 1147 void 1148 g_SM(int argc, char **argv) 1149 { 1150 if(argc > 1) 1151 hprint(hout, "%s ", argv[1]); 1152 } 1153 1154 void 1155 g_ft(int argc, char **argv) 1156 { 1157 char *font; 1158 1159 if(argc < 2) 1160 return; 1161 1162 if(curfont) 1163 hprint(hout, "%s", curfont); 1164 1165 switch(*argv[1]){ 1166 case '2': 1167 case 'B': 1168 font = "B"; 1169 curfont = "</B>"; 1170 break; 1171 case '3': 1172 case 'I': 1173 font = "I"; 1174 curfont = "</I>"; 1175 break; 1176 case 'L': 1177 font = "TT"; 1178 curfont = "</TT>"; 1179 break; 1180 default: 1181 curfont = nil; 1182 return; 1183 } 1184 hprint(hout, "<%s>", font); 1185 } 1186