1/* 2 * This program was written by Richard Verhoeven (NL:5482ZX35) 3 * at the Eindhoven University of Technology. Email: rcb5@win.tue.nl 4 * 5 * Permission is granted to distribute, modify and use this program as long 6 * as this comment is not removed or changed. 7 * 8 * THIS IS A MODIFIED VERSION. IT WAS MODIFIED BY chet@po.cwru.edu FOR 9 * USE BY BASH. 10 */ 11 12/* 13 * man2html will add links to the converted manpages. The function add_links 14 * is used for that. At the moment it will add links as follows, where 15 * indicates what should match to start with: 16 * ^^^ 17 * Recognition Item Link 18 * ---------------------------------------------------------- 19 * name(*) Manpage ../man?/name.* 20 * ^ 21 * name@hostname Email address mailto:name@hostname 22 * ^ 23 * method://string URL method://string 24 * ^^^ 25 * www.host.name WWW server http://www.host.name 26 * ^^^^ 27 * ftp.host.name FTP server ftp://ftp.host.name 28 * ^^^^ 29 * <file.h> Include file file:/usr/include/file.h 30 * ^^^ 31 * 32 * Since man2html does not check if manpages, hosts or email addresses exist, 33 * some links might not work. For manpages, some extra checks are performed 34 * to make sure not every () pair creates a link. Also out of date pages 35 * might point to incorrect places. 36 * 37 * The program will not allow users to get system specific files, such as 38 * /etc/passwd. It will check that "man" is part of the specified file and 39 * that "/../" isn't. Even if someone manages to get such file, man2html will 40 * handle it like a manpage and will usually not produce any output (or crash). 41 * 42 * If you find any bugs when normal manpages are converted, please report 43 * them to me (rcb5@win.tue.nl) after you have checked that man(1) can handle 44 * the manpage correct. 45 * 46 * Known bugs and missing features: 47 * 48 * * Equations are not converted at all. 49 * * Tables are converted but some features are not possible in html. 50 * * The tabbing environment is converted by counting characters and adding 51 * spaces. This might go wrong (outside <PRE>) 52 * * Some pages look beter if man2html works in troff mode, especially pages 53 * with tables. You can deside at compile time which made you want to use. 54 * 55 * -DNROFF=0 troff mode 56 * -DNROFF=1 nroff mode (default) 57 * 58 * if you install both modes, you should compile with the correct CGIBASE. 59 * * Some manpages rely on the fact that troff/nroff is used to convert 60 * them and use features which are not descripted in the man manpages. 61 * (definitions, calculations, conditionals, requests). I can't guarantee 62 * that all these features work on all manpages. (I didn't have the 63 * time to look through all the available manpages.) 64 */ 65#ifdef HAVE_CONFIG_H 66#include <config.h> 67#endif 68 69#define NROFF 0 70 71#include <stdio.h> 72#include <stdlib.h> 73#include <string.h> 74#include <sys/stat.h> 75#include <ctype.h> 76#include <sys/types.h> 77#include <time.h> 78#include <sys/time.h> 79#include <errno.h> 80 81#define NULL_TERMINATED(n) ((n) + 1) 82 83#define HUGE_STR_MAX 10000 84#define LARGE_STR_MAX 2000 85#define MED_STR_MAX 500 86#define SMALL_STR_MAX 100 87#define TINY_STR_MAX 10 88 89#define MAX_MAN_PATHS 100 /* Max number of directories */ 90#define MAX_ZCATS 10 /* Max number of zcat style programs */ 91#define MAX_WORDLIST 100 92 93#ifndef EXIT_SUCCESS 94#define EXIT_SUCCESS 0 95#endif 96#ifndef EXIT_FAILURE 97#define EXIT_FAILURE 1 98#endif 99#ifndef EXIT_USAGE 100#define EXIT_USAGE 2 101#endif 102 103static char location_base[NULL_TERMINATED(MED_STR_MAX)] = ""; 104 105static char th_page_and_sec[128] = { '\0' }; 106static char th_datestr[128] = { '\0' }; 107static char th_version[128] = { '\0' }; 108 109char *signature = "<HR>\nThis document was created by man2html from %s.<BR>\nTime: %s\n"; 110 111/* timeformat for signature */ 112#define TIMEFORMAT "%d %B %Y %T %Z" 113 114char *manpage; 115 116/* BSD mandoc Bl/El lists to HTML list types */ 117#define BL_DESC_LIST 1 118#define BL_BULLET_LIST 2 119#define BL_ENUM_LIST 4 120 121/* BSD mandoc Bd/Ed example(?) blocks */ 122#define BD_LITERAL 1 123#define BD_INDENT 2 124 125#ifndef HAVE_STRERROR 126static char * 127strerror(int e) 128{ 129 static char emsg[40]; 130 131#if defined (HAVE_SYS_ERRLIST) 132 extern int sys_nerr; 133 extern char *sys_errlist[]; 134 135 if (e > 0 && e < sys_nerr) 136 return (sys_errlist[e]); 137 else 138#endif /* HAVE_SYS_ERRLIST */ 139 { 140 sprintf(emsg, "Unknown system error %d", e); 141 return (&emsg[0]); 142 } 143} 144#endif /* !HAVE_STRERROR */ 145 146static char * 147strgrow(char *old, int len) 148{ 149 char *new = realloc(old, (strlen(old) + len + 1) * sizeof(char)); 150 151 if (!new) { 152 fprintf(stderr, "man2html: out of memory"); 153 exit(EXIT_FAILURE); 154 } 155 return new; 156} 157 158static char * 159stralloc(int len) 160{ 161 /* allocate enough for len + NULL */ 162 char *new = malloc((len + 1) * sizeof(char)); 163 164 if (!new) { 165 fprintf(stderr, "man2html: out of memory"); 166 exit(EXIT_FAILURE); 167 } 168 return new; 169} 170 171/* 172 * Some systems don't have strdup so lets use our own - which can also 173 * check for out of memory. 174 */ 175static char * 176strduplicate(char *from) 177{ 178 char *new = stralloc(strlen(from)); 179 180 strcpy(new, from); 181 return new; 182} 183 184/* Assumes space for n plus a null */ 185static char * 186strmaxcpy(char *to, char *from, int n) 187{ 188 int len = strlen(from); 189 190 strncpy(to, from, n); 191 to[(len <= n) ? len : n] = '\0'; 192 return to; 193} 194 195static char * 196strmaxcat(char *to, char *from, int n) 197{ 198 int to_len = strlen(to); 199 200 if (to_len < n) { 201 int from_len = strlen(from); 202 int cp = (to_len + from_len <= n) ? from_len : n - to_len; 203 204 strncpy(to + to_len, from, cp); 205 to[to_len + cp] = '\0'; 206 } 207 return to; 208} 209 210/* Assumes space for limit plus a null */ 211static char * 212strlimitcpy(char *to, char *from, int n, int limit) 213{ 214 int len = n > limit ? limit : n; 215 216 strmaxcpy(to, from, len); 217 to[len] = '\0'; 218 return to; 219} 220 221/* 222 * takes string and escapes all metacharacters. should be used before 223 * including string in system() or similar call. 224 */ 225static char * 226escape_input(char *str) 227{ 228 int i, j = 0; 229 static char new[NULL_TERMINATED(MED_STR_MAX)]; 230 231 if (strlen(str) * 2 + 1 > MED_STR_MAX) { 232 fprintf(stderr, 233 "man2html: escape_input - str too long:\n%-80s...\n", 234 str); 235 exit(EXIT_FAILURE); 236 } 237 for (i = 0; i < strlen(str); i++) { 238 if (!(((str[i] >= 'A') && (str[i] <= 'Z')) || 239 ((str[i] >= 'a') && (str[i] <= 'z')) || 240 ((str[i] >= '0') && (str[i] <= '9')))) { 241 new[j] = '\\'; 242 j++; 243 } 244 new[j] = str[i]; 245 j++; 246 } 247 new[j] = '\0'; 248 return new; 249} 250 251static void 252usage(void) 253{ 254 fprintf(stderr, "man2html: usage: man2html filename\n"); 255} 256 257 258 259/* 260 * below this you should not change anything unless you know a lot 261 * about this program or about troff. 262 */ 263 264typedef struct STRDEF STRDEF; 265struct STRDEF { 266 int nr, slen; 267 char *st; 268 STRDEF *next; 269}; 270 271typedef struct INTDEF INTDEF; 272struct INTDEF { 273 int nr; 274 int val; 275 int incr; 276 INTDEF *next; 277}; 278 279static char NEWLINE[2] = "\n"; 280static char idxlabel[6] = "ixAAA"; 281 282#define INDEXFILE "/tmp/manindex.list" 283 284static char *fname; 285static FILE *idxfile; 286 287static STRDEF *chardef, *strdef, *defdef; 288static INTDEF *intdef; 289 290#define V(A,B) ((A)*256+(B)) 291 292static INTDEF standardint[] = { 293 {V('n', ' '), NROFF, 0, NULL}, 294 {V('t', ' '), 1 - NROFF, 0, NULL}, 295 {V('o', ' '), 1, 0, NULL}, 296 {V('e', ' '), 0, 0, NULL}, 297 {V('.', 'l'), 70, 0, NULL}, 298 {V('.', '$'), 0, 0, NULL}, 299 {V('.', 'A'), NROFF, 0, NULL}, 300 {V('.', 'T'), 1 - NROFF, 0, NULL}, 301 {V('.', 'V'), 1, 0, NULL}, /* the me package tests for this */ 302{0, 0, 0, NULL}}; 303 304static STRDEF standardstring[] = { 305 {V('R', ' '), 1, "®", NULL}, 306 {V('l', 'q'), 2, "``", NULL}, 307 {V('r', 'q'), 2, "''", NULL}, 308 {0, 0, NULL, NULL} 309}; 310 311 312static STRDEF standardchar[] = { 313 {V('*', '*'), 1, "*", NULL}, 314 {V('*', 'A'), 1, "A", NULL}, 315 {V('*', 'B'), 1, "B", NULL}, 316 {V('*', 'C'), 2, "Xi", NULL}, 317 {V('*', 'D'), 5, "Delta", NULL}, 318 {V('*', 'E'), 1, "E", NULL}, 319 {V('*', 'F'), 3, "Phi", NULL}, 320 {V('*', 'G'), 5, "Gamma", NULL}, 321 {V('*', 'H'), 5, "Theta", NULL}, 322 {V('*', 'I'), 1, "I", NULL}, 323 {V('*', 'K'), 1, "K", NULL}, 324 {V('*', 'L'), 6, "Lambda", NULL}, 325 {V('*', 'M'), 1, "M", NULL}, 326 {V('*', 'N'), 1, "N", NULL}, 327 {V('*', 'O'), 1, "O", NULL}, 328 {V('*', 'P'), 2, "Pi", NULL}, 329 {V('*', 'Q'), 3, "Psi", NULL}, 330 {V('*', 'R'), 1, "P", NULL}, 331 {V('*', 'S'), 5, "Sigma", NULL}, 332 {V('*', 'T'), 1, "T", NULL}, 333 {V('*', 'U'), 1, "Y", NULL}, 334 {V('*', 'W'), 5, "Omega", NULL}, 335 {V('*', 'X'), 1, "X", NULL}, 336 {V('*', 'Y'), 1, "H", NULL}, 337 {V('*', 'Z'), 1, "Z", NULL}, 338 {V('*', 'a'), 5, "alpha", NULL}, 339 {V('*', 'b'), 4, "beta", NULL}, 340 {V('*', 'c'), 2, "xi", NULL}, 341 {V('*', 'd'), 5, "delta", NULL}, 342 {V('*', 'e'), 7, "epsilon", NULL}, 343 {V('*', 'f'), 3, "phi", NULL}, 344 {V('*', 'g'), 5, "gamma", NULL}, 345 {V('*', 'h'), 5, "theta", NULL}, 346 {V('*', 'i'), 4, "iota", NULL}, 347 {V('*', 'k'), 5, "kappa", NULL}, 348 {V('*', 'l'), 6, "lambda", NULL}, 349 {V('*', 'm'), 1, "µ", NULL}, 350 {V('*', 'n'), 2, "nu", NULL}, 351 {V('*', 'o'), 1, "o", NULL}, 352 {V('*', 'p'), 2, "pi", NULL}, 353 {V('*', 'q'), 3, "psi", NULL}, 354 {V('*', 'r'), 3, "rho", NULL}, 355 {V('*', 's'), 5, "sigma", NULL}, 356 {V('*', 't'), 3, "tau", NULL}, 357 {V('*', 'u'), 7, "upsilon", NULL}, 358 {V('*', 'w'), 5, "omega", NULL}, 359 {V('*', 'x'), 3, "chi", NULL}, 360 {V('*', 'y'), 3, "eta", NULL}, 361 {V('*', 'z'), 4, "zeta", NULL}, 362 {V('t', 's'), 5, "sigma", NULL}, 363 {V('+', '-'), 1, "±", NULL}, 364 {V('1', '2'), 1, "½", NULL}, 365 {V('1', '4'), 1, "¼", NULL}, 366 {V('3', '4'), 1, "¾", NULL}, 367 {V('F', 'i'), 3, "ffi", NULL}, 368 {V('F', 'l'), 3, "ffl", NULL}, 369 {V('a', 'a'), 1, "´", NULL}, 370 {V('a', 'p'), 1, "~", NULL}, 371 {V('b', 'r'), 1, "|", NULL}, 372 {V('b', 'u'), 1, "*", NULL}, 373 {V('b', 'v'), 1, "|", NULL}, 374 {V('c', 'i'), 1, "o", NULL}, 375 {V('c', 'o'), 1, "©", NULL}, 376 {V('c', 't'), 1, "¢", NULL}, 377 {V('d', 'e'), 1, "°", NULL}, 378 {V('d', 'g'), 1, "+", NULL}, 379 {V('d', 'i'), 1, "÷", NULL}, 380 {V('e', 'm'), 1, "-", NULL}, 381 {V('e', 'm'), 3, "---", NULL}, 382 {V('e', 'q'), 1, "=", NULL}, 383 {V('e', 's'), 1, "Ø", NULL}, 384 {V('f', 'f'), 2, "ff", NULL}, 385 {V('f', 'i'), 2, "fi", NULL}, 386 {V('f', 'l'), 2, "fl", NULL}, 387 {V('f', 'm'), 1, "´", NULL}, 388 {V('g', 'a'), 1, "`", NULL}, 389 {V('h', 'y'), 1, "-", NULL}, 390 {V('l', 'c'), 2, "|¯", NULL}, 391 {V('l', 'f'), 2, "|_", NULL}, 392 {V('l', 'k'), 1, "<FONT SIZE=+2>{</FONT>", NULL}, 393 {V('m', 'i'), 1, "-", NULL}, 394 {V('m', 'u'), 1, "×", NULL}, 395 {V('n', 'o'), 1, "¬", NULL}, 396 {V('o', 'r'), 1, "|", NULL}, 397 {V('p', 'l'), 1, "+", NULL}, 398 {V('r', 'c'), 2, "¯|", NULL}, 399 {V('r', 'f'), 2, "_|", NULL}, 400 {V('r', 'g'), 1, "®", NULL}, 401 {V('r', 'k'), 1, "<FONT SIZE=+2>}</FONT>", NULL}, 402 {V('r', 'n'), 1, "¯", NULL}, 403 {V('r', 'u'), 1, "_", NULL}, 404 {V('s', 'c'), 1, "§", NULL}, 405 {V('s', 'l'), 1, "/", NULL}, 406 {V('s', 'q'), 2, "[]", NULL}, 407 {V('u', 'l'), 1, "_", NULL}, 408 {0, 0, NULL, NULL} 409}; 410 411/* default: print code */ 412 413 414static char eqndelimopen = 0, eqndelimclose = 0; 415static char escapesym = '\\', nobreaksym = '\'', controlsym = '.', fieldsym = 0, padsym = 0; 416 417static char *buffer = NULL; 418static int buffpos = 0, buffmax = 0; 419static int scaninbuff = 0; 420static int itemdepth = 0; 421static int dl_set[20] = {0}; 422static int still_dd = 0; 423static int tabstops[20] = {8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96}; 424static int maxtstop = 12; 425static int curpos = 0; 426 427static char *scan_troff(char *c, int san, char **result); 428static char *scan_troff_mandoc(char *c, int san, char **result); 429 430static char **argument = NULL; 431 432static char charb[TINY_STR_MAX]; 433 434static void 435print_sig(void) 436{ 437 char datbuf[NULL_TERMINATED(MED_STR_MAX)]; 438 struct tm *timetm; 439 time_t clock; 440 441 datbuf[0] = '\0'; 442 clock = time(NULL); 443 timetm = localtime(&clock); 444 strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); 445 printf(signature, manpage, datbuf); 446} 447 448static char * 449expand_char(int nr) 450{ 451 STRDEF *h; 452 453 h = chardef; 454 if (!nr) 455 return NULL; 456 while (h) 457 if (h->nr == nr) { 458 curpos += h->slen; 459 return h->st; 460 } else 461 h = h->next; 462 charb[0] = nr / 256; 463 charb[1] = nr % 256; 464 charb[2] = '\0'; 465 if (charb[0] == '<') { /* Fix up <= */ 466 charb[4] = charb[1]; 467 strncpy(charb, "<", 4); 468 charb[5] = '\0'; 469 } 470 curpos += 2; 471 return charb; 472} 473 474static char * 475expand_string(int nr) 476{ 477 STRDEF *h = strdef; 478 479 if (!nr) 480 return NULL; 481 while (h) 482 if (h->nr == nr) { 483 curpos += h->slen; 484 return h->st; 485 } else 486 h = h->next; 487 return NULL; 488} 489 490static char * 491read_man_page(char *filename) 492{ 493 char *man_buf = NULL; 494 int i; 495 FILE *man_stream = NULL; 496 struct stat stbuf; 497 int buf_size; 498 499 if (stat(filename, &stbuf) == -1) 500 return NULL; 501 502 buf_size = stbuf.st_size; 503 man_buf = stralloc(buf_size + 5); 504 man_stream = fopen(filename, "r"); 505 if (man_stream) { 506 man_buf[0] = '\n'; 507 if (fread(man_buf + 1, 1, buf_size, man_stream) == buf_size) { 508 man_buf[buf_size] = '\n'; 509 man_buf[buf_size + 1] = man_buf[buf_size + 2] = '\0'; 510 } else { 511 man_buf = NULL; 512 } 513 fclose(man_stream); 514 } 515 return man_buf; 516} 517 518 519static char outbuffer[NULL_TERMINATED(HUGE_STR_MAX)]; 520static int obp = 0; 521static int no_newline_output = 0; 522static int newline_for_fun = 0; 523static int output_possible = 0; 524static int out_length = 0; 525 526/* 527 * Add the links to the output. At the moment the following are 528 * recognized: 529 * 530#if 0 531 * name(*) -> ../man?/name.* 532#endif 533 * method://string -> method://string 534 * www.host.name -> http://www.host.name 535 * ftp.host.name -> ftp://ftp.host.name 536 * name@host -> mailto:name@host 537 * <name.h> -> file:/usr/include/name.h (guess) 538 * 539 * Other possible links to add in the future: 540 * 541 * /dir/dir/file -> file:/dir/dir/file 542 */ 543static void 544add_links(char *c) 545{ 546 int i, j, nr; 547 char *f, *g, *h; 548 char *idtest[6]; /* url, mailto, www, ftp, manpage */ 549 550 out_length += strlen(c); 551 /* search for (section) */ 552 nr = 0; 553 idtest[0] = strstr(c + 1, "://"); 554 idtest[1] = strchr(c + 1, '@'); 555 idtest[2] = strstr(c, "www."); 556 idtest[3] = strstr(c, "ftp."); 557#if 0 558 idtest[4] = strchr(c + 1, '('); 559#else 560 idtest[4] = 0; 561#endif 562 idtest[5] = strstr(c + 1, ".h>"); 563 for (i = 0; i < 6; i++) 564 nr += (idtest[i] != NULL); 565 while (nr) { 566 j = -1; 567 for (i = 0; i < 6; i++) 568 if (idtest[i] && (j < 0 || idtest[i] < idtest[j])) 569 j = i; 570 switch (j) { 571 case 5: /* <name.h> */ 572 f = idtest[5]; 573 h = f + 2; 574 g = f; 575 while (g > c && g[-1] != ';') 576 g--; 577 if (g != c) { 578 char t; 579 580 t = *g; 581 *g = '\0'; 582 fputs(c, stdout); 583 *g = t; 584 *h = '\0'; 585 printf("<A HREF=\"file:/usr/include/%s\">%s</A>>", g, g); 586 c = f + 6; 587 } else { 588 f[5] = '\0'; 589 fputs(c, stdout); 590 f[5] = ';'; 591 c = f + 5; 592 } 593 break; 594 case 4: /* manpage */ 595#if 0 596 f = idtest[j]; 597 /* check section */ 598 g = strchr(f, ')'); 599 if (g && f - g < 6 && (isalnum(f[-1]) || f[-1] == '>') && 600 ((isdigit(f[1]) && f[1] != '0' && 601 (f[2] == ')' || (isalpha(f[2]) && f[3] == ')') || f[2] == 'X')) || 602 (f[2] == ')' && (f[1] == 'n' || f[1] == 'l')))) { 603 /* this might be a link */ 604 h = f - 1; 605 /* skip html makeup */ 606 while (h > c && *h == '>') { 607 while (h != c && *h != '<') 608 h--; 609 if (h != c) 610 h--; 611 } 612 if (isalnum(*h)) { 613 char t, sec, subsec, *e; 614 615 e = h + 1; 616 sec = f[1]; 617 subsec = f[2]; 618 if ((subsec == 'X' && f[3] != ')') || subsec == ')') 619 subsec = '\0'; 620 while (h > c && (isalnum(h[-1]) || h[-1] == '_' || 621 h[-1] == '-' || h[-1] == '.')) 622 h--; 623 t = *h; 624 *h = '\0'; 625 fputs(c, stdout); 626 *h = t; 627 t = *e; 628 *e = '\0'; 629 if (subsec) 630 printf("<A HREF=\"" 631 CGIBASE 632 "?man%c/%s.%c%c\">%s</A>", 633 sec, h, sec, tolower(subsec), h); 634 else 635 printf("<A HREF=\"" 636 CGIBASE 637 "?man%c/%s.%c\">%s</A>", 638 sec, h, sec, h); 639 *e = t; 640 c = e; 641 } 642 } 643 *f = '\0'; 644 fputs(c, stdout); 645 *f = '('; 646 idtest[4] = f - 1; 647 c = f; 648#endif 649 break; /* manpage */ 650 case 3: /* ftp */ 651 case 2: /* www */ 652 g = f = idtest[j]; 653 while (*g && (isalnum(*g) || *g == '_' || *g == '-' || *g == '+' || 654 *g == '.')) 655 g++; 656 if (g[-1] == '.') 657 g--; 658 if (g - f > 4) { 659 char t; 660 661 t = *f; 662 *f = '\0'; 663 fputs(c, stdout); 664 *f = t; 665 t = *g; 666 *g = '\0'; 667 printf("<A HREF=\"%s://%s\">%s</A>", (j == 3 ? "ftp" : "http"), 668 f, f); 669 *g = t; 670 c = g; 671 } else { 672 f[3] = '\0'; 673 fputs(c, stdout); 674 c = f + 3; 675 f[3] = '.'; 676 } 677 break; 678 case 1: /* mailto */ 679 g = f = idtest[1]; 680 while (g > c && (isalnum(g[-1]) || g[-1] == '_' || g[-1] == '-' || 681 g[-1] == '+' || g[-1] == '.' || g[-1] == '%')) 682 g--; 683 h = f + 1; 684 while (*h && (isalnum(*h) || *h == '_' || *h == '-' || *h == '+' || 685 *h == '.')) 686 h++; 687 if (*h == '.') 688 h--; 689 if (h - f > 4 && f - g > 1) { 690 char t; 691 692 t = *g; 693 *g = '\0'; 694 fputs(c, stdout); 695 *g = t; 696 t = *h; 697 *h = '\0'; 698 printf("<A HREF=\"mailto:%s\">%s</A>", g, g); 699 *h = t; 700 c = h; 701 } else { 702 *f = '\0'; 703 fputs(c, stdout); 704 *f = '@'; 705 idtest[1] = c; 706 c = f; 707 } 708 break; 709 case 0: /* url */ 710 g = f = idtest[0]; 711 while (g > c && isalpha(g[-1]) && islower(g[-1])) 712 g--; 713 h = f + 3; 714 while (*h && !isspace(*h) && *h != '<' && *h != '>' && *h != '"' && 715 *h != '&') 716 h++; 717 if (f - g > 2 && f - g < 7 && h - f > 3) { 718 char t; 719 720 t = *g; 721 *g = '\0'; 722 fputs(c, stdout); 723 *g = t; 724 t = *h; 725 *h = '\0'; 726 printf("<A HREF=\"%s\">%s</A>", g, g); 727 *h = t; 728 c = h; 729 } else { 730 f[1] = '\0'; 731 fputs(c, stdout); 732 f[1] = '/'; 733 c = f + 1; 734 } 735 break; 736 default: 737 break; 738 } 739 nr = 0; 740 if (idtest[0] && idtest[0] < c) 741 idtest[0] = strstr(c + 1, "://"); 742 if (idtest[1] && idtest[1] < c) 743 idtest[1] = strchr(c + 1, '@'); 744 if (idtest[2] && idtest[2] < c) 745 idtest[2] = strstr(c, "www."); 746 if (idtest[3] && idtest[3] < c) 747 idtest[3] = strstr(c, "ftp."); 748 if (idtest[4] && idtest[4] < c) 749 idtest[4] = strchr(c + 1, '('); 750 if (idtest[5] && idtest[5] < c) 751 idtest[5] = strstr(c + 1, ".h>"); 752 for (i = 0; i < 6; i++) 753 nr += (idtest[i] != NULL); 754 } 755 fputs(c, stdout); 756} 757 758static int current_font = 0; 759static int current_size = 0; 760static int fillout = 1; 761 762static void 763out_html(char *c) 764{ 765 if (!c) 766 return; 767 if (no_newline_output) { 768 int i = 0; 769 770 no_newline_output = 1; 771 while (c[i]) { 772 if (!no_newline_output) 773 c[i - 1] = c[i]; 774 if (c[i] == '\n') 775 no_newline_output = 1; 776 i++; 777 } 778 if (!no_newline_output) 779 c[i - 1] = 0; 780 } 781 if (scaninbuff) { 782 while (*c) { 783 if (buffpos >= buffmax) { 784 char *h; 785 786 h = realloc(buffer, buffmax * 2); 787 if (!h) 788 return; 789 buffer = h; 790 buffmax *= 2; 791 } 792 buffer[buffpos++] = *c++; 793 } 794 } else if (output_possible) { 795 while (*c) { 796 outbuffer[obp++] = *c; 797 if (*c == '\n' || obp > HUGE_STR_MAX) { 798 outbuffer[obp] = '\0'; 799 add_links(outbuffer); 800 obp = 0; 801 } 802 c++; 803 } 804 } 805} 806 807#define FO0 "" 808#define FC0 "" 809#define FO1 "<I>" 810#define FC1 "</I>" 811#define FO2 "<B>" 812#define FC2 "</B>" 813#define FO3 "<TT>" 814#define FC3 "</TT>" 815 816static char *switchfont[16] = { 817 "", FC0 FO1, FC0 FO2, FC0 FO3, 818 FC1 FO0, "", FC1 FO2, FC1 FO3, 819 FC2 FO0, FC2 FO1, "", FC2 FO3, 820 FC3 FO0, FC3 FO1, FC3 FO2, "" 821}; 822 823static char * 824change_to_font(int nr) 825{ 826 int i; 827 828 switch (nr) { 829 case '0': 830 nr++; 831 case '1': 832 case '2': 833 case '3': 834 case '4': 835 nr = nr - '1'; 836 break; 837 case V('C', 'W'): 838 nr = 3; 839 break; 840 case 'L': 841 nr = 3; 842 break; 843 case 'B': 844 nr = 2; 845 break; 846 case 'I': 847 nr = 1; 848 break; 849 case 'P': 850 case 'R': 851 nr = 0; 852 break; 853 case 0: 854 case 1: 855 case 2: 856 case 3: 857 break; 858 default: 859 nr = 0; 860 break; 861 } 862 i = current_font * 4 + nr % 4; 863 current_font = nr % 4; 864 return switchfont[i]; 865} 866 867static char sizebuf[200]; 868 869static char * 870change_to_size(int nr) 871{ 872 int i; 873 874 switch (nr) { 875 case '0': 876 case '1': 877 case '2': 878 case '3': 879 case '4': 880 case '5': 881 case '6': 882 case '7': 883 case '8': 884 case '9': 885 nr = nr - '0'; 886 break; 887 case '\0': 888 break; 889 default: 890 nr = current_size + nr; 891 if (nr > 9) 892 nr = 9; 893 if (nr < -9) 894 nr = -9; 895 break; 896 } 897 if (nr == current_size) 898 return ""; 899 i = current_font; 900 sizebuf[0] = '\0'; 901 strcat(sizebuf, change_to_font(0)); 902 if (current_size) 903 strcat(sizebuf, "</FONT>"); 904 current_size = nr; 905 if (nr) { 906 int l; 907 908 strcat(sizebuf, "<FONT SIZE="); 909 l = strlen(sizebuf); 910 if (nr > 0) 911 sizebuf[l++] = '+'; 912 else 913 sizebuf[l++] = '-', nr = -nr; 914 sizebuf[l++] = nr + '0'; 915 sizebuf[l++] = '>'; 916 sizebuf[l] = '\0'; 917 } 918 strcat(sizebuf, change_to_font(i)); 919 return sizebuf; 920} 921 922static int asint = 0; 923static int intresult = 0; 924 925#define SKIPEOL while (*c && *c++!='\n') 926 927static int skip_escape = 0; 928static int single_escape = 0; 929 930static char * 931scan_escape(char *c) 932{ 933 char *h = NULL; 934 char b[5]; 935 INTDEF *intd; 936 int exoutputp, exskipescape; 937 int i, j; 938 939 intresult = 0; 940 switch (*c) { 941 case 'e': 942 h = "\\"; 943 curpos++; 944 break; 945 case '0': 946 case ' ': 947 h = " "; 948 curpos++; 949 break; 950 case '|': 951 h = ""; 952 break; 953 case '"': 954 SKIPEOL; 955 c--; 956 h = ""; 957 break; 958 case '$': 959 if (argument) { 960 c++; 961 i = (*c - '1'); 962 if (!(h = argument[i])) 963 h = ""; 964 } 965 break; 966 case 'z': 967 c++; 968 if (*c == '\\') { 969 c = scan_escape(c + 1); 970 c--; 971 h = ""; 972 } else { 973 b[0] = *c; 974 b[1] = '\0'; 975 h = ""; 976 } 977 break; 978 case 'k': 979 c++; 980 if (*c == '(') 981 c += 2; 982 case '^': 983 case '!': 984 case '%': 985 case 'a': 986 case 'd': 987 case 'r': 988 case 'u': 989 case '\n': 990 case '&': 991 h = ""; 992 break; 993 case '(': 994 c++; 995 i = c[0] * 256 + c[1]; 996 c++; 997 h = expand_char(i); 998 break; 999 case '*': 1000 c++; 1001 if (*c == '(') { 1002 c++; 1003 i = c[0] * 256 + c[1]; 1004 c++; 1005 } else 1006 i = *c * 256 + ' '; 1007 h = expand_string(i); 1008 break; 1009 case 'f': 1010 c++; 1011 if (*c == '\\') { 1012 c++; 1013 c = scan_escape(c); 1014 c--; 1015 i = intresult; 1016 } else if (*c != '(') 1017 i = *c; 1018 else { 1019 c++; 1020 i = c[0] * 256 + c[1]; 1021 c++; 1022 } 1023 if (!skip_escape) 1024 h = change_to_font(i); 1025 else 1026 h = ""; 1027 break; 1028 case 's': 1029 c++; 1030 j = 0; 1031 i = 0; 1032 if (*c == '-') { 1033 j = -1; 1034 c++; 1035 } else if (*c == '+') { 1036 j = 1; 1037 c++; 1038 } 1039 if (*c == '0') 1040 c++; 1041 else if (*c == '\\') { 1042 c++; 1043 c = scan_escape(c); 1044 i = intresult; 1045 if (!j) 1046 j = 1; 1047 } else 1048 while (isdigit(*c) && (!i || (!j && i < 4))) 1049 i = i * 10 + (*c++) - '0'; 1050 if (!j) { 1051 j = 1; 1052 if (i) 1053 i = i - 10; 1054 } 1055 if (!skip_escape) 1056 h = change_to_size(i * j); 1057 else 1058 h = ""; 1059 c--; 1060 break; 1061 case 'n': 1062 c++; 1063 j = 0; 1064 switch (*c) { 1065 case '+': 1066 j = 1; 1067 c++; 1068 break; 1069 case '-': 1070 j = -1; 1071 c++; 1072 break; 1073 default: 1074 break; 1075 } 1076 if (*c == '(') { 1077 c++; 1078 i = V(c[0], c[1]); 1079 c = c + 1; 1080 } else { 1081 i = V(c[0], ' '); 1082 } 1083 intd = intdef; 1084 while (intd && intd->nr != i) 1085 intd = intd->next; 1086 if (intd) { 1087 intd->val = intd->val + j * intd->incr; 1088 intresult = intd->val; 1089 } else { 1090 switch (i) { 1091 case V('.', 's'): 1092 intresult = current_size; 1093 break; 1094 case V('.', 'f'): 1095 intresult = current_font; 1096 break; 1097 default: 1098 intresult = 0; 1099 break; 1100 } 1101 } 1102 h = ""; 1103 break; 1104 case 'w': 1105 c++; 1106 i = *c; 1107 c++; 1108 exoutputp = output_possible; 1109 exskipescape = skip_escape; 1110 output_possible = 0; 1111 skip_escape = 1; 1112 j = 0; 1113 while (*c != i) { 1114 j++; 1115 if (*c == escapesym) 1116 c = scan_escape(c + 1); 1117 else 1118 c++; 1119 } 1120 output_possible = exoutputp; 1121 skip_escape = exskipescape; 1122 intresult = j; 1123 break; 1124 case 'l': 1125 h = "<HR>"; 1126 curpos = 0; 1127 case 'b': 1128 case 'v': 1129 case 'x': 1130 case 'o': 1131 case 'L': 1132 case 'h': 1133 c++; 1134 i = *c; 1135 c++; 1136 exoutputp = output_possible; 1137 exskipescape = skip_escape; 1138 output_possible = 0; 1139 skip_escape = 1; 1140 while (*c != i) 1141 if (*c == escapesym) 1142 c = scan_escape(c + 1); 1143 else 1144 c++; 1145 output_possible = exoutputp; 1146 skip_escape = exskipescape; 1147 break; 1148 case 'c': 1149 no_newline_output = 1; 1150 break; 1151 case '{': 1152 newline_for_fun++; 1153 h = ""; 1154 break; 1155 case '}': 1156 if (newline_for_fun) 1157 newline_for_fun--; 1158 h = ""; 1159 break; 1160 case 'p': 1161 h = "<BR>\n"; 1162 curpos = 0; 1163 break; 1164 case 't': 1165 h = "\t"; 1166 curpos = (curpos + 8) & 0xfff8; 1167 break; 1168 case '<': 1169 h = "<"; 1170 curpos++; 1171 break; 1172 case '>': 1173 h = ">"; 1174 curpos++; 1175 break; 1176 case '\\': 1177 if (single_escape) { 1178 c--; 1179 break; 1180 } 1181 default: 1182 b[0] = *c; 1183 b[1] = 0; 1184 h = b; 1185 curpos++; 1186 break; 1187 } 1188 c++; 1189 if (!skip_escape) 1190 out_html(h); 1191 return c; 1192} 1193 1194typedef struct TABLEITEM TABLEITEM; 1195 1196struct TABLEITEM { 1197 char *contents; 1198 int size, align, valign, colspan, rowspan, font, vleft, vright, space, 1199 width; 1200 TABLEITEM *next; 1201}; 1202 1203static TABLEITEM emptyfield = {NULL, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, NULL}; 1204 1205typedef struct TABLEROW TABLEROW; 1206 1207struct TABLEROW { 1208 TABLEITEM *first; 1209 TABLEROW *prev, *next; 1210}; 1211 1212static char *tableopt[] = { 1213 "center", "expand", "box", "allbox", "doublebox", 1214 "tab", "linesize", "delim", NULL 1215}; 1216static int tableoptl[] = {6, 6, 3, 6, 9, 3, 8, 5, 0}; 1217 1218static void 1219clear_table(TABLEROW * table) 1220{ 1221 TABLEROW *tr1, *tr2; 1222 TABLEITEM *ti1, *ti2; 1223 1224 tr1 = table; 1225 while (tr1->prev) 1226 tr1 = tr1->prev; 1227 while (tr1) { 1228 ti1 = tr1->first; 1229 while (ti1) { 1230 ti2 = ti1->next; 1231 if (ti1->contents) 1232 free(ti1->contents); 1233 free(ti1); 1234 ti1 = ti2; 1235 } 1236 tr2 = tr1; 1237 tr1 = tr1->next; 1238 free(tr2); 1239 } 1240} 1241 1242static char *scan_expression(char *c, int *result); 1243 1244static char * 1245scan_format(char *c, TABLEROW ** result, int *maxcol) 1246{ 1247 TABLEROW *layout, *currow; 1248 TABLEITEM *curfield; 1249 int i, j; 1250 1251 if (*result) { 1252 clear_table(*result); 1253 } 1254 layout = currow = (TABLEROW *) malloc(sizeof(TABLEROW)); 1255 currow->next = currow->prev = NULL; 1256 currow->first = curfield = (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1257 *curfield = emptyfield; 1258 while (*c && *c != '.') { 1259 switch (*c) { 1260 case 'C': 1261 case 'c': 1262 case 'N': 1263 case 'n': 1264 case 'R': 1265 case 'r': 1266 case 'A': 1267 case 'a': 1268 case 'L': 1269 case 'l': 1270 case 'S': 1271 case 's': 1272 case '^': 1273 case '_': 1274 if (curfield->align) { 1275 curfield->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1276 curfield = curfield->next; 1277 *curfield = emptyfield; 1278 } 1279 curfield->align = toupper(*c); 1280 c++; 1281 break; 1282 case 'i': 1283 case 'I': 1284 case 'B': 1285 case 'b': 1286 curfield->font = toupper(*c); 1287 c++; 1288 break; 1289 case 'f': 1290 case 'F': 1291 c++; 1292 curfield->font = toupper(*c); 1293 c++; 1294 if (!isspace(*c)) 1295 c++; 1296 break; 1297 case 't': 1298 case 'T': 1299 curfield->valign = 't'; 1300 c++; 1301 break; 1302 case 'p': 1303 case 'P': 1304 c++; 1305 i = j = 0; 1306 if (*c == '+') { 1307 j = 1; 1308 c++; 1309 } 1310 if (*c == '-') { 1311 j = -1; 1312 c++; 1313 } 1314 while (isdigit(*c)) 1315 i = i * 10 + (*c++) - '0'; 1316 if (j) 1317 curfield->size = i * j; 1318 else 1319 curfield->size = j - 10; 1320 break; 1321 case 'v': 1322 case 'V': 1323 case 'w': 1324 case 'W': 1325 c = scan_expression(c + 2, &curfield->width); 1326 break; 1327 case '|': 1328 if (curfield->align) 1329 curfield->vleft++; 1330 else 1331 curfield->vright++; 1332 c++; 1333 break; 1334 case 'e': 1335 case 'E': 1336 c++; 1337 break; 1338 case '0': 1339 case '1': 1340 case '2': 1341 case '3': 1342 case '4': 1343 case '5': 1344 case '6': 1345 case '7': 1346 case '8': 1347 case '9': 1348 i = 0; 1349 while (isdigit(*c)) 1350 i = i * 10 + (*c++) - '0'; 1351 curfield->space = i; 1352 break; 1353 case ',': 1354 case '\n': 1355 currow->next = (TABLEROW *) malloc(sizeof(TABLEROW)); 1356 currow->next->prev = currow; 1357 currow = currow->next; 1358 currow->next = NULL; 1359 curfield = currow->first = (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1360 *curfield = emptyfield; 1361 c++; 1362 break; 1363 default: 1364 c++; 1365 break; 1366 } 1367 } 1368 if (*c == '.') 1369 while (*c++ != '\n'); 1370 *maxcol = 0; 1371 currow = layout; 1372 while (currow) { 1373 curfield = layout->first; 1374 i = 0; 1375 while (curfield) { 1376 i++; 1377 curfield = curfield->next; 1378 } 1379 if (i > *maxcol) 1380 *maxcol = i; 1381 currow = currow->next; 1382 } 1383 *result = layout; 1384 return c; 1385} 1386 1387static TABLEROW * 1388next_row(TABLEROW * tr) 1389{ 1390 if (tr->next) { 1391 tr = tr->next; 1392 if (!tr->next) 1393 next_row(tr); 1394 return tr; 1395 } else { 1396 TABLEITEM *ti, *ti2; 1397 1398 tr->next = (TABLEROW *) malloc(sizeof(TABLEROW)); 1399 tr->next->prev = tr; 1400 ti = tr->first; 1401 tr = tr->next; 1402 tr->next = NULL; 1403 if (ti) 1404 tr->first = ti2 = (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1405 else 1406 tr->first = ti2 = NULL; 1407 while (ti != ti2) { 1408 *ti2 = *ti; 1409 ti2->contents = NULL; 1410 if ((ti = ti->next)) { 1411 ti2->next = (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1412 } 1413 ti2 = ti2->next; 1414 } 1415 return tr; 1416 } 1417} 1418 1419static char itemreset[20] = "\\fR\\s0"; 1420 1421static char * 1422scan_table(char *c) 1423{ 1424 char *t, *h, *g; 1425 int center = 0, expand = 0, box = 0, border = 0, linesize = 1; 1426 int i, j, maxcol = 0, finished = 0; 1427 int oldfont, oldsize, oldfillout; 1428 char itemsep = '\t'; 1429 TABLEROW *layout = NULL, *currow, *ftable; 1430 TABLEITEM *curfield; 1431 1432 while (*c++ != '\n'); 1433 h = c; 1434 if (*h == '.') 1435 return c - 1; 1436 oldfont = current_font; 1437 oldsize = current_size; 1438 oldfillout = fillout; 1439 out_html(change_to_font(0)); 1440 out_html(change_to_size(0)); 1441 if (!fillout) { 1442 fillout = 1; 1443 out_html("</PRE>"); 1444 } 1445 while (*h && *h != '\n') 1446 h++; 1447 if (h[-1] == ';') { 1448 /* scan table options */ 1449 while (c < h) { 1450 while (isspace(*c)) 1451 c++; 1452 for (i = 0; tableopt[i] && strncmp(tableopt[i], c, tableoptl[i]); i++); 1453 c = c + tableoptl[i]; 1454 switch (i) { 1455 case 0: 1456 center = 1; 1457 break; 1458 case 1: 1459 expand = 1; 1460 break; 1461 case 2: 1462 box = 1; 1463 break; 1464 case 3: 1465 border = 1; 1466 break; 1467 case 4: 1468 box = 2; 1469 break; 1470 case 5: 1471 while (*c++ != '('); 1472 itemsep = *c++; 1473 break; 1474 case 6: 1475 while (*c++ != '('); 1476 linesize = 0; 1477 while (isdigit(*c)) 1478 linesize = linesize * 10 + (*c++) - '0'; 1479 break; 1480 case 7: 1481 while (*c != ')') 1482 c++; 1483 default: 1484 break; 1485 } 1486 c++; 1487 } 1488 c = h + 1; 1489 } 1490 /* scan layout */ 1491 c = scan_format(c, &layout, &maxcol); 1492 currow = layout; 1493 next_row(currow); 1494 curfield = layout->first; 1495 i = 0; 1496 while (!finished) { 1497 /* search item */ 1498 h = c; 1499 if ((*c == '_' || *c == '=') && (c[1] == itemsep || c[1] == '\n')) { 1500 if (c[-1] == '\n' && c[1] == '\n') { 1501 if (currow->prev) { 1502 currow->prev->next = (TABLEROW *) malloc(sizeof(TABLEROW)); 1503 currow->prev->next->next = currow; 1504 currow->prev->next->prev = currow->prev; 1505 currow->prev = currow->prev->next; 1506 } else { 1507 currow->prev = layout = (TABLEROW *) malloc(sizeof(TABLEROW)); 1508 currow->prev->prev = NULL; 1509 currow->prev->next = currow; 1510 } 1511 curfield = currow->prev->first = 1512 (TABLEITEM *) malloc(sizeof(TABLEITEM)); 1513 *curfield = emptyfield; 1514 curfield->align = *c; 1515 curfield->colspan = maxcol; 1516 curfield = currow->first; 1517 c = c + 2; 1518 } else { 1519 if (curfield) { 1520 curfield->align = *c; 1521 do { 1522 curfield = curfield->next; 1523 } while (curfield && curfield->align == 'S'); 1524 } 1525 if (c[1] == '\n') { 1526 currow = next_row(currow); 1527 curfield = currow->first; 1528 } 1529 c = c + 2; 1530 } 1531 } else if (*c == 'T' && c[1] == '{') { 1532 h = c + 2; 1533 c = strstr(h, "\nT}"); 1534 c++; 1535 *c = '\0'; 1536 g = NULL; 1537 scan_troff(h, 0, &g); 1538 scan_troff(itemreset, 0, &g); 1539 *c = 'T'; 1540 c += 3; 1541 if (curfield) { 1542 curfield->contents = g; 1543 do { 1544 curfield = curfield->next; 1545 } while (curfield && curfield->align == 'S'); 1546 } else if (g) 1547 free(g); 1548 if (c[-1] == '\n') { 1549 currow = next_row(currow); 1550 curfield = currow->first; 1551 } 1552 } else if (*c == '.' && c[1] == 'T' && c[2] == '&' && c[-1] == '\n') { 1553 TABLEROW *hr; 1554 1555 while (*c++ != '\n'); 1556 hr = currow; 1557 currow = currow->prev; 1558 hr->prev = NULL; 1559 c = scan_format(c, &hr, &i); 1560 hr->prev = currow; 1561 currow->next = hr; 1562 currow = hr; 1563 next_row(currow); 1564 curfield = currow->first; 1565 } else if (*c == '.' && c[1] == 'T' && c[2] == 'E' && c[-1] == '\n') { 1566 finished = 1; 1567 while (*c++ != '\n'); 1568 if (currow->prev) 1569 currow->prev->next = NULL; 1570 currow->prev = NULL; 1571 clear_table(currow); 1572 } else if (*c == '.' && c[-1] == '\n' && !isdigit(c[1])) { 1573 /* 1574 * skip troff request inside table (usually only .sp 1575 * ) 1576 */ 1577 while (*c++ != '\n'); 1578 } else { 1579 h = c; 1580 while (*c && (*c != itemsep || c[-1] == '\\') && 1581 (*c != '\n' || c[-1] == '\\')) 1582 c++; 1583 i = 0; 1584 if (*c == itemsep) { 1585 i = 1; 1586 *c = '\n'; 1587 } 1588 if (h[0] == '\\' && h[2] == '\n' && 1589 (h[1] == '_' || h[1] == '^')) { 1590 if (curfield) { 1591 curfield->align = h[1]; 1592 do { 1593 curfield = curfield->next; 1594 } while (curfield && curfield->align == 'S'); 1595 } 1596 h = h + 3; 1597 } else { 1598 g = NULL; 1599 h = scan_troff(h, 1, &g); 1600 scan_troff(itemreset, 0, &g); 1601 if (curfield) { 1602 curfield->contents = g; 1603 do { 1604 curfield = curfield->next; 1605 } while (curfield && curfield->align == 'S'); 1606 } else if (g) 1607 free(g); 1608 } 1609 if (i) 1610 *c = itemsep; 1611 c = h; 1612 if (c[-1] == '\n') { 1613 currow = next_row(currow); 1614 curfield = currow->first; 1615 } 1616 } 1617 } 1618 /* calculate colspan and rowspan */ 1619 currow = layout; 1620 while (currow->next) 1621 currow = currow->next; 1622 while (currow) { 1623 TABLEITEM *ti, *ti1 = NULL, *ti2 = NULL; 1624 1625 ti = currow->first; 1626 if (currow->prev) 1627 ti1 = currow->prev->first; 1628 while (ti) { 1629 switch (ti->align) { 1630 case 'S': 1631 if (ti2) { 1632 ti2->colspan++; 1633 if (ti2->rowspan < ti->rowspan) 1634 ti2->rowspan = ti->rowspan; 1635 } 1636 break; 1637 case '^': 1638 if (ti1) 1639 ti1->rowspan++; 1640 default: 1641 if (!ti2) 1642 ti2 = ti; 1643 else { 1644 do { 1645 ti2 = ti2->next; 1646 } while (ti2 && curfield->align == 'S'); 1647 } 1648 break; 1649 } 1650 ti = ti->next; 1651 if (ti1) 1652 ti1 = ti1->next; 1653 } 1654 currow = currow->prev; 1655 } 1656 /* produce html output */ 1657 if (center) 1658 out_html("<CENTER>"); 1659 if (box == 2) 1660 out_html("<TABLE BORDER><TR><TD>"); 1661 out_html("<TABLE"); 1662 if (box || border) { 1663 out_html(" BORDER"); 1664 if (!border) 1665 out_html("><TR><TD><TABLE"); 1666 if (expand) 1667 out_html(" WIDTH=100%"); 1668 } 1669 out_html(">\n"); 1670 currow = layout; 1671 while (currow) { 1672 j = 0; 1673 out_html("<TR VALIGN=top>"); 1674 curfield = currow->first; 1675 while (curfield) { 1676 if (curfield->align != 'S' && curfield->align != '^') { 1677 out_html("<TD"); 1678 switch (curfield->align) { 1679 case 'N': 1680 curfield->space += 4; 1681 case 'R': 1682 out_html(" ALIGN=right"); 1683 break; 1684 case 'C': 1685 out_html(" ALIGN=center"); 1686 default: 1687 break; 1688 } 1689 if (!curfield->valign && curfield->rowspan > 1) 1690 out_html(" VALIGN=center"); 1691 if (curfield->colspan > 1) { 1692 char buf[5]; 1693 1694 out_html(" COLSPAN="); 1695 sprintf(buf, "%i", curfield->colspan); 1696 out_html(buf); 1697 } 1698 if (curfield->rowspan > 1) { 1699 char buf[5]; 1700 1701 out_html(" ROWSPAN="); 1702 sprintf(buf, "%i", curfield->rowspan); 1703 out_html(buf); 1704 } 1705 j = j + curfield->colspan; 1706 out_html(">"); 1707 if (curfield->size) 1708 out_html(change_to_size(curfield->size)); 1709 if (curfield->font) 1710 out_html(change_to_font(curfield->font)); 1711 switch (curfield->align) { 1712 case '=': 1713 out_html("<HR><HR>"); 1714 break; 1715 case '_': 1716 out_html("<HR>"); 1717 break; 1718 default: 1719 if (curfield->contents) 1720 out_html(curfield->contents); 1721 break; 1722 } 1723 if (curfield->space) 1724 for (i = 0; i < curfield->space; i++) 1725 out_html(" "); 1726 if (curfield->font) 1727 out_html(change_to_font(0)); 1728 if (curfield->size) 1729 out_html(change_to_size(0)); 1730 if (j >= maxcol && curfield->align > '@' && curfield->align != '_') 1731 out_html("<BR>"); 1732 out_html("</TD>"); 1733 } 1734 curfield = curfield->next; 1735 } 1736 out_html("</TR>\n"); 1737 currow = currow->next; 1738 } 1739 if (box && !border) 1740 out_html("</TABLE>"); 1741 out_html("</TABLE>"); 1742 if (box == 2) 1743 out_html("</TABLE>"); 1744 if (center) 1745 out_html("</CENTER>\n"); 1746 else 1747 out_html("\n"); 1748 if (!oldfillout) 1749 out_html("<PRE>"); 1750 fillout = oldfillout; 1751 out_html(change_to_size(oldsize)); 1752 out_html(change_to_font(oldfont)); 1753 return c; 1754} 1755 1756static char * 1757scan_expression(char *c, int *result) 1758{ 1759 int value = 0, value2, j = 0, sign = 1, opex = 0; 1760 char oper = 'c'; 1761 1762 if (*c == '!') { 1763 c = scan_expression(c + 1, &value); 1764 value = (!value); 1765 } else if (*c == 'n') { 1766 c++; 1767 value = NROFF; 1768 } else if (*c == 't') { 1769 c++; 1770 value = 1 - NROFF; 1771 } else if (*c == '\'' || *c == '"' || *c < ' ' || (*c == '\\' && c[1] == '(')) { 1772 /* 1773 * ?string1?string2? test if string1 equals string2. 1774 */ 1775 char *st1 = NULL, *st2 = NULL, *h; 1776 char *tcmp = NULL; 1777 char sep; 1778 1779 sep = *c; 1780 if (sep == '\\') { 1781 tcmp = c; 1782 c = c + 3; 1783 } 1784 c++; 1785 h = c; 1786 while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) 1787 c++; 1788 *c = '\n'; 1789 scan_troff(h, 1, &st1); 1790 *c = sep; 1791 if (tcmp) 1792 c = c + 3; 1793 c++; 1794 h = c; 1795 while (*c != sep && (!tcmp || strncmp(c, tcmp, 4))) 1796 c++; 1797 *c = '\n'; 1798 scan_troff(h, 1, &st2); 1799 *c = sep; 1800 if (!st1 && !st2) 1801 value = 1; 1802 else if (!st1 || !st2) 1803 value = 0; 1804 else 1805 value = (!strcmp(st1, st2)); 1806 if (st1) 1807 free(st1); 1808 if (st2) 1809 free(st2); 1810 if (tcmp) 1811 c = c + 3; 1812 c++; 1813 } else { 1814 while (*c && !isspace(*c) && *c != ')') { 1815 opex = 0; 1816 switch (*c) { 1817 case '(': 1818 c = scan_expression(c + 1, &value2); 1819 value2 = sign * value2; 1820 opex = 1; 1821 break; 1822 case '.': 1823 case '0': 1824 case '1': 1825 case '2': 1826 case '3': 1827 case '4': 1828 case '5': 1829 case '6': 1830 case '7': 1831 case '8': 1832 case '9':{ 1833 int num = 0, denum = 1; 1834 1835 value2 = 0; 1836 while (isdigit(*c)) 1837 value2 = value2 * 10 + ((*c++) - '0'); 1838 if (*c == '.') { 1839 c++; 1840 while (isdigit(*c)) { 1841 num = num * 10 + ((*c++) - '0'); 1842 denum = denum * 10; 1843 } 1844 } 1845 if (isalpha(*c)) { 1846 /* scale indicator */ 1847 switch (*c) { 1848 case 'i': /* inch -> 10pt */ 1849 value2 = value2 * 10 + (num * 10 + denum / 2) / denum; 1850 num = 0; 1851 break; 1852 default: 1853 break; 1854 } 1855 c++; 1856 } 1857 value2 = value2 + (num + denum / 2) / denum; 1858 value2 = sign * value2; 1859 opex = 1; 1860 break; 1861 } 1862 case '\\': 1863 c = scan_escape(c + 1); 1864 value2 = intresult * sign; 1865 if (isalpha(*c)) 1866 c++; /* scale indicator */ 1867 opex = 1; 1868 break; 1869 case '-': 1870 if (oper) { 1871 sign = -1; 1872 c++; 1873 break; 1874 } 1875 case '>': 1876 case '<': 1877 case '+': 1878 case '/': 1879 case '*': 1880 case '%': 1881 case '&': 1882 case '=': 1883 case ':': 1884 if (c[1] == '=') 1885 oper = (*c++) + 16; 1886 else 1887 oper = *c; 1888 c++; 1889 break; 1890 default: 1891 c++; 1892 break; 1893 } 1894 if (opex) { 1895 sign = 1; 1896 switch (oper) { 1897 case 'c': 1898 value = value2; 1899 break; 1900 case '-': 1901 value = value - value2; 1902 break; 1903 case '+': 1904 value = value + value2; 1905 break; 1906 case '*': 1907 value = value * value2; 1908 break; 1909 case '/': 1910 if (value2) 1911 value = value / value2; 1912 break; 1913 case '%': 1914 if (value2) 1915 value = value % value2; 1916 break; 1917 case '<': 1918 value = (value < value2); 1919 break; 1920 case '>': 1921 value = (value > value2); 1922 break; 1923 case '>' + 16: 1924 value = (value >= value2); 1925 break; 1926 case '<' + 16: 1927 value = (value <= value2); 1928 break; 1929 case '=': 1930 case '=' + 16: 1931 value = (value == value2); 1932 break; 1933 case '&': 1934 value = (value && value2); 1935 break; 1936 case ':': 1937 value = (value || value2); 1938 break; 1939 default: 1940 fprintf(stderr, "man2html: unknown operator %c.\n", oper); 1941 } 1942 oper = 0; 1943 } 1944 } 1945 if (*c == ')') 1946 c++; 1947 } 1948 *result = value; 1949 return c; 1950} 1951 1952static void 1953trans_char(char *c, char s, char t) 1954{ 1955 char *sl = c; 1956 int slash = 0; 1957 1958 while (*sl != '\n' || slash) { 1959 if (!slash) { 1960 if (*sl == escapesym) 1961 slash = 1; 1962 else if (*sl == s) 1963 *sl = t; 1964 } else 1965 slash = 0; 1966 sl++; 1967 } 1968} 1969 1970/* Remove \a from C in place. Return modified C. */ 1971static char * 1972unescape (char *c) 1973{ 1974 int i, l; 1975 1976 l = strlen (c); 1977 i = 0; 1978 while (i < l && c[i]) { 1979 if (c[i] == '\a') { 1980 if (c[i+1]) 1981 memmove(c + i, c + i + 1, strlen(c + i + 1) + 1); 1982 else { 1983 c[i] = '\0'; 1984 break; 1985 } 1986 } 1987 i++; 1988 } 1989 return c; 1990} 1991 1992static char * 1993fill_words(char *c, char *words[], int *n) 1994{ 1995 char *sl = c; 1996 int slash = 0; 1997 int skipspace = 0; 1998 1999 *n = 0; 2000 words[*n] = sl; 2001 while (*sl && (*sl != '\n' || slash)) { 2002 if (!slash) { 2003 if (*sl == '"') { 2004 *sl = '\a'; 2005 skipspace = !skipspace; 2006 } else if (*sl == '\a') { 2007 /* handle already-translated " */ 2008 skipspace = !skipspace; 2009 } else if (*sl == escapesym) 2010 slash = 1; 2011 else if ((*sl == ' ' || *sl == '\t') && !skipspace) { 2012 *sl = '\n'; 2013 if (words[*n] != sl) 2014 (*n)++; 2015 words[*n] = sl + 1; 2016 } 2017 } else { 2018 if (*sl == '"') { 2019 sl--; 2020 *sl = '\n'; 2021 if (words[*n] != sl) 2022 (*n)++; 2023 sl++; 2024 while (*sl && *sl != '\n') 2025 sl++; 2026 words[*n] = sl; 2027 sl--; 2028 } 2029 slash = 0; 2030 } 2031 sl++; 2032 } 2033 if (sl != words[*n]) 2034 (*n)++; 2035 return sl; 2036} 2037 2038static char *abbrev_list[] = { 2039 "GSBG", "Getting Started ", 2040 "SUBG", "Customizing SunOS", 2041 "SHBG", "Basic Troubleshooting", 2042 "SVBG", "SunView User's Guide", 2043 "MMBG", "Mail and Messages", 2044 "DMBG", "Doing More with SunOS", 2045 "UNBG", "Using the Network", 2046 "GDBG", "Games, Demos & Other Pursuits", 2047 "CHANGE", "SunOS 4.1 Release Manual", 2048 "INSTALL", "Installing SunOS 4.1", 2049 "ADMIN", "System and Network Administration", 2050 "SECUR", "Security Features Guide", 2051 "PROM", "PROM User's Manual", 2052 "DIAG", "Sun System Diagnostics", 2053 "SUNDIAG", "Sundiag User's Guide", 2054 "MANPAGES", "SunOS Reference Manual", 2055 "REFMAN", "SunOS Reference Manual", 2056 "SSI", "Sun System Introduction", 2057 "SSO", "System Services Overview", 2058 "TEXT", "Editing Text Files", 2059 "DOCS", "Formatting Documents", 2060 "TROFF", "Using <B>nroff</B> and <B>troff</B>", 2061 "INDEX", "Global Index", 2062 "CPG", "C Programmer's Guide", 2063 "CREF", "C Reference Manual", 2064 "ASSY", "Assembly Language Reference", 2065 "PUL", "Programming Utilities and Libraries", 2066 "DEBUG", "Debugging Tools", 2067 "NETP", "Network Programming", 2068 "DRIVER", "Writing Device Drivers", 2069 "STREAMS", "STREAMS Programming", 2070 "SBDK", "SBus Developer's Kit", 2071 "WDDS", "Writing Device Drivers for the SBus", 2072 "FPOINT", "Floating-Point Programmer's Guide", 2073 "SVPG", "SunView 1 Programmer's Guide", 2074 "SVSPG", "SunView 1 System Programmer's Guide", 2075 "PIXRCT", "Pixrect Reference Manual", 2076 "CGI", "SunCGI Reference Manual", 2077 "CORE", "SunCore Reference Manual", 2078 "4ASSY", "Sun-4 Assembly Language Reference", 2079 "SARCH", "<FONT SIZE=-1>SPARC</FONT> Architecture Manual", 2080 "KR", "The C Programming Language", 2081NULL, NULL}; 2082 2083static char * 2084lookup_abbrev(char *c) 2085{ 2086 int i = 0; 2087 2088 if (!c) 2089 return ""; 2090 while (abbrev_list[i] && strcmp(c, abbrev_list[i])) 2091 i = i + 2; 2092 if (abbrev_list[i]) 2093 return abbrev_list[i + 1]; 2094 else 2095 return c; 2096} 2097 2098static char manidx[NULL_TERMINATED(HUGE_STR_MAX)]; 2099static int subs = 0; 2100static int mip = 0; 2101static char label[5] = "lbAA"; 2102 2103static void 2104add_to_index(int level, char *item) 2105{ 2106 char *c = NULL; 2107 2108 label[3]++; 2109 if (label[3] > 'Z') { 2110 label[3] = 'A'; 2111 label[2]++; 2112 } 2113 if (level != subs) { 2114 if (subs) { 2115 strmaxcpy(manidx + mip, "</DL>\n", HUGE_STR_MAX - mip); 2116 mip += 6; 2117 } else { 2118 strmaxcpy(manidx + mip, "<DL>\n", HUGE_STR_MAX - mip); 2119 mip += 5; 2120 } 2121 } 2122 subs = level; 2123 scan_troff(item, 1, &c); 2124 sprintf(manidx + mip, "<DT><A HREF=\"#%s\">%s</A><DD>\n", label, c); 2125 if (c) 2126 free(c); 2127 while (manidx[mip]) 2128 mip++; 2129} 2130 2131static char * 2132skip_till_newline(char *c) 2133{ 2134 int lvl = 0; 2135 2136 while (*c && *c != '\n' || lvl > 0) { 2137 if (*c == '\\') { 2138 c++; 2139 if (*c == '}') 2140 lvl--; 2141 else if (*c == '{') 2142 lvl++; 2143 } 2144 c++; 2145 } 2146 c++; 2147 if (lvl < 0 && newline_for_fun) { 2148 newline_for_fun = newline_for_fun + lvl; 2149 if (newline_for_fun < 0) 2150 newline_for_fun = 0; 2151 } 2152 return c; 2153} 2154 2155static void 2156outputPageHeader(char *l, char *c, char *r) 2157{ 2158 out_html("<TABLE WIDTH=100%>\n<TR>\n"); 2159 out_html("<TH ALIGN=LEFT width=33%>"); 2160 out_html(l); 2161 out_html("<TH ALIGN=CENTER width=33%>"); 2162 out_html(c); 2163 out_html("<TH ALIGN=RIGHT width=33%>"); 2164 out_html(r); 2165 out_html("\n</TR>\n</TABLE>\n"); 2166} 2167 2168static void 2169outputPageFooter(char *l, char *c, char *r) 2170{ 2171 out_html("<HR>\n"); 2172 outputPageHeader(l, c, r); 2173} 2174 2175static int ifelseval = 0; 2176 2177static char * 2178scan_request(char *c) 2179{ 2180 /* BSD Mandoc stuff */ 2181 static int mandoc_synopsis = 0; /* True if we are in the synopsis 2182 * section */ 2183 static int mandoc_command = 0; /* True if this is mandoc page */ 2184 static int mandoc_bd_options; /* Only copes with non-nested Bd's */ 2185 2186 int i, j, mode = 0; 2187 char *h; 2188 char *wordlist[MAX_WORDLIST]; 2189 int words; 2190 char *sl; 2191 STRDEF *owndef; 2192 2193 while (*c == ' ' || *c == '\t') 2194 c++; 2195 if (c[0] == '\n') 2196 return c + 1; 2197 if (c[1] == '\n') 2198 j = 1; 2199 else 2200 j = 2; 2201 while (c[j] == ' ' || c[j] == '\t') 2202 j++; 2203 if (c[0] == escapesym) { 2204 /* some pages use .\" .\$1 .\} */ 2205 /* .\$1 is too difficult/stupid */ 2206 if (c[1] == '$') 2207 c = skip_till_newline(c); 2208 else 2209 c = scan_escape(c + 1); 2210 } else { 2211 i = V(c[0], c[1]); 2212 switch (i) { 2213 case V('a', 'b'): 2214 h = c + j; 2215 while (*h && *h != '\n') 2216 h++; 2217 *h = '\0'; 2218 if (scaninbuff && buffpos) { 2219 buffer[buffpos] = '\0'; 2220 puts(buffer); 2221 } 2222 /* fprintf(stderr, "%s\n", c+2); */ 2223 exit(0); 2224 break; 2225 case V('d', 'i'): 2226 { 2227 STRDEF *de; 2228 int oldcurpos = curpos; 2229 2230 c = c + j; 2231 i = V(c[0], c[1]); 2232 if (*c == '\n') { 2233 c++; 2234 break; 2235 } 2236 while (*c && *c != '\n') 2237 c++; 2238 c++; 2239 h = c; 2240 while (*c && strncmp(c, ".di", 3)) 2241 while (*c && *c++ != '\n'); 2242 *c = '\0'; 2243 de = strdef; 2244 while (de && de->nr != i) 2245 de = de->next; 2246 if (!de) { 2247 de = (STRDEF *) malloc(sizeof(STRDEF)); 2248 de->nr = i; 2249 de->slen = 0; 2250 de->next = strdef; 2251 de->st = NULL; 2252 strdef = de; 2253 } else { 2254 if (de->st) 2255 free(de->st); 2256 de->slen = 0; 2257 de->st = NULL; 2258 } 2259 scan_troff(h, 0, &de->st); 2260 *c = '.'; 2261 while (*c && *c++ != '\n'); 2262 break; 2263 } 2264 case V('d', 's'): 2265 mode = 1; 2266 case V('a', 's'): 2267 { 2268 STRDEF *de; 2269 int oldcurpos = curpos; 2270 2271 c = c + j; 2272 i = V(c[0], c[1]); 2273 j = 0; 2274 while (c[j] && c[j] != '\n') 2275 j++; 2276 if (j < 3) { 2277 c = c + j; 2278 break; 2279 } 2280 if (c[1] == ' ') 2281 c = c + 1; 2282 else 2283 c = c + 2; 2284 while (isspace(*c)) 2285 c++; 2286 if (*c == '"') 2287 c++; 2288 de = strdef; 2289 while (de && de->nr != i) 2290 de = de->next; 2291 single_escape = 1; 2292 curpos = 0; 2293 if (!de) { 2294 char *h; 2295 2296 de = (STRDEF *) malloc(sizeof(STRDEF)); 2297 de->nr = i; 2298 de->slen = 0; 2299 de->next = strdef; 2300 de->st = NULL; 2301 strdef = de; 2302 h = NULL; 2303 c = scan_troff(c, 1, &h); 2304 de->st = h; 2305 de->slen = curpos; 2306 } else { 2307 if (mode) { 2308 char *h = NULL; 2309 2310 c = scan_troff(c, 1, &h); 2311 free(de->st); 2312 de->slen = 0; 2313 de->st = h; 2314 } else 2315 c = scan_troff(c, 1, &de->st); 2316 de->slen += curpos; 2317 } 2318 single_escape = 0; 2319 curpos = oldcurpos; 2320 } 2321 break; 2322 case V('b', 'r'): 2323 if (still_dd) 2324 out_html("<DD>"); 2325 else 2326 out_html("<BR>\n"); 2327 curpos = 0; 2328 c = c + j; 2329 if (c[0] == escapesym) { 2330 c = scan_escape(c + 1); 2331 } 2332 c = skip_till_newline(c); 2333 break; 2334 case V('c', '2'): 2335 c = c + j; 2336 if (*c != '\n') { 2337 nobreaksym = *c; 2338 } else 2339 nobreaksym = '\''; 2340 c = skip_till_newline(c); 2341 break; 2342 case V('c', 'c'): 2343 c = c + j; 2344 if (*c != '\n') { 2345 controlsym = *c; 2346 } else 2347 controlsym = '.'; 2348 c = skip_till_newline(c); 2349 break; 2350 case V('c', 'e'): 2351 c = c + j; 2352 if (*c == '\n') { 2353 i = 1; 2354 } else { 2355 i = 0; 2356 while ('0' <= *c && *c <= '9') { 2357 i = i * 10 + *c - '0'; 2358 c++; 2359 } 2360 } 2361 c = skip_till_newline(c); 2362 /* center next i lines */ 2363 if (i > 0) { 2364 out_html("<CENTER>\n"); 2365 while (i && *c) { 2366 char *line = NULL; 2367 2368 c = scan_troff(c, 1, &line); 2369 if (line && strncmp(line, "<BR>", 4)) { 2370 out_html(line); 2371 out_html("<BR>\n"); 2372 i--; 2373 } 2374 } 2375 out_html("</CENTER>\n"); 2376 curpos = 0; 2377 } 2378 break; 2379 case V('e', 'c'): 2380 c = c + j; 2381 if (*c != '\n') { 2382 escapesym = *c; 2383 } else 2384 escapesym = '\\'; 2385 break; 2386 c = skip_till_newline(c); 2387 case V('e', 'o'): 2388 escapesym = '\0'; 2389 c = skip_till_newline(c); 2390 break; 2391 case V('e', 'x'): 2392 exit(0); 2393 break; 2394 case V('f', 'c'): 2395 c = c + j; 2396 if (*c == '\n') { 2397 fieldsym = padsym = '\0'; 2398 } else { 2399 fieldsym = c[0]; 2400 padsym = c[1]; 2401 } 2402 c = skip_till_newline(c); 2403 break; 2404 case V('f', 'i'): 2405 if (!fillout) { 2406 out_html(change_to_font(0)); 2407 out_html(change_to_size('0')); 2408 out_html("</PRE>\n"); 2409 } 2410 curpos = 0; 2411 fillout = 1; 2412 c = skip_till_newline(c); 2413 break; 2414 case V('f', 't'): 2415 c = c + j; 2416 if (*c == '\n') { 2417 out_html(change_to_font(0)); 2418 } else { 2419 if (*c == escapesym) { 2420 int fn; 2421 2422 c = scan_expression(c, &fn); 2423 c--; 2424 out_html(change_to_font(fn)); 2425 } else { 2426 out_html(change_to_font(*c)); 2427 c++; 2428 } 2429 } 2430 c = skip_till_newline(c); 2431 break; 2432 case V('e', 'l'): 2433 /* .el anything : else part of if else */ 2434 if (ifelseval) { 2435 c = c + j; 2436 c[-1] = '\n'; 2437 c = scan_troff(c, 1, NULL); 2438 } else 2439 c = skip_till_newline(c + j); 2440 break; 2441 case V('i', 'e'): 2442 /* .ie c anything : then part of if else */ 2443 case V('i', 'f'): 2444 /* 2445 * .if c anything .if !c anything .if N anything .if 2446 * !N anything .if 'string1'string2' anything .if 2447 * !'string1'string2' anything 2448 */ 2449 c = c + j; 2450 c = scan_expression(c, &i); 2451 ifelseval = !i; 2452 if (i) { 2453 *c = '\n'; 2454 c++; 2455 c = scan_troff(c, 1, NULL); 2456 } else 2457 c = skip_till_newline(c); 2458 break; 2459 case V('i', 'g'): 2460 { 2461 char *endwith = "..\n"; 2462 2463 i = 3; 2464 c = c + j; 2465 if (*c != '\n') { 2466 endwith = c - 1; 2467 i = 1; 2468 c[-1] = '.'; 2469 while (*c && *c != '\n') 2470 c++, i++; 2471 } 2472 c++; 2473 while (*c && strncmp(c, endwith, i)) 2474 while (*c++ != '\n'); 2475 while (*c++ != '\n'); 2476 break; 2477 } 2478 case V('n', 'f'): 2479 if (fillout) { 2480 out_html(change_to_font(0)); 2481 out_html(change_to_size('0')); 2482 out_html("<PRE>\n"); 2483 } 2484 curpos = 0; 2485 fillout = 0; 2486 c = skip_till_newline(c); 2487 break; 2488 case V('p', 's'): 2489 c = c + j; 2490 if (*c == '\n') { 2491 out_html(change_to_size('0')); 2492 } else { 2493 j = 0; 2494 i = 0; 2495 if (*c == '-') { 2496 j = -1; 2497 c++; 2498 } else if (*c == '+') { 2499 j = 1; 2500 c++; 2501 } 2502 c = scan_expression(c, &i); 2503 if (!j) { 2504 j = 1; 2505 if (i > 5) 2506 i = i - 10; 2507 } 2508 out_html(change_to_size(i * j)); 2509 } 2510 c = skip_till_newline(c); 2511 break; 2512 case V('s', 'p'): 2513 c = c + j; 2514 if (fillout) 2515 out_html("<P>"); 2516 else { 2517 out_html(NEWLINE); 2518 NEWLINE[0] = '\n'; 2519 } 2520 curpos = 0; 2521 c = skip_till_newline(c); 2522 break; 2523 case V('s', 'o'): 2524 { 2525 FILE *f; 2526 struct stat stbuf; 2527 int l = 0; 2528 char *buf; 2529 char *name = NULL; 2530 2531 curpos = 0; 2532 c = c + j; 2533 if (*c == '/') { 2534 h = c; 2535 } else { 2536 h = c - 3; 2537 h[0] = '.'; 2538 h[1] = '.'; 2539 h[2] = '/'; 2540 } 2541 while (*c != '\n') 2542 c++; 2543 *c = '\0'; 2544 scan_troff(h, 1, &name); 2545 if (name[3] == '/') 2546 h = name + 3; 2547 else 2548 h = name; 2549 if (stat(h, &stbuf) != -1) 2550 l = stbuf.st_size; 2551 buf = stralloc(l + 4); 2552#if NOCGI 2553 if (!out_length) { 2554 char *t, *s; 2555 2556 t = strrchr(fname, '/'); 2557 if (!t) 2558 t = fname; 2559 fprintf(stderr, "ln -s %s.html %s.html\n", h, t); 2560 s = strrchr(t, '.'); 2561 if (!s) 2562 s = t; 2563 printf("<HTML><HEAD><TITLE> Manpage of %s</TITLE>\n" 2564 "</HEAD><BODY>\n" 2565 "See the manpage for <A HREF=\"%s.html\">%s</A>.\n" 2566 "</BODY></HTML>\n", 2567 s, h, h); 2568 } else 2569#endif 2570 { 2571 /* 2572 * this works alright, except for 2573 * section 3 2574 */ 2575 buf = read_man_page(h); 2576 if (!buf) { 2577 2578 fprintf(stderr, "man2html: unable to open or read file %s.\n", 2579 h); 2580 out_html("<BLOCKQUOTE>" 2581 "man2html: unable to open or read file.\n"); 2582 out_html(h); 2583 out_html("</BLOCKQUOTE>\n"); 2584 } else { 2585 buf[0] = buf[l] = '\n'; 2586 buf[l + 1] = buf[l + 2] = '\0'; 2587 scan_troff(buf + 1, 0, NULL); 2588 } 2589 if (buf) 2590 free(buf); 2591 } 2592 *c++ = '\n'; 2593 break; 2594 } 2595 case V('t', 'a'): 2596 c = c + j; 2597 j = 0; 2598 while (*c != '\n') { 2599 sl = scan_expression(c, &tabstops[j]); 2600 if (*c == '-' || *c == '+') 2601 tabstops[j] += tabstops[j - 1]; 2602 c = sl; 2603 while (*c == ' ' || *c == '\t') 2604 c++; 2605 j++; 2606 } 2607 maxtstop = j; 2608 curpos = 0; 2609 break; 2610 case V('t', 'i'): 2611 /* 2612 * while (itemdepth || dl_set[itemdepth]) { 2613 * out_html("</DL>\n"); if (dl_set[itemdepth]) 2614 * dl_set[itemdepth]=0; else itemdepth--; } 2615 */ 2616 out_html("<BR>\n"); 2617 c = c + j; 2618 c = scan_expression(c, &j); 2619 for (i = 0; i < j; i++) 2620 out_html(" "); 2621 curpos = j; 2622 c = skip_till_newline(c); 2623 break; 2624 case V('t', 'm'): 2625 c = c + j; 2626 h = c; 2627 while (*c != '\n') 2628 c++; 2629 *c = '\0'; 2630 /* fprintf(stderr,"%s\n", h); */ 2631 *c = '\n'; 2632 break; 2633 case V('B', ' '): 2634 case V('B', '\n'): 2635 case V('I', ' '): 2636 case V('I', '\n'): 2637 /* parse one line in a certain font */ 2638 out_html(change_to_font(*c)); 2639 trans_char(c, '"', '\a'); 2640 c = c + j; 2641 if (*c == '\n') 2642 c++; 2643 c = scan_troff(c, 1, NULL); 2644 out_html(change_to_font('R')); 2645 out_html(NEWLINE); 2646 if (fillout) 2647 curpos++; 2648 else 2649 curpos = 0; 2650 break; 2651 case V('O', 'P'): /* groff manpages use this 2652 * construction */ 2653 /* .OP a b : [ <B>a</B> <I>b</I> ] */ 2654 mode = 1; 2655 c[0] = 'B'; 2656 c[1] = 'I'; 2657 out_html(change_to_font('R')); 2658 out_html("["); 2659 curpos++; 2660 case V('B', 'R'): 2661 case V('B', 'I'): 2662 case V('I', 'B'): 2663 case V('I', 'R'): 2664 case V('R', 'B'): 2665 case V('R', 'I'): 2666 { 2667 char font[2]; 2668 2669 font[0] = c[0]; 2670 font[1] = c[1]; 2671 c = c + j; 2672 if (*c == '\n') 2673 c++; 2674 sl = fill_words(c, wordlist, &words); 2675 c = sl + 1; 2676 /* 2677 * .BR name (section) indicates a link. It 2678 * will be added in the output routine. 2679 */ 2680 for (i = 0; i < words; i++) { 2681 if (mode) { 2682 out_html(" "); 2683 curpos++; 2684 } 2685 wordlist[i][-1] = ' '; 2686 out_html(change_to_font(font[i & 1])); 2687 scan_troff(wordlist[i], 1, NULL); 2688 } 2689 out_html(change_to_font('R')); 2690 if (mode) { 2691 out_html(" ]"); 2692 curpos++; 2693 } 2694 out_html(NEWLINE); 2695 if (!fillout) 2696 curpos = 0; 2697 else 2698 curpos++; 2699 } 2700 break; 2701 case V('D', 'T'): 2702 for (j = 0; j < 20; j++) 2703 tabstops[j] = (j + 1) * 8; 2704 maxtstop = 20; 2705 c = skip_till_newline(c); 2706 break; 2707 case V('I', 'P'): 2708 sl = fill_words(c + j, wordlist, &words); 2709 c = sl + 1; 2710 if (!dl_set[itemdepth]) { 2711 out_html("<DL COMPACT>\n"); 2712 dl_set[itemdepth] = 1; 2713 } 2714 out_html("<DT>"); 2715 if (words) { 2716 scan_troff(wordlist[0], 1, NULL); 2717 } 2718 out_html("<DD>"); 2719 curpos = 0; 2720 break; 2721 case V('T', 'P'): 2722 if (!dl_set[itemdepth]) { 2723 out_html("<DL COMPACT>\n"); 2724 dl_set[itemdepth] = 1; 2725 } 2726 out_html("<DT>"); 2727 c = skip_till_newline(c); 2728 /* somewhere a definition ends with '.TP' */ 2729 if (!*c) 2730 still_dd = 1; 2731 else { 2732 c = scan_troff(c, 1, NULL); 2733 out_html("<DD>"); 2734 } 2735 curpos = 0; 2736 break; 2737 case V('I', 'X'): 2738 /* general index */ 2739 sl = fill_words(c + j, wordlist, &words); 2740 c = sl + 1; 2741 j = 4; 2742 while (idxlabel[j] == 'Z') 2743 idxlabel[j--] = 'A'; 2744 idxlabel[j]++; 2745#ifdef MAKEINDEX 2746 fprintf(idxfile, "%s@%s@", fname, idxlabel); 2747 for (j = 0; j < words; j++) { 2748 h = NULL; 2749 scan_troff(wordlist[j], 1, &h); 2750 fprintf(idxfile, "_\b@%s", h); 2751 free(h); 2752 } 2753 fprintf(idxfile, "\n"); 2754#endif 2755 out_html("<A NAME=\""); 2756 out_html(idxlabel); 2757 /* 2758 * this will not work in mosaic (due to a bug). 2759 * Adding ' ' between '>' and '<' solves it, but 2760 * creates some space. A normal space does not work. 2761 */ 2762 out_html("\"></A>"); 2763 break; 2764 case V('L', 'P'): 2765 case V('P', 'P'): 2766 if (dl_set[itemdepth]) { 2767 out_html("</DL>\n"); 2768 dl_set[itemdepth] = 0; 2769 } 2770 if (fillout) 2771 out_html("<P>\n"); 2772 else { 2773 out_html(NEWLINE); 2774 NEWLINE[0] = '\n'; 2775 } 2776 curpos = 0; 2777 c = skip_till_newline(c); 2778 break; 2779 case V('H', 'P'): 2780 if (!dl_set[itemdepth]) { 2781 out_html("<DL COMPACT>"); 2782 dl_set[itemdepth] = 1; 2783 } 2784 out_html("<DT>\n"); 2785 still_dd = 1; 2786 c = skip_till_newline(c); 2787 curpos = 0; 2788 break; 2789 case V('P', 'D'): 2790 c = skip_till_newline(c); 2791 break; 2792 case V('R', 's'): /* BSD mandoc */ 2793 case V('R', 'S'): 2794 sl = fill_words(c + j, wordlist, &words); 2795 j = 1; 2796 if (words > 0) 2797 scan_expression(wordlist[0], &j); 2798 if (j >= 0) { 2799 itemdepth++; 2800 dl_set[itemdepth] = 0; 2801 out_html("<DL COMPACT><DT><DD>"); 2802 c = skip_till_newline(c); 2803 curpos = 0; 2804 break; 2805 } 2806 case V('R', 'e'): /* BSD mandoc */ 2807 case V('R', 'E'): 2808 if (itemdepth > 0) { 2809 if (dl_set[itemdepth]) 2810 out_html("</DL>"); 2811 out_html("</DL>\n"); 2812 itemdepth--; 2813 } 2814 c = skip_till_newline(c); 2815 curpos = 0; 2816 break; 2817 case V('S', 'B'): 2818 out_html(change_to_size(-1)); 2819 out_html(change_to_font('B')); 2820 c = scan_troff(c + j, 1, NULL); 2821 out_html(change_to_font('R')); 2822 out_html(change_to_size('0')); 2823 break; 2824 case V('S', 'M'): 2825 c = c + j; 2826 if (*c == '\n') 2827 c++; 2828 out_html(change_to_size(-1)); 2829 trans_char(c, '"', '\a'); 2830 c = scan_troff(c, 1, NULL); 2831 out_html(change_to_size('0')); 2832 break; 2833 case V('S', 's'): /* BSD mandoc */ 2834 mandoc_command = 1; 2835 case V('S', 'S'): 2836 mode = 1; 2837 case V('S', 'h'): /* BSD mandoc */ 2838 /* hack for fallthru from above */ 2839 mandoc_command = !mode || mandoc_command; 2840 case V('S', 'H'): 2841 c = c + j; 2842 if (*c == '\n') 2843 c++; 2844 while (itemdepth || dl_set[itemdepth]) { 2845 out_html("</DL>\n"); 2846 if (dl_set[itemdepth]) 2847 dl_set[itemdepth] = 0; 2848 else if (itemdepth > 0) 2849 itemdepth--; 2850 } 2851 out_html(change_to_font(0)); 2852 out_html(change_to_size(0)); 2853 if (!fillout) { 2854 fillout = 1; 2855 out_html("</PRE>"); 2856 } 2857 trans_char(c, '"', '\a'); 2858 add_to_index(mode, c); 2859 out_html("<A NAME=\""); 2860 out_html(label); 2861 /* for mosaic users */ 2862 if (mode) 2863 out_html("\"> </A>\n<H4>"); 2864 else 2865 out_html("\"> </A>\n<H3>"); 2866 mandoc_synopsis = strncmp(c, "SYNOPSIS", 8) == 0; 2867 c = mandoc_command ? scan_troff_mandoc(c, 1, NULL) : scan_troff(c, 1, NULL); 2868 if (mode) 2869 out_html("</H4>\n"); 2870 else 2871 out_html("</H3>\n"); 2872 curpos = 0; 2873 break; 2874 case V('T', 'S'): 2875 c = scan_table(c); 2876 break; 2877 case V('D', 't'): /* BSD mandoc */ 2878 mandoc_command = 1; 2879 case V('T', 'H'): 2880 if (!output_possible) { 2881 sl = fill_words(c + j, wordlist, &words); 2882 if (words > 1) { 2883 char *t; 2884 for (i = 1; i < words; i++) 2885 wordlist[i][-1] = '\0'; 2886 *sl = '\0'; 2887 output_possible = 1; 2888 sprintf(th_page_and_sec, "%s(%s)", wordlist[0], wordlist[1]); 2889 if (words > 2) { 2890 t = unescape(wordlist[2]); 2891 strncpy(th_datestr, t, sizeof(th_datestr)); 2892 th_datestr[sizeof(th_datestr) - 1] = '\0'; 2893 } else 2894 th_datestr[0] = '\0'; 2895 if (words > 3) { 2896 t = unescape(wordlist[3]); 2897 strncpy(th_version, t, sizeof(th_version)); 2898 th_version[sizeof(th_version) - 1] = '\0'; 2899 } else 2900 th_version[0] = '\0'; 2901 out_html("<HTML><HEAD>\n<TITLE>"); 2902 out_html(th_page_and_sec); 2903 out_html(" Manual Page"); 2904 out_html("</TITLE>\n</HEAD>\n<BODY>"); 2905 2906 outputPageHeader(th_page_and_sec, th_datestr, th_page_and_sec); 2907 2908 out_html("<BR><A HREF=\"#index\">Index</A>\n"); 2909 *sl = '\n'; 2910 out_html("<HR>\n"); 2911 if (mandoc_command) 2912 out_html("<BR>BSD mandoc<BR>"); 2913 } 2914 c = sl + 1; 2915 } else 2916 c = skip_till_newline(c); 2917 curpos = 0; 2918 break; 2919 case V('T', 'X'): 2920 sl = fill_words(c + j, wordlist, &words); 2921 *sl = '\0'; 2922 out_html(change_to_font('I')); 2923 if (words > 1) 2924 wordlist[1][-1] = '\0'; 2925 c = lookup_abbrev(wordlist[0]); 2926 curpos += strlen(c); 2927 out_html(c); 2928 out_html(change_to_font('R')); 2929 if (words > 1) 2930 out_html(wordlist[1]); 2931 *sl = '\n'; 2932 c = sl + 1; 2933 break; 2934 case V('r', 'm'): 2935 /* .rm xx : Remove request, macro or string */ 2936 case V('r', 'n'): 2937 /* 2938 * .rn xx yy : Rename request, macro or string xx to 2939 * yy 2940 */ 2941 { 2942 STRDEF *de; 2943 2944 c = c + j; 2945 i = V(c[0], c[1]); 2946 c = c + 2; 2947 while (isspace(*c) && *c != '\n') 2948 c++; 2949 j = V(c[0], c[1]); 2950 while (*c && *c != '\n') 2951 c++; 2952 c++; 2953 de = strdef; 2954 while (de && de->nr != j) 2955 de = de->next; 2956 if (de) { 2957 if (de->st) 2958 free(de->st); 2959 de->nr = 0; 2960 } 2961 de = strdef; 2962 while (de && de->nr != i) 2963 de = de->next; 2964 if (de) 2965 de->nr = j; 2966 break; 2967 } 2968 case V('n', 'x'): 2969 /* .nx filename : next file. */ 2970 case V('i', 'n'): 2971 /* .in +-N : Indent */ 2972 c = skip_till_newline(c); 2973 break; 2974 case V('n', 'r'): 2975 /* 2976 * .nr R +-N M: define and set number register R by 2977 * +-N; auto-increment by M 2978 */ 2979 { 2980 INTDEF *intd; 2981 2982 c = c + j; 2983 i = V(c[0], c[1]); 2984 c = c + 2; 2985 intd = intdef; 2986 while (intd && intd->nr != i) 2987 intd = intd->next; 2988 if (!intd) { 2989 intd = (INTDEF *) malloc(sizeof(INTDEF)); 2990 intd->nr = i; 2991 intd->val = 0; 2992 intd->incr = 0; 2993 intd->next = intdef; 2994 intdef = intd; 2995 } 2996 while (*c == ' ' || *c == '\t') 2997 c++; 2998 c = scan_expression(c, &intd->val); 2999 if (*c != '\n') { 3000 while (*c == ' ' || *c == '\t') 3001 c++; 3002 c = scan_expression(c, &intd->incr); 3003 } 3004 c = skip_till_newline(c); 3005 break; 3006 } 3007 case V('a', 'm'): 3008 /* .am xx yy : append to a macro. */ 3009 /* define or handle as .ig yy */ 3010 mode = 1; 3011 case V('d', 'e'): 3012 /* 3013 * .de xx yy : define or redefine macro xx; end at 3014 * .yy (..) 3015 */ 3016 /* define or handle as .ig yy */ 3017 { 3018 STRDEF *de; 3019 int olen = 0; 3020 3021 c = c + j; 3022 sl = fill_words(c, wordlist, &words); 3023 i = V(c[0], c[1]); 3024 j = 2; 3025 if (words == 1) 3026 wordlist[1] = ".."; 3027 else { 3028 wordlist[1]--; 3029 wordlist[1][0] = '.'; 3030 j = 3; 3031 } 3032 c = sl + 1; 3033 sl = c; 3034 while (*c && strncmp(c, wordlist[1], j)) 3035 c = skip_till_newline(c); 3036 de = defdef; 3037 while (de && de->nr != i) 3038 de = de->next; 3039 if (mode && de) 3040 olen = strlen(de->st); 3041 j = olen + c - sl; 3042 h = stralloc(j * 2 + 4); 3043 if (h) { 3044 for (j = 0; j < olen; j++) 3045 h[j] = de->st[j]; 3046 if (!j || h[j - 1] != '\n') 3047 h[j++] = '\n'; 3048 while (sl != c) { 3049 if (sl[0] == '\\' && sl[1] == '\\') { 3050 h[j++] = '\\'; 3051 sl++; 3052 } else 3053 h[j++] = *sl; 3054 sl++; 3055 } 3056 h[j] = '\0'; 3057 if (de) { 3058 if (de->st) 3059 free(de->st); 3060 de->st = h; 3061 } else { 3062 de = (STRDEF *) malloc(sizeof(STRDEF)); 3063 de->nr = i; 3064 de->next = defdef; 3065 de->st = h; 3066 defdef = de; 3067 } 3068 } 3069 } 3070 c = skip_till_newline(c); 3071 break; 3072 case V('B', 'l'): /* BSD mandoc */ 3073 { 3074 char list_options[NULL_TERMINATED(MED_STR_MAX)]; 3075 char *nl = strchr(c, '\n'); 3076 3077 c = c + j; 3078 if (dl_set[itemdepth]) { /* These things can 3079 * nest. */ 3080 itemdepth++; 3081 } 3082 if (nl) { /* Parse list options */ 3083 strlimitcpy(list_options, c, nl - c, MED_STR_MAX); 3084 } 3085 if (strstr(list_options, "-bullet")) { /* HTML Unnumbered List */ 3086 dl_set[itemdepth] = BL_BULLET_LIST; 3087 out_html("<UL>\n"); 3088 } else if (strstr(list_options, "-enum")) { /* HTML Ordered List */ 3089 dl_set[itemdepth] = BL_ENUM_LIST; 3090 out_html("<OL>\n"); 3091 } else { /* HTML Descriptive List */ 3092 dl_set[itemdepth] = BL_DESC_LIST; 3093 out_html("<DL COMPACT>\n"); 3094 } 3095 if (fillout) 3096 out_html("<P>\n"); 3097 else { 3098 out_html(NEWLINE); 3099 NEWLINE[0] = '\n'; 3100 } 3101 curpos = 0; 3102 c = skip_till_newline(c); 3103 break; 3104 } 3105 case V('E', 'l'): /* BSD mandoc */ 3106 c = c + j; 3107 if (dl_set[itemdepth] & BL_DESC_LIST) { 3108 out_html("</DL>\n"); 3109 } else if (dl_set[itemdepth] & BL_BULLET_LIST) { 3110 out_html("</UL>\n"); 3111 } else if (dl_set[itemdepth] & BL_ENUM_LIST) { 3112 out_html("</OL>\n"); 3113 } 3114 dl_set[itemdepth] = 0; 3115 if (itemdepth > 0) 3116 itemdepth--; 3117 if (fillout) 3118 out_html("<P>\n"); 3119 else { 3120 out_html(NEWLINE); 3121 NEWLINE[0] = '\n'; 3122 } 3123 curpos = 0; 3124 c = skip_till_newline(c); 3125 break; 3126 case V('I', 't'): /* BSD mandoc */ 3127 c = c + j; 3128 if (strncmp(c, "Xo", 2) == 0 && isspace(*(c + 2))) { 3129 c = skip_till_newline(c); 3130 } 3131 if (dl_set[itemdepth] & BL_DESC_LIST) { 3132 out_html("<DT>"); 3133 out_html(change_to_font('B')); 3134 if (*c == '\n') { /* Don't allow embedded 3135 * comms after a newline */ 3136 c++; 3137 c = scan_troff(c, 1, NULL); 3138 } else { /* Do allow embedded comms on 3139 * the same line. */ 3140 c = scan_troff_mandoc(c, 1, NULL); 3141 } 3142 out_html(change_to_font('R')); 3143 out_html(NEWLINE); 3144 out_html("<DD>"); 3145 } else if (dl_set[itemdepth] & (BL_BULLET_LIST | BL_ENUM_LIST)) { 3146 out_html("<LI>"); 3147 c = scan_troff_mandoc(c, 1, NULL); 3148 out_html(NEWLINE); 3149 } 3150 if (fillout) 3151 curpos++; 3152 else 3153 curpos = 0; 3154 break; 3155 case V('B', 'k'): /* BSD mandoc */ 3156 case V('E', 'k'): /* BSD mandoc */ 3157 case V('D', 'd'): /* BSD mandoc */ 3158 case V('O', 's'): /* BSD mandoc */ 3159 trans_char(c, '"', '\a'); 3160 c = c + j; 3161 if (*c == '\n') 3162 c++; 3163 c = scan_troff_mandoc(c, 1, NULL); 3164 out_html(NEWLINE); 3165 if (fillout) 3166 curpos++; 3167 else 3168 curpos = 0; 3169 break; 3170 case V('B', 't'): /* BSD mandoc */ 3171 trans_char(c, '"', '\a'); 3172 c = c + j; 3173 out_html(" is currently in beta test."); 3174 if (fillout) 3175 curpos++; 3176 else 3177 curpos = 0; 3178 break; 3179 case V('B', 'x'): /* BSD mandoc */ 3180 trans_char(c, '"', '\a'); 3181 c = c + j; 3182 if (*c == '\n') 3183 c++; 3184 out_html("BSD "); 3185 c = scan_troff_mandoc(c, 1, NULL); 3186 if (fillout) 3187 curpos++; 3188 else 3189 curpos = 0; 3190 break; 3191 case V('D', 'l'): /* BSD mandoc */ 3192 c = c + j; 3193 out_html(NEWLINE); 3194 out_html("<BLOCKQUOTE>"); 3195 out_html(change_to_font('L')); 3196 if (*c == '\n') 3197 c++; 3198 c = scan_troff_mandoc(c, 1, NULL); 3199 out_html(change_to_font('R')); 3200 out_html("</BLOCKQUOTE>"); 3201 if (fillout) 3202 curpos++; 3203 else 3204 curpos = 0; 3205 break; 3206 case V('B', 'd'): /* BSD mandoc */ 3207 { /* Seems like a kind of example/literal mode */ 3208 char bd_options[NULL_TERMINATED(MED_STR_MAX)]; 3209 char *nl = strchr(c, '\n'); 3210 3211 c = c + j; 3212 if (nl) { 3213 strlimitcpy(bd_options, c, nl - c, MED_STR_MAX); 3214 } 3215 out_html(NEWLINE); 3216 mandoc_bd_options = 0; /* Remember options for 3217 * terminating Bl */ 3218 if (strstr(bd_options, "-offset indent")) { 3219 mandoc_bd_options |= BD_INDENT; 3220 out_html("<BLOCKQUOTE>\n"); 3221 } 3222 if (strstr(bd_options, "-literal") 3223 || strstr(bd_options, "-unfilled")) { 3224 if (fillout) { 3225 mandoc_bd_options |= BD_LITERAL; 3226 out_html(change_to_font(0)); 3227 out_html(change_to_size('0')); 3228 out_html("<PRE>\n"); 3229 } 3230 curpos = 0; 3231 fillout = 0; 3232 } 3233 c = skip_till_newline(c); 3234 break; 3235 } 3236 case V('E', 'd'): /* BSD mandoc */ 3237 if (mandoc_bd_options & BD_LITERAL) { 3238 if (!fillout) { 3239 out_html(change_to_font(0)); 3240 out_html(change_to_size('0')); 3241 out_html("</PRE>\n"); 3242 } 3243 } 3244 if (mandoc_bd_options & BD_INDENT) 3245 out_html("</BLOCKQUOTE>\n"); 3246 curpos = 0; 3247 fillout = 1; 3248 c = skip_till_newline(c); 3249 break; 3250 case V('B', 'e'): /* BSD mandoc */ 3251 c = c + j; 3252 if (fillout) 3253 out_html("<P>"); 3254 else { 3255 out_html(NEWLINE); 3256 NEWLINE[0] = '\n'; 3257 } 3258 curpos = 0; 3259 c = skip_till_newline(c); 3260 break; 3261 case V('X', 'r'): /* BSD mandoc */ 3262 { 3263 /* 3264 * Translate xyz 1 to xyz(1) Allow for 3265 * multiple spaces. Allow the section to be 3266 * missing. 3267 */ 3268 char buff[NULL_TERMINATED(MED_STR_MAX)]; 3269 char *bufptr; 3270 3271 trans_char(c, '"', '\a'); 3272 bufptr = buff; 3273 c = c + j; 3274 if (*c == '\n') 3275 c++; /* Skip spaces */ 3276 while (isspace(*c) && *c != '\n') 3277 c++; 3278 while (isalnum(*c)) { /* Copy the xyz part */ 3279 *bufptr = *c; 3280 bufptr++; 3281 if (bufptr >= buff + MED_STR_MAX) 3282 break; 3283 c++; 3284 } 3285 while (isspace(*c) && *c != '\n') 3286 c++; /* Skip spaces */ 3287 if (isdigit(*c)) { /* Convert the number if 3288 * there is one */ 3289 *bufptr = '('; 3290 bufptr++; 3291 if (bufptr < buff + MED_STR_MAX) { 3292 while (isalnum(*c)) { 3293 *bufptr = *c; 3294 bufptr++; 3295 if (bufptr >= buff + MED_STR_MAX) 3296 break; 3297 c++; 3298 } 3299 if (bufptr < buff + MED_STR_MAX) { 3300 *bufptr = ')'; 3301 bufptr++; 3302 } 3303 } 3304 } 3305 while (*c != '\n') { /* Copy the remainder */ 3306 if (!isspace(*c)) { 3307 *bufptr = *c; 3308 bufptr++; 3309 if (bufptr >= buff + MED_STR_MAX) 3310 break; 3311 } 3312 c++; 3313 } 3314 *bufptr = '\n'; 3315 scan_troff_mandoc(buff, 1, NULL); 3316 3317 out_html(NEWLINE); 3318 if (fillout) 3319 curpos++; 3320 else 3321 curpos = 0; 3322 } 3323 break; 3324 case V('F', 'l'): /* BSD mandoc */ 3325 trans_char(c, '"', '\a'); 3326 c = c + j; 3327 out_html("-"); 3328 if (*c != '\n') { 3329 out_html(change_to_font('B')); 3330 c = scan_troff_mandoc(c, 1, NULL); 3331 out_html(change_to_font('R')); 3332 } 3333 out_html(NEWLINE); 3334 if (fillout) 3335 curpos++; 3336 else 3337 curpos = 0; 3338 break; 3339 case V('P', 'a'): /* BSD mandoc */ 3340 case V('P', 'f'): /* BSD mandoc */ 3341 trans_char(c, '"', '\a'); 3342 c = c + j; 3343 if (*c == '\n') 3344 c++; 3345 c = scan_troff_mandoc(c, 1, NULL); 3346 out_html(NEWLINE); 3347 if (fillout) 3348 curpos++; 3349 else 3350 curpos = 0; 3351 break; 3352 case V('P', 'p'): /* BSD mandoc */ 3353 if (fillout) 3354 out_html("<P>\n"); 3355 else { 3356 out_html(NEWLINE); 3357 NEWLINE[0] = '\n'; 3358 } 3359 curpos = 0; 3360 c = skip_till_newline(c); 3361 break; 3362 case V('D', 'q'): /* BSD mandoc */ 3363 trans_char(c, '"', '\a'); 3364 c = c + j; 3365 if (*c == '\n') 3366 c++; 3367 out_html("``"); 3368 c = scan_troff_mandoc(c, 1, NULL); 3369 out_html("''"); 3370 out_html(NEWLINE); 3371 if (fillout) 3372 curpos++; 3373 else 3374 curpos = 0; 3375 break; 3376 case V('O', 'p'): /* BSD mandoc */ 3377 trans_char(c, '"', '\a'); 3378 c = c + j; 3379 if (*c == '\n') 3380 c++; 3381 out_html(change_to_font('R')); 3382 out_html("["); 3383 c = scan_troff_mandoc(c, 1, NULL); 3384 out_html(change_to_font('R')); 3385 out_html("]"); 3386 out_html(NEWLINE); 3387 if (fillout) 3388 curpos++; 3389 else 3390 curpos = 0; 3391 break; 3392 case V('O', 'o'): /* BSD mandoc */ 3393 trans_char(c, '"', '\a'); 3394 c = c + j; 3395 if (*c == '\n') 3396 c++; 3397 out_html(change_to_font('R')); 3398 out_html("["); 3399 c = scan_troff_mandoc(c, 1, NULL); 3400 if (fillout) 3401 curpos++; 3402 else 3403 curpos = 0; 3404 break; 3405 case V('O', 'c'): /* BSD mandoc */ 3406 trans_char(c, '"', '\a'); 3407 c = c + j; 3408 c = scan_troff_mandoc(c, 1, NULL); 3409 out_html(change_to_font('R')); 3410 out_html("]"); 3411 if (fillout) 3412 curpos++; 3413 else 3414 curpos = 0; 3415 break; 3416 case V('P', 'q'): /* BSD mandoc */ 3417 trans_char(c, '"', '\a'); 3418 c = c + j; 3419 if (*c == '\n') 3420 c++; 3421 out_html("("); 3422 c = scan_troff_mandoc(c, 1, NULL); 3423 out_html(")"); 3424 out_html(NEWLINE); 3425 if (fillout) 3426 curpos++; 3427 else 3428 curpos = 0; 3429 break; 3430 case V('Q', 'l'): /* BSD mandoc */ 3431 { /* Single quote first word in the line */ 3432 char *sp; 3433 3434 trans_char(c, '"', '\a'); 3435 c = c + j; 3436 if (*c == '\n') 3437 c++; 3438 sp = c; 3439 do { /* Find first whitespace after the 3440 * first word that isn't a mandoc 3441 * macro */ 3442 while (*sp && isspace(*sp)) 3443 sp++; 3444 while (*sp && !isspace(*sp)) 3445 sp++; 3446 } while (*sp && isupper(*(sp - 2)) && islower(*(sp - 1))); 3447 3448 /* 3449 * Use a newline to mark the end of text to 3450 * be quoted 3451 */ 3452 if (*sp) 3453 *sp = '\n'; 3454 out_html("`"); /* Quote the text */ 3455 c = scan_troff_mandoc(c, 1, NULL); 3456 out_html("'"); 3457 out_html(NEWLINE); 3458 if (fillout) 3459 curpos++; 3460 else 3461 curpos = 0; 3462 break; 3463 } 3464 case V('S', 'q'): /* BSD mandoc */ 3465 trans_char(c, '"', '\a'); 3466 c = c + j; 3467 if (*c == '\n') 3468 c++; 3469 out_html("`"); 3470 c = scan_troff_mandoc(c, 1, NULL); 3471 out_html("'"); 3472 out_html(NEWLINE); 3473 if (fillout) 3474 curpos++; 3475 else 3476 curpos = 0; 3477 break; 3478 case V('A', 'r'): /* BSD mandoc */ 3479 /* parse one line in italics */ 3480 out_html(change_to_font('I')); 3481 trans_char(c, '"', '\a'); 3482 c = c + j; 3483 if (*c == '\n') { /* An empty Ar means "file 3484 * ..." */ 3485 out_html("file ..."); 3486 } else { 3487 c = scan_troff_mandoc(c, 1, NULL); 3488 } 3489 out_html(change_to_font('R')); 3490 out_html(NEWLINE); 3491 if (fillout) 3492 curpos++; 3493 else 3494 curpos = 0; 3495 break; 3496 case V('A', 'd'): /* BSD mandoc */ 3497 case V('E', 'm'): /* BSD mandoc */ 3498 case V('V', 'a'): /* BSD mandoc */ 3499 case V('X', 'c'): /* BSD mandoc */ 3500 /* parse one line in italics */ 3501 out_html(change_to_font('I')); 3502 trans_char(c, '"', '\a'); 3503 c = c + j; 3504 if (*c == '\n') 3505 c++; 3506 c = scan_troff_mandoc(c, 1, NULL); 3507 out_html(change_to_font('R')); 3508 out_html(NEWLINE); 3509 if (fillout) 3510 curpos++; 3511 else 3512 curpos = 0; 3513 break; 3514 case V('N', 'd'): /* BSD mandoc */ 3515 trans_char(c, '"', '\a'); 3516 c = c + j; 3517 if (*c == '\n') 3518 c++; 3519 out_html(" - "); 3520 c = scan_troff_mandoc(c, 1, NULL); 3521 out_html(NEWLINE); 3522 if (fillout) 3523 curpos++; 3524 else 3525 curpos = 0; 3526 break; 3527 case V('N', 'm'): /* BSD mandoc */ 3528 { 3529 static char mandoc_name[NULL_TERMINATED(SMALL_STR_MAX)] = ""; 3530 3531 trans_char(c, '"', '\a'); 3532 c = c + j; 3533 if (mandoc_synopsis) { /* Break lines only in 3534 * the Synopsis. The 3535 * Synopsis section 3536 * seems to be treated 3537 * as a special case - 3538 * Bummer! */ 3539 static int count = 0; /* Don't break on the 3540 * first Nm */ 3541 3542 if (count) { 3543 out_html("<BR>"); 3544 } else { 3545 char *end = strchr(c, '\n'); 3546 3547 if (end) { /* Remember the name for 3548 * later. */ 3549 strlimitcpy(mandoc_name, c, end - c, SMALL_STR_MAX); 3550 } 3551 } 3552 count++; 3553 } 3554 out_html(change_to_font('B')); 3555 while (*c == ' ' || *c == '\t') 3556 c++; 3557 if (*c == '\n') { /* If Nm has no 3558 * argument, use one 3559 * from an earlier Nm 3560 * command that did have 3561 * one. Hope there 3562 * aren't too many 3563 * commands that do 3564 * this. */ 3565 out_html(mandoc_name); 3566 } else { 3567 c = scan_troff_mandoc(c, 1, NULL); 3568 } 3569 out_html(change_to_font('R')); 3570 out_html(NEWLINE); 3571 if (fillout) 3572 curpos++; 3573 else 3574 curpos = 0; 3575 break; 3576 } 3577 case V('C', 'd'): /* BSD mandoc */ 3578 case V('C', 'm'): /* BSD mandoc */ 3579 case V('I', 'c'): /* BSD mandoc */ 3580 case V('M', 's'): /* BSD mandoc */ 3581 case V('O', 'r'): /* BSD mandoc */ 3582 case V('S', 'y'): /* BSD mandoc */ 3583 /* parse one line in bold */ 3584 out_html(change_to_font('B')); 3585 trans_char(c, '"', '\a'); 3586 c = c + j; 3587 if (*c == '\n') 3588 c++; 3589 c = scan_troff_mandoc(c, 1, NULL); 3590 out_html(change_to_font('R')); 3591 out_html(NEWLINE); 3592 if (fillout) 3593 curpos++; 3594 else 3595 curpos = 0; 3596 break; 3597 case V('D', 'v'): /* BSD mandoc */ 3598 case V('E', 'v'): /* BSD mandoc */ 3599 case V('F', 'r'): /* BSD mandoc */ 3600 case V('L', 'i'): /* BSD mandoc */ 3601 case V('N', 'o'): /* BSD mandoc */ 3602 case V('N', 's'): /* BSD mandoc */ 3603 case V('T', 'n'): /* BSD mandoc */ 3604 case V('n', 'N'): /* BSD mandoc */ 3605 trans_char(c, '"', '\a'); 3606 c = c + j; 3607 if (*c == '\n') 3608 c++; 3609 out_html(change_to_font('B')); 3610 c = scan_troff_mandoc(c, 1, NULL); 3611 out_html(change_to_font('R')); 3612 out_html(NEWLINE); 3613 if (fillout) 3614 curpos++; 3615 else 3616 curpos = 0; 3617 break; 3618 case V('%', 'A'): /* BSD mandoc biblio stuff */ 3619 case V('%', 'D'): 3620 case V('%', 'N'): 3621 case V('%', 'O'): 3622 case V('%', 'P'): 3623 case V('%', 'Q'): 3624 case V('%', 'V'): 3625 c = c + j; 3626 if (*c == '\n') 3627 c++; 3628 c = scan_troff(c, 1, NULL); /* Don't allow embedded 3629 * mandoc coms */ 3630 if (fillout) 3631 curpos++; 3632 else 3633 curpos = 0; 3634 break; 3635 case V('%', 'B'): 3636 case V('%', 'J'): 3637 case V('%', 'R'): 3638 case V('%', 'T'): 3639 c = c + j; 3640 out_html(change_to_font('I')); 3641 if (*c == '\n') 3642 c++; 3643 c = scan_troff(c, 1, NULL); /* Don't allow embedded 3644 * mandoc coms */ 3645 out_html(change_to_font('R')); 3646 if (fillout) 3647 curpos++; 3648 else 3649 curpos = 0; 3650 break; 3651 default: 3652 /* search macro database of self-defined macros */ 3653 owndef = defdef; 3654 while (owndef && owndef->nr != i) 3655 owndef = owndef->next; 3656 if (owndef) { 3657 char **oldargument; 3658 int deflen; 3659 int onff; 3660 3661 sl = fill_words(c + j, wordlist, &words); 3662 c = sl + 1; 3663 *sl = '\0'; 3664 for (i = 1; i < words; i++) 3665 wordlist[i][-1] = '\0'; 3666 for (i = 0; i < words; i++) { 3667 char *h = NULL; 3668 3669 if (mandoc_command) { 3670 scan_troff_mandoc(wordlist[i], 1, &h); 3671 } else { 3672 scan_troff(wordlist[i], 1, &h); 3673 } 3674 wordlist[i] = h; 3675 } 3676 for (i = words; i < 20; i++) 3677 wordlist[i] = NULL; 3678 deflen = strlen(owndef->st); 3679 for (i = 0; owndef->st[deflen + 2 + i] = owndef->st[i]; i++); 3680 oldargument = argument; 3681 argument = wordlist; 3682 onff = newline_for_fun; 3683 if (mandoc_command) { 3684 scan_troff_mandoc(owndef->st + deflen + 2, 0, NULL); 3685 } else { 3686 scan_troff(owndef->st + deflen + 2, 0, NULL); 3687 } 3688 newline_for_fun = onff; 3689 argument = oldargument; 3690 for (i = 0; i < words; i++) 3691 if (wordlist[i]) 3692 free(wordlist[i]); 3693 *sl = '\n'; 3694 } else if (mandoc_command && 3695 ((isupper(*c) && islower(*(c + 1))) 3696 || (islower(*c) && isupper(*(c + 1)))) 3697 ) { /* Let through any BSD mandoc 3698 * commands that haven't been delt 3699 * with. I don't want to miss 3700 * anything out of the text. */ 3701 char buf[4]; 3702 3703 strncpy(buf, c, 2); 3704 buf[2] = ' '; 3705 buf[3] = '\0'; 3706 out_html(buf); /* Print the command (it 3707 * might just be text). */ 3708 c = c + j; 3709 trans_char(c, '"', '\a'); 3710 if (*c == '\n') 3711 c++; 3712 out_html(change_to_font('R')); 3713 c = scan_troff(c, 1, NULL); 3714 out_html(NEWLINE); 3715 if (fillout) 3716 curpos++; 3717 else 3718 curpos = 0; 3719 } else { 3720 c = skip_till_newline(c); 3721 } 3722 break; 3723 } 3724 } 3725 if (fillout) { 3726 out_html(NEWLINE); 3727 curpos++; 3728 } 3729 NEWLINE[0] = '\n'; 3730 return c; 3731} 3732 3733static void 3734flush(void) 3735{ 3736} 3737 3738static int contained_tab = 0; 3739static int mandoc_line = 0; /* Signals whether to look for embedded 3740 * mandoc commands. */ 3741 3742/* san : stop at newline */ 3743static char * 3744scan_troff(char *c, int san, char **result) 3745{ 3746 char *h; 3747 char intbuff[NULL_TERMINATED(MED_STR_MAX)]; 3748 int ibp = 0; 3749 int i; 3750 char *exbuffer; 3751 int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun; 3752 int usenbsp = 0; 3753 3754#define FLUSHIBP if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; } 3755 3756 exbuffer = buffer; 3757 exbuffpos = buffpos; 3758 exbuffmax = buffmax; 3759 exnewline_for_fun = newline_for_fun; 3760 exscaninbuff = scaninbuff; 3761 newline_for_fun = 0; 3762 if (result) { 3763 if (*result) { 3764 buffer = *result; 3765 buffpos = strlen(buffer); 3766 buffmax = buffpos; 3767 } else { 3768 buffer = stralloc(LARGE_STR_MAX); 3769 buffpos = 0; 3770 buffmax = LARGE_STR_MAX; 3771 } 3772 scaninbuff = 1; 3773 } 3774 h = c; 3775 /* start scanning */ 3776 3777 while (*h && (!san || newline_for_fun || *h != '\n')) { 3778 3779 if (*h == escapesym) { 3780 h++; 3781 FLUSHIBP; 3782 h = scan_escape(h); 3783 } else if (*h == controlsym && h[-1] == '\n') { 3784 h++; 3785 FLUSHIBP; 3786 h = scan_request(h); 3787 if (san && h[-1] == '\n') 3788 h--; 3789 } else if (mandoc_line 3790 && *(h) && isupper(*(h)) 3791 && *(h + 1) && islower(*(h + 1)) 3792 && *(h + 2) && isspace(*(h + 2))) { 3793 /* 3794 * BSD imbedded command eg ".It Fl Ar arg1 Fl Ar 3795 * arg2" 3796 */ 3797 FLUSHIBP; 3798 h = scan_request(h); 3799 if (san && h[-1] == '\n') 3800 h--; 3801 } else if (*h == nobreaksym && h[-1] == '\n') { 3802 h++; 3803 FLUSHIBP; 3804 h = scan_request(h); 3805 if (san && h[-1] == '\n') 3806 h--; 3807 } else { 3808 int mx; 3809 3810 if (h[-1] == '\n' && still_dd && isalnum(*h)) { 3811 /* 3812 * sometimes a .HP request is not followed by 3813 * a .br request 3814 */ 3815 FLUSHIBP; 3816 out_html("<DD>"); 3817 curpos = 0; 3818 still_dd = 0; 3819 } 3820 switch (*h) { 3821 case '&': 3822 intbuff[ibp++] = '&'; 3823 intbuff[ibp++] = 'a'; 3824 intbuff[ibp++] = 'm'; 3825 intbuff[ibp++] = 'p'; 3826 intbuff[ibp++] = ';'; 3827 curpos++; 3828 break; 3829 case '<': 3830 intbuff[ibp++] = '&'; 3831 intbuff[ibp++] = 'l'; 3832 intbuff[ibp++] = 't'; 3833 intbuff[ibp++] = ';'; 3834 curpos++; 3835 break; 3836 case '>': 3837 intbuff[ibp++] = '&'; 3838 intbuff[ibp++] = 'g'; 3839 intbuff[ibp++] = 't'; 3840 intbuff[ibp++] = ';'; 3841 curpos++; 3842 break; 3843 case '"': 3844 intbuff[ibp++] = '&'; 3845 intbuff[ibp++] = 'q'; 3846 intbuff[ibp++] = 'u'; 3847 intbuff[ibp++] = 'o'; 3848 intbuff[ibp++] = 't'; 3849 intbuff[ibp++] = ';'; 3850 curpos++; 3851 break; 3852 case '\n': 3853 if (h[-1] == '\n' && fillout) { 3854 intbuff[ibp++] = '<'; 3855 intbuff[ibp++] = 'P'; 3856 intbuff[ibp++] = '>'; 3857 } 3858 if (contained_tab && fillout) { 3859 intbuff[ibp++] = '<'; 3860 intbuff[ibp++] = 'B'; 3861 intbuff[ibp++] = 'R'; 3862 intbuff[ibp++] = '>'; 3863 } 3864 contained_tab = 0; 3865 curpos = 0; 3866 usenbsp = 0; 3867 intbuff[ibp++] = '\n'; 3868 break; 3869 case '\t': 3870 { 3871 int curtab = 0; 3872 3873 contained_tab = 1; 3874 FLUSHIBP; 3875 /* like a typewriter, not like TeX */ 3876 tabstops[19] = curpos + 1; 3877 while (curtab < maxtstop && tabstops[curtab] <= curpos) 3878 curtab++; 3879 if (curtab < maxtstop) { 3880 if (!fillout) { 3881 while (curpos < tabstops[curtab]) { 3882 intbuff[ibp++] = ' '; 3883 if (ibp > 480) { 3884 FLUSHIBP; 3885 } 3886 curpos++; 3887 } 3888 } else { 3889 out_html("<TT>"); 3890 while (curpos < tabstops[curtab]) { 3891 out_html(" "); 3892 curpos++; 3893 } 3894 out_html("</TT>"); 3895 } 3896 } 3897 } 3898 break; 3899 default: 3900 if (*h == ' ' && (h[-1] == '\n' || usenbsp)) { 3901 FLUSHIBP; 3902 if (!usenbsp && fillout) { 3903 out_html("<BR>"); 3904 curpos = 0; 3905 } 3906 usenbsp = fillout; 3907 if (usenbsp) 3908 out_html(" "); 3909 else 3910 intbuff[ibp++] = ' '; 3911 } else if (*h > 31 && *h < 127) 3912 intbuff[ibp++] = *h; 3913 else if (((unsigned char) (*h)) > 127) { 3914 intbuff[ibp++] = '&'; 3915 intbuff[ibp++] = '#'; 3916 intbuff[ibp++] = '0' + ((unsigned char) (*h)) / 100; 3917 intbuff[ibp++] = '0' + (((unsigned char) (*h)) % 100) / 10; 3918 intbuff[ibp++] = '0' + ((unsigned char) (*h)) % 10; 3919 intbuff[ibp++] = ';'; 3920 } 3921 curpos++; 3922 break; 3923 } 3924 if (ibp > (MED_STR_MAX - 20)) 3925 FLUSHIBP; 3926 h++; 3927 } 3928 } 3929 FLUSHIBP; 3930 if (buffer) 3931 buffer[buffpos] = '\0'; 3932 if (san && *h) 3933 h++; 3934 newline_for_fun = exnewline_for_fun; 3935 if (result) { 3936 *result = buffer; 3937 buffer = exbuffer; 3938 buffpos = exbuffpos; 3939 buffmax = exbuffmax; 3940 scaninbuff = exscaninbuff; 3941 } 3942 return h; 3943} 3944 3945 3946static char * 3947scan_troff_mandoc(char *c, int san, char **result) 3948{ 3949 char *ret, *end = c; 3950 int oldval = mandoc_line; 3951 3952 mandoc_line = 1; 3953 while (*end && *end != '\n') { 3954 end++; 3955 } 3956 3957 if (end > c + 2 3958 && ispunct(*(end - 1)) 3959 && isspace(*(end - 2)) && *(end - 2) != '\n') { 3960 /* 3961 * Don't format lonely punctuation E.g. in "xyz ," format the 3962 * xyz and then append the comma removing the space. 3963 */ 3964 *(end - 2) = '\n'; 3965 ret = scan_troff(c, san, result); 3966 *(end - 2) = *(end - 1); 3967 *(end - 1) = ' '; 3968 } else { 3969 ret = scan_troff(c, san, result); 3970 } 3971 mandoc_line = oldval; 3972 return ret; 3973} 3974 3975main(int argc, char **argv) 3976{ 3977 FILE *f; 3978 char *t; 3979 int l, i; 3980 char *buf; 3981 char *h, *fullname; 3982 STRDEF *stdf; 3983 3984 t = NULL; 3985 while ((i = getopt(argc, argv, "")) != EOF) { 3986 switch (i) { 3987 default: 3988 usage(); 3989 exit(EXIT_USAGE); 3990 } 3991 } 3992 3993 if (argc != 2) { 3994 usage(); 3995 exit(EXIT_USAGE); 3996 } 3997 manpage = h = t = argv[1]; 3998 i = 0; 3999 4000 buf = read_man_page(h); 4001 if (!buf) { 4002 fprintf(stderr, "man2html: cannot read %s: %s\n", h, strerror(errno)); 4003 exit(1); 4004 } 4005#ifdef MAKEINDEX 4006 idxfile = fopen(INDEXFILE, "a"); 4007#endif 4008 stdf = &standardchar[0]; 4009 i = 0; 4010 while (stdf->nr) { 4011 stdf->next = &standardchar[i]; 4012 stdf = stdf->next; 4013 i++; 4014 } 4015 chardef = &standardchar[0]; 4016 4017 stdf = &standardstring[0]; 4018 i = 0; 4019 while (stdf->nr) { 4020 stdf->next = &standardstring[i]; 4021 stdf = stdf->next; 4022 i++; 4023 } 4024 strdef = &standardstring[0]; 4025 4026 intdef = &standardint[0]; 4027 i = 0; 4028 while (intdef->nr) { 4029 intdef->next = &standardint[i]; 4030 intdef = intdef->next; 4031 i++; 4032 } 4033 intdef = &standardint[0]; 4034 4035 defdef = NULL; 4036 4037 scan_troff(buf + 1, 0, NULL); 4038 4039 while (itemdepth || dl_set[itemdepth]) { 4040 out_html("</DL>\n"); 4041 if (dl_set[itemdepth]) 4042 dl_set[itemdepth] = 0; 4043 else if (itemdepth > 0) 4044 itemdepth--; 4045 } 4046 4047 out_html(change_to_font(0)); 4048 out_html(change_to_size(0)); 4049 if (!fillout) { 4050 fillout = 1; 4051 out_html("</PRE>"); 4052 } 4053 out_html(NEWLINE); 4054 4055 if (output_possible) { 4056 outputPageFooter(th_version, th_datestr, th_page_and_sec); 4057 /* for mosaic users */ 4058 fputs("<HR>\n<A NAME=\"index\"> </A><H2>Index</H2>\n<DL>\n", stdout); 4059 manidx[mip] = 0; 4060 fputs(manidx, stdout); 4061 if (subs) 4062 fputs("</DL>\n", stdout); 4063 fputs("</DL>\n", stdout); 4064 print_sig(); 4065 fputs("</BODY>\n</HTML>\n", stdout); 4066 } else 4067 fprintf(stderr, "man2html: no output produced\n"); 4068#ifdef MAKEINDEX 4069 if (idxfile) 4070 fclose(idxfile); 4071#endif 4072 exit(EXIT_SUCCESS); 4073} 4074