mutt stable branch with some hacks
at master 1418 lines 28 kB view raw
1/* 2 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19/** 20 ** This program parses mutt's init.h and generates documentation in 21 ** three different formats: 22 ** 23 ** -> a commented muttrc configuration file 24 ** -> nroff, suitable for inclusion in a manual page 25 ** -> docbook-xml, suitable for inclusion in the 26 ** SGML-based manual 27 ** 28 **/ 29 30#if HAVE_CONFIG_H 31# include "config.h" 32#endif 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <ctype.h> 38 39#include <errno.h> 40 41#ifdef HAVE_UNISTD_H 42# include <unistd.h> 43#endif 44 45#ifdef HAVE_GETOPT_H 46# include <getopt.h> 47#endif 48 49#include "makedoc-defs.h" 50 51#ifndef HAVE_STRERROR 52#ifndef STDC_HEADERS 53extern int sys_nerr; 54extern char *sys_errlist[]; 55#endif 56 57#define strerror(x) ((x) > 0 && (x) < sys_nerr) ? sys_errlist[(x)] : 0 58#endif /* !HAVE_STRERROR */ 59 60extern int optind; 61 62#define BUFFSIZE 2048 63 64enum output_formats_t 65{ 66 F_CONF, F_MAN, F_SGML, F_NONE 67}; 68 69#define D_NL (1 << 0) 70#define D_EM (1 << 1) 71#define D_BF (1 << 2) 72#define D_TAB (1 << 3) 73#define D_NP (1 << 4) 74#define D_INIT (1 << 5) 75#define D_DL (1 << 6) 76#define D_DT (1 << 7) 77#define D_DD (1 << 8) 78#define D_PA (1 << 9) 79#define D_IL (1 << 10) 80#define D_TT (1 << 11) 81 82enum 83{ 84 SP_START_EM, 85 SP_START_BF, 86 SP_START_TT, 87 SP_END_FT, 88 SP_NEWLINE, 89 SP_NEWPAR, 90 SP_END_PAR, 91 SP_STR, 92 SP_START_TAB, 93 SP_END_TAB, 94 SP_START_DL, 95 SP_DT, 96 SP_DD, 97 SP_END_DD, 98 SP_END_DL, 99 SP_START_IL, 100 SP_END_IL, 101 SP_END_SECT, 102 SP_REFER 103}; 104 105enum output_formats_t OutputFormat = F_NONE; 106char *Progname; 107short Debug = 0; 108 109static char *get_token (char *, size_t, char *); 110static char *skip_ws (char *); 111static const char *type2human (int); 112static int buff2type (const char *); 113static int flush_doc (int, FILE *); 114static int handle_docline (char *, FILE *, int); 115static int print_it (int, char *, FILE *, int); 116static void print_confline (const char *, int, const char *, FILE *); 117static void handle_confline (char *, FILE *); 118static void makedoc (FILE *, FILE *); 119static void pretty_default (char *, size_t, const char *, int); 120static int sgml_fputc (int, FILE *); 121static int sgml_fputs (const char *, FILE *); 122static int sgml_id_fputs (const char *, FILE *); 123 124int main (int argc, char *argv[]) 125{ 126 int c; 127 FILE *f; 128 129 if ((Progname = strrchr (argv[0], '/'))) 130 Progname++; 131 else 132 Progname = argv[0]; 133 134 while ((c = getopt (argc, argv, "cmsd")) != EOF) 135 { 136 switch (c) 137 { 138 case 'c': OutputFormat = F_CONF; break; 139 case 'm': OutputFormat = F_MAN; break; 140 case 's': OutputFormat = F_SGML; break; 141 case 'd': Debug++; break; 142 default: 143 { 144 fprintf (stderr, "%s: bad command line parameter.\n", Progname); 145 exit (1); 146 } 147 } 148 } 149 150 if (optind != argc) 151 { 152 if ((f = fopen (argv[optind], "r")) == NULL) 153 { 154 fprintf (stderr, "%s: Can't open %s (%s).\n", 155 Progname, argv[optind], strerror (errno)); 156 exit (1); 157 } 158 } 159 else 160 f = stdin; 161 162 switch (OutputFormat) 163 { 164 case F_CONF: 165 case F_MAN: 166 case F_SGML: makedoc (f, stdout); break; 167 default: 168 { 169 fprintf (stderr, "%s: No output format specified.\n", 170 Progname); 171 exit (1); 172 } 173 } 174 175 if (f != stdin) 176 fclose (f); 177 178 return 0; 179} 180 181 182static void makedoc (FILE *in, FILE *out) 183{ 184 char buffer[BUFFSIZE]; 185 char token[BUFFSIZE]; 186 char *p; 187 int active = 0; 188 int line = 0; 189 int docstat = D_INIT; 190 191 while ((fgets (buffer, sizeof (buffer), in))) 192 { 193 line++; 194 if ((p = strchr (buffer, '\n')) == NULL) 195 { 196 fprintf (stderr, "%s: Line %d too long. Ask a wizard to enlarge\n" 197 "%s: my buffer size.\n", Progname, line, Progname); 198 exit (1); 199 } 200 else 201 *p = '\0'; 202 203 if (!(p = get_token (token, sizeof (token), buffer))) 204 continue; 205 206 if (Debug) 207 { 208 fprintf (stderr, "%s: line %d. first token: \"%s\".\n", 209 Progname, line, token); 210 } 211 212 if (!strcmp (token, "/*++*/")) 213 active = 1; 214 else if (!strcmp (token, "/*--*/")) 215 { 216 docstat = flush_doc (docstat, out); 217 active = 0; 218 } 219 else if (active && (!strcmp (token, "/**") || !strcmp (token, "**"))) 220 docstat = handle_docline (p, out, docstat); 221 else if (active && !strcmp (token, "{")) 222 { 223 docstat = flush_doc (docstat, out); 224 handle_confline (p, out); 225 } 226 } 227 flush_doc (docstat, out); 228 fputs ("\n", out); 229} 230 231/* skip whitespace */ 232 233static char *skip_ws (char *s) 234{ 235 while (*s && isspace ((unsigned char) *s)) 236 s++; 237 238 return s; 239} 240 241/* isolate a token */ 242 243static char single_char_tokens[] = "[]{},;|"; 244 245static char *get_token (char *d, size_t l, char *s) 246{ 247 char *t; 248 short is_quoted = 0; 249 char *dd = d; 250 251 if (Debug) 252 fprintf (stderr, "%s: get_token called for `%s'.\n", 253 Progname, s); 254 255 s = skip_ws (s); 256 257 if (Debug > 1) 258 fprintf (stderr, "%s: argument after skip_ws(): `%s'.\n", 259 Progname, s); 260 261 if (!*s) 262 { 263 if (Debug) 264 fprintf (stderr, "%s: no more tokens on this line.\n", Progname); 265 return NULL; 266 } 267 268 if (strchr (single_char_tokens, *s)) 269 { 270 if (Debug) 271 { 272 fprintf (stderr, "%s: found single character token `%c'.\n", 273 Progname, *s); 274 } 275 d[0] = *s++; 276 d[1] = 0; 277 return s; 278 } 279 280 if (*s == '"') 281 { 282 if (Debug) 283 { 284 fprintf (stderr, "%s: found quote character.\n", Progname); 285 } 286 287 s++; 288 is_quoted = 1; 289 } 290 291 for (t = s; *t && --l > 0; t++) 292 { 293 if (*t == '\\' && !t[1]) 294 break; 295 296 if (is_quoted && *t == '\\') 297 { 298 switch ((*d = *++t)) 299 { 300 case 'n': *d = '\n'; break; 301 case 't': *d = '\t'; break; 302 case 'r': *d = '\r'; break; 303 case 'a': *d = '\a'; break; 304 } 305 306 d++; 307 continue; 308 } 309 310 if (is_quoted && *t == '"') 311 { 312 t++; 313 break; 314 } 315 else if (!is_quoted && strchr (single_char_tokens, *t)) 316 break; 317 else if (!is_quoted && isspace ((unsigned char) *t)) 318 break; 319 else 320 *d++ = *t; 321 } 322 323 *d = '\0'; 324 325 if (Debug) 326 { 327 fprintf (stderr, "%s: Got %stoken: `%s'.\n", 328 Progname, is_quoted ? "quoted " : "", dd); 329 fprintf (stderr, "%s: Remainder: `%s'.\n", 330 Progname, t); 331 } 332 333 return t; 334} 335 336 337/** 338 ** Configuration line parser 339 ** 340 ** The following code parses a line from init.h which declares 341 ** a configuration variable. 342 ** 343 **/ 344 345/* note: the following enum must be in the same order as the 346 * following string definitions! 347 */ 348 349enum 350{ 351 DT_NONE = 0, 352 DT_BOOL, 353 DT_NUM, 354 DT_STR, 355 DT_PATH, 356 DT_QUAD, 357 DT_SORT, 358 DT_RX, 359 DT_MAGIC, 360 DT_SYN, 361 DT_ADDR, 362 DT_MBCHARTBL 363}; 364 365struct 366{ 367 char *machine; 368 char *human; 369} 370types[] = 371{ 372 { "DT_NONE", "-none-" }, 373 { "DT_BOOL", "boolean" }, 374 { "DT_NUM", "number" }, 375 { "DT_STR", "string" }, 376 { "DT_PATH", "path" }, 377 { "DT_QUAD", "quadoption" }, 378 { "DT_SORT", "sort order" }, 379 { "DT_RX", "regular expression" }, 380 { "DT_MAGIC", "folder magic" }, 381 { "DT_SYN", NULL }, 382 { "DT_ADDR", "e-mail address" }, 383 { "DT_MBCHARTBL", "string" }, 384 { NULL, NULL } 385}; 386 387 388static int buff2type (const char *s) 389{ 390 int type; 391 392 for (type = DT_NONE; types[type].machine; type++) 393 if (!strcmp (types[type].machine, s)) 394 return type; 395 396 return DT_NONE; 397} 398 399static const char *type2human (int type) 400{ 401 return types[type].human; 402} 403static void handle_confline (char *s, FILE *out) 404{ 405 char varname[BUFFSIZE]; 406 char buff[BUFFSIZE]; 407 char tmp[BUFFSIZE]; 408 int type; 409 410 char val[BUFFSIZE]; 411 412 /* xxx - put this into an actual state machine? */ 413 414 /* variable name */ 415 if (!(s = get_token (varname, sizeof (varname), s))) return; 416 417 /* comma */ 418 if (!(s = get_token (buff, sizeof (buff), s))) return; 419 420 /* type */ 421 if (!(s = get_token (buff, sizeof (buff), s))) return; 422 423 type = buff2type (buff); 424 425 /* possibly a "|" or comma */ 426 if (!(s = get_token (buff, sizeof (buff), s))) return; 427 428 if (!strcmp (buff, "|")) 429 { 430 if (Debug) fprintf (stderr, "%s: Expecting <subtype> <comma>.\n", Progname); 431 /* ignore subtype and comma */ 432 if (!(s = get_token (buff, sizeof (buff), s))) return; 433 if (!(s = get_token (buff, sizeof (buff), s))) return; 434 } 435 436 /* redraw, comma */ 437 438 while (1) 439 { 440 if (!(s = get_token (buff, sizeof (buff), s))) return; 441 if (!strcmp (buff, ",")) 442 break; 443 } 444 445 /* option name or UL &address */ 446 if (!(s = get_token (buff, sizeof (buff), s))) return; 447 if (!strcmp (buff, "UL")) 448 if (!(s = get_token (buff, sizeof (buff), s))) return; 449 450 /* comma */ 451 if (!(s = get_token (buff, sizeof (buff), s))) return; 452 453 if (Debug) fprintf (stderr, "%s: Expecting default value.\n", Progname); 454 455 /* <default value> or UL <default value> */ 456 if (!(s = get_token (buff, sizeof (buff), s))) return; 457 if (!strcmp (buff, "UL")) 458 { 459 if (Debug) fprintf (stderr, "%s: Skipping UL.\n", Progname); 460 if (!(s = get_token (buff, sizeof (buff), s))) return; 461 } 462 463 memset (tmp, 0, sizeof (tmp)); 464 465 do 466 { 467 if (!strcmp (buff, "}")) 468 break; 469 470 strncpy (tmp + strlen (tmp), buff, sizeof (tmp) - strlen (tmp)); 471 } 472 while ((s = get_token (buff, sizeof (buff), s))); 473 474 pretty_default (val, sizeof (val), tmp, type); 475 print_confline (varname, type, val, out); 476} 477 478static void pretty_default (char *t, size_t l, const char *s, int type) 479{ 480 memset (t, 0, l); 481 l--; 482 483 switch (type) 484 { 485 case DT_QUAD: 486 { 487 if (!strcasecmp (s, "MUTT_YES")) strncpy (t, "yes", l); 488 else if (!strcasecmp (s, "MUTT_NO")) strncpy (t, "no", l); 489 else if (!strcasecmp (s, "MUTT_ASKYES")) strncpy (t, "ask-yes", l); 490 else if (!strcasecmp (s, "MUTT_ASKNO")) strncpy (t, "ask-no", l); 491 break; 492 } 493 case DT_BOOL: 494 { 495 if (atoi (s)) 496 strncpy (t, "yes", l); 497 else 498 strncpy (t, "no", l); 499 break; 500 } 501 case DT_SORT: 502 { 503 /* heuristic! */ 504 if (strncmp (s, "SORT_", 5)) 505 fprintf (stderr, 506 "WARNING: expected prefix of SORT_ for type DT_SORT instead of %s\n", s); 507 strncpy (t, s + 5, l); 508 for (; *t; t++) *t = tolower ((unsigned char) *t); 509 break; 510 } 511 case DT_MAGIC: 512 { 513 /* heuristic! */ 514 if (strncmp (s, "MUTT_", 5)) 515 fprintf (stderr, 516 "WARNING: expected prefix of MUTT_ for type DT_MAGIC instead of %s\n", s); 517 strncpy (t, s + 5, l); 518 for (; *t; t++) *t = tolower ((unsigned char) *t); 519 break; 520 } 521 case DT_STR: 522 case DT_RX: 523 case DT_ADDR: 524 case DT_PATH: 525 case DT_MBCHARTBL: 526 { 527 if (!strcmp (s, "0")) 528 break; 529 /* fallthrough */ 530 } 531 default: 532 { 533 strncpy (t, s, l); 534 break; 535 } 536 } 537} 538 539static void char_to_escape (char *dest, unsigned int c) 540{ 541 switch (c) 542 { 543 case '\r': strcpy (dest, "\\r"); break; /* __STRCPY_CHECKED__ */ 544 case '\n': strcpy (dest, "\\n"); break; /* __STRCPY_CHECKED__ */ 545 case '\t': strcpy (dest, "\\t"); break; /* __STRCPY_CHECKED__ */ 546 case '\f': strcpy (dest, "\\f"); break; /* __STRCPY_CHECKED__ */ 547 default: sprintf (dest, "\\%03o", c); break; 548 } 549} 550static void conf_char_to_escape (unsigned int c , FILE *out) 551{ 552 char buff[16]; 553 char_to_escape (buff, c); 554 fputs (buff, out); 555} 556 557static void conf_print_strval (const char *v, FILE *out) 558{ 559 for (; *v; v++) 560 { 561 if (*v < ' ' || *v & 0x80) 562 { 563 conf_char_to_escape ((unsigned int) *v, out); 564 continue; 565 } 566 567 if (*v == '"' || *v == '\\') 568 fputc ('\\', out); 569 fputc (*v, out); 570 } 571} 572 573static void man_print_strval (const char *v, FILE *out) 574{ 575 for (; *v; v++) 576 { 577 if (*v < ' ' || *v & 0x80) 578 { 579 fputc ('\\', out); 580 conf_char_to_escape ((unsigned int) *v, out); 581 continue; 582 } 583 584 if (*v == '"') 585 fputs ("\\(rq", out); 586 else if (*v == '\\') 587 fputs ("\\\\", out); 588 else if (*v == '-') 589 fputs ("\\-", out); 590 else 591 fputc (*v, out); 592 } 593} 594 595static void sgml_print_strval (const char *v, FILE *out) 596{ 597 char buff[16]; 598 for (; *v; v++) 599 { 600 if (*v < ' ' || *v & 0x80) 601 { 602 char_to_escape (buff, (unsigned int) *v); 603 sgml_fputs (buff, out); 604 continue; 605 } 606 sgml_fputc ((unsigned int) *v, out); 607 } 608} 609 610static int sgml_fputc (int c, FILE *out) 611{ 612 switch (c) 613 { 614 /* the bare minimum for escaping */ 615 case '<': return fputs ("&lt;", out); 616 case '>': return fputs ("&gt;", out); 617 case '&': return fputs ("&amp;", out); 618 default: return fputc (c, out); 619 } 620} 621 622static int sgml_fputs (const char *s, FILE *out) 623{ 624 for (; *s; s++) 625 if (sgml_fputc ((unsigned int) *s, out) == EOF) 626 return EOF; 627 628 return 0; 629} 630 631/* reduce CDATA to ID */ 632static int sgml_id_fputs (const char *s, FILE* out) 633{ 634 char id; 635 636 if (*s == '<') 637 s++; 638 639 for (; *s; s++) 640 { 641 if (*s == '_') 642 id = '-'; 643 else 644 id = *s; 645 if (*s == '>' && !*(s+1)) 646 break; 647 648 if (fputc ((unsigned int) id, out) == EOF) 649 return EOF; 650 } 651 652 return 0; 653} 654 655static void print_confline (const char *varname, int type, const char *val, FILE *out) 656{ 657 if (type == DT_SYN) return; 658 659 switch (OutputFormat) 660 { 661 /* configuration file */ 662 case F_CONF: 663 { 664 if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH || 665 type == DT_MBCHARTBL) 666 { 667 fprintf (out, "\n# set %s=\"", varname); 668 conf_print_strval (val, out); 669 fputs ("\"", out); 670 } 671 else if (type != DT_SYN) 672 fprintf (out, "\n# set %s=%s", varname, val); 673 674 fprintf (out, "\n#\n# Name: %s", varname); 675 fprintf (out, "\n# Type: %s", type2human (type)); 676 if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH || 677 type == DT_MBCHARTBL) 678 { 679 fputs ("\n# Default: \"", out); 680 conf_print_strval (val, out); 681 fputs ("\"", out); 682 } 683 else 684 fprintf (out, "\n# Default: %s", val); 685 686 fputs ("\n# ", out); 687 break; 688 } 689 690 /* manual page */ 691 case F_MAN: 692 { 693 fprintf (out, "\n.TP\n.B %s\n", varname); 694 fputs (".nf\n", out); 695 fprintf (out, "Type: %s\n", type2human (type)); 696 if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH || 697 type == DT_MBCHARTBL) 698 { 699 fputs ("Default: \\(lq", out); 700 man_print_strval (val, out); 701 fputs ("\\(rq\n", out); 702 } 703 else { 704 fputs ("Default: ", out); 705 man_print_strval (val, out); 706 fputs ("\n", out); 707 } 708 709 fputs (".fi", out); 710 711 break; 712 } 713 714 /* SGML based manual */ 715 case F_SGML: 716 { 717 fputs ("\n<sect2 id=\"", out); 718 sgml_id_fputs(varname, out); 719 fputs ("\">\n<title>", out); 720 sgml_fputs (varname, out); 721 fprintf (out, "</title>\n<literallayout>Type: %s", type2human (type)); 722 723 724 if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH || 725 type == DT_MBCHARTBL) 726 { 727 if (val && *val) 728 { 729 fputs ("\nDefault: <quote><literal>", out); 730 sgml_print_strval (val, out); 731 fputs ("</literal></quote>", out); 732 } 733 else 734 { 735 fputs ("\nDefault: (empty)", out); 736 } 737 fputs ("</literallayout>\n", out); 738 } 739 else 740 fprintf (out, "\nDefault: %s</literallayout>\n", val); 741 break; 742 } 743 /* make gcc happy */ 744 default: 745 break; 746 } 747} 748 749/** 750 ** Documentation line parser 751 ** 752 ** The following code parses specially formatted documentation 753 ** comments in init.h. 754 ** 755 ** The format is very remotely inspired by nroff. Most important, it's 756 ** easy to parse and convert, and it was easy to generate from the SGML 757 ** source of mutt's original manual. 758 ** 759 ** - \fI switches to italics 760 ** - \fB switches to boldface 761 ** - \fP switches to normal display 762 ** - .dl on a line starts a definition list (name taken taken from HTML). 763 ** - .dt starts a term in a definition list. 764 ** - .dd starts a definition in a definition list. 765 ** - .de on a line finishes a definition list. 766 ** - .il on a line starts an itemized list 767 ** - .dd starts an item in an itemized list 768 ** - .ie on a line finishes an itemized list 769 ** - .ts on a line starts a "tscreen" environment (name taken from SGML). 770 ** - .te on a line finishes this environment. 771 ** - .pp on a line starts a paragraph. 772 ** - \$word will be converted to a reference to word, where appropriate. 773 ** Note that \$$word is possible as well. 774 ** - '. ' in the beginning of a line expands to two space characters. 775 ** This is used to protect indentations in tables. 776 **/ 777 778/* close eventually-open environments. */ 779 780static int fd_recurse = 0; 781 782static int flush_doc (int docstat, FILE *out) 783{ 784 if (docstat & D_INIT) 785 return D_INIT; 786 787 if (fd_recurse++) 788 { 789 fprintf (stderr, "%s: Internal error, recursion in flush_doc()!\n", Progname); 790 exit (1); 791 } 792 793 if (docstat & (D_PA)) 794 docstat = print_it (SP_END_PAR, NULL, out, docstat); 795 796 if (docstat & (D_TAB)) 797 docstat = print_it (SP_END_TAB, NULL, out, docstat); 798 799 if (docstat & (D_DL)) 800 docstat = print_it (SP_END_DL, NULL, out, docstat); 801 802 if (docstat & (D_EM | D_BF | D_TT)) 803 docstat = print_it (SP_END_FT, NULL, out, docstat); 804 805 docstat = print_it (SP_END_SECT, NULL, out, docstat); 806 807 docstat = print_it (SP_NEWLINE, NULL, out, 0); 808 809 fd_recurse--; 810 return D_INIT; 811} 812 813/* print something. */ 814 815static int print_it (int special, char *str, FILE *out, int docstat) 816{ 817 int onl = docstat & (D_NL|D_NP); 818 819 docstat &= ~(D_NL|D_NP|D_INIT); 820 821 switch (OutputFormat) 822 { 823 /* configuration file */ 824 case F_CONF: 825 { 826 switch (special) 827 { 828 static int Continuation = 0; 829 830 case SP_END_FT: docstat &= ~(D_EM|D_BF|D_TT); break; 831 case SP_START_BF: docstat |= D_BF; break; 832 case SP_START_EM: docstat |= D_EM; break; 833 case SP_START_TT: docstat |= D_TT; break; 834 case SP_NEWLINE: 835 { 836 if (onl) 837 docstat |= onl; 838 else 839 { 840 fputs ("\n# ", out); 841 docstat |= D_NL; 842 } 843 if (docstat & D_DL) 844 ++ Continuation; 845 break; 846 } 847 case SP_NEWPAR: 848 { 849 if (onl & D_NP) 850 { 851 docstat |= onl; 852 break; 853 } 854 855 if (!(onl & D_NL)) 856 fputs ("\n# ", out); 857 fputs ("\n# ", out); 858 docstat |= D_NP; 859 break; 860 } 861 case SP_START_TAB: 862 { 863 if (!onl) 864 fputs ("\n# ", out); 865 docstat |= D_TAB; 866 break; 867 } 868 case SP_END_TAB: 869 { 870 docstat &= ~D_TAB; 871 docstat |= D_NL; 872 break; 873 } 874 case SP_START_DL: 875 { 876 docstat |= D_DL; 877 break; 878 } 879 case SP_DT: 880 { 881 Continuation = 0; 882 docstat |= D_DT; 883 break; 884 } 885 case SP_DD: 886 { 887 if (docstat & D_IL) 888 fputs ("- ", out); 889 Continuation = 0; 890 break; 891 } 892 case SP_END_DL: 893 { 894 Continuation = 0; 895 docstat &= ~D_DL; 896 break; 897 } 898 case SP_START_IL: 899 { 900 docstat |= D_IL; 901 break; 902 } 903 case SP_END_IL: 904 { 905 Continuation = 0; 906 docstat &= ~D_IL; 907 break; 908 } 909 case SP_STR: 910 { 911 if (Continuation) 912 { 913 Continuation = 0; 914 fputs (" ", out); 915 } 916 fputs (str, out); 917 if (docstat & D_DT) 918 { 919 int i; 920 921 for (i = strlen (str) ; i < 8 ; i++) 922 putc (' ', out); 923 docstat &= ~D_DT; 924 docstat |= D_NL; 925 } 926 break; 927 } 928 } 929 break; 930 } 931 932 /* manual page */ 933 case F_MAN: 934 { 935 switch (special) 936 { 937 case SP_END_FT: 938 { 939 fputs ("\\fP", out); 940 docstat &= ~(D_EM|D_BF|D_TT); 941 break; 942 } 943 case SP_START_BF: 944 { 945 fputs ("\\fB", out); 946 docstat |= D_BF; 947 docstat &= ~(D_EM|D_TT); 948 break; 949 } 950 case SP_START_EM: 951 { 952 fputs ("\\fI", out); 953 docstat |= D_EM; 954 docstat &= ~(D_BF|D_TT); 955 break; 956 } 957 case SP_START_TT: 958 { 959 fputs ("\\fC", out); 960 docstat |= D_TT; 961 docstat &= ~(D_BF|D_EM); 962 break; 963 } 964 case SP_NEWLINE: 965 { 966 if (onl) 967 docstat |= onl; 968 else 969 { 970 fputc ('\n', out); 971 docstat |= D_NL; 972 } 973 break; 974 } 975 case SP_NEWPAR: 976 { 977 if (onl & D_NP) 978 { 979 docstat |= onl; 980 break; 981 } 982 983 if (!(onl & D_NL)) 984 fputc ('\n', out); 985 fputs (".IP\n", out); 986 987 docstat |= D_NP; 988 break; 989 } 990 case SP_START_TAB: 991 { 992 fputs ("\n.IP\n.EX\n", out); 993 docstat |= D_TAB | D_NL; 994 break; 995 } 996 case SP_END_TAB: 997 { 998 fputs ("\n.EE\n", out); 999 docstat &= ~D_TAB; 1000 docstat |= D_NL; 1001 break; 1002 } 1003 case SP_START_DL: 1004 { 1005 fputs (".RS\n.PD 0\n", out); 1006 docstat |= D_DL; 1007 break; 1008 } 1009 case SP_DT: 1010 { 1011 fputs (".TP\n", out); 1012 break; 1013 } 1014 case SP_DD: 1015 { 1016 if (docstat & D_IL) 1017 fputs (".TP\n\\(hy ", out); 1018 else 1019 fputs ("\n", out); 1020 break; 1021 } 1022 case SP_END_DL: 1023 { 1024 fputs (".RE\n.PD 1", out); 1025 docstat &= ~D_DL; 1026 break; 1027 } 1028 case SP_START_IL: 1029 { 1030 fputs (".RS\n.PD 0\n", out); 1031 docstat |= D_IL; 1032 break; 1033 } 1034 case SP_END_IL: 1035 { 1036 fputs (".RE\n.PD 1", out); 1037 docstat &= ~D_DL; 1038 break; 1039 } 1040 case SP_STR: 1041 { 1042 while (*str) 1043 { 1044 for (; *str; str++) 1045 { 1046 if (*str == '"') 1047 fputs ("\\(rq", out); 1048 else if (*str == '\\') 1049 fputs ("\\\\", out); 1050 else if (*str == '-') 1051 fputs ("\\-", out); 1052 else if (!strncmp (str, "``", 2)) 1053 { 1054 fputs ("\\(lq", out); 1055 str++; 1056 } 1057 else if (!strncmp (str, "''", 2)) 1058 { 1059 fputs ("\\(rq", out); 1060 str++; 1061 } 1062 else 1063 fputc (*str, out); 1064 } 1065 } 1066 break; 1067 } 1068 } 1069 break; 1070 } 1071 1072 /* SGML based manual */ 1073 case F_SGML: 1074 { 1075 switch (special) 1076 { 1077 case SP_END_FT: 1078 { 1079 if (docstat & D_EM) fputs ("</emphasis>", out); 1080 if (docstat & D_BF) fputs ("</emphasis>", out); 1081 if (docstat & D_TT) fputs ("</literal>", out); 1082 docstat &= ~(D_EM|D_BF|D_TT); 1083 break; 1084 } 1085 case SP_START_BF: 1086 { 1087 fputs ("<emphasis role=\"bold\">", out); 1088 docstat |= D_BF; 1089 docstat &= ~(D_EM|D_TT); 1090 break; 1091 } 1092 case SP_START_EM: 1093 { 1094 fputs ("<emphasis>", out); 1095 docstat |= D_EM; 1096 docstat &= ~(D_BF|D_TT); 1097 break; 1098 } 1099 case SP_START_TT: 1100 { 1101 fputs ("<literal>", out); 1102 docstat |= D_TT; 1103 docstat &= ~(D_BF|D_EM); 1104 break; 1105 } 1106 case SP_NEWLINE: 1107 { 1108 if (onl) 1109 docstat |= onl; 1110 else 1111 { 1112 fputc ('\n', out); 1113 docstat |= D_NL; 1114 } 1115 break; 1116 } 1117 case SP_NEWPAR: 1118 { 1119 if (onl & D_NP) 1120 { 1121 docstat |= onl; 1122 break; 1123 } 1124 1125 if (!(onl & D_NL)) 1126 fputc ('\n', out); 1127 if (docstat & D_PA) 1128 fputs("</para>\n", out); 1129 fputs ("<para>\n", out); 1130 1131 docstat |= D_NP; 1132 docstat |= D_PA; 1133 1134 break; 1135 } 1136 case SP_END_PAR: 1137 { 1138 fputs ("</para>\n", out); 1139 docstat &= ~D_PA; 1140 break; 1141 } 1142 case SP_START_TAB: 1143 { 1144 if (docstat & D_PA) 1145 { 1146 fputs ("\n</para>\n", out); 1147 docstat &= ~D_PA; 1148 } 1149 fputs ("\n<screen>\n", out); 1150 docstat |= D_TAB | D_NL; 1151 break; 1152 } 1153 case SP_END_TAB: 1154 { 1155 fputs ("</screen>", out); 1156 docstat &= ~D_TAB; 1157 docstat |= D_NL; 1158 break; 1159 } 1160 case SP_START_DL: 1161 { 1162 if (docstat & D_PA) 1163 { 1164 fputs ("\n</para>\n", out); 1165 docstat &= ~D_PA; 1166 } 1167 fputs ("\n<informaltable>\n<tgroup cols=\"2\">\n<tbody>\n", out); 1168 docstat |= D_DL; 1169 break; 1170 } 1171 case SP_DT: 1172 { 1173 fputs ("<row><entry>", out); 1174 break; 1175 } 1176 case SP_DD: 1177 { 1178 docstat |= D_DD; 1179 if (docstat & D_DL) 1180 fputs("</entry><entry>", out); 1181 else 1182 fputs ("<listitem><para>", out); 1183 break; 1184 } 1185 case SP_END_DD: 1186 { 1187 if (docstat & D_DL) 1188 fputs ("</entry></row>\n", out); 1189 else 1190 fputs ("</para></listitem>", out); 1191 docstat &= ~D_DD; 1192 break; 1193 } 1194 case SP_END_DL: 1195 { 1196 fputs ("</entry></row></tbody></tgroup></informaltable>\n", out); 1197 docstat &= ~(D_DD|D_DL); 1198 break; 1199 } 1200 case SP_START_IL: 1201 { 1202 if (docstat & D_PA) 1203 { 1204 fputs ("\n</para>\n", out); 1205 docstat &= ~D_PA; 1206 } 1207 fputs ("\n<itemizedlist>\n", out); 1208 docstat |= D_IL; 1209 break; 1210 } 1211 case SP_END_IL: 1212 { 1213 fputs ("</para></listitem></itemizedlist>\n", out); 1214 docstat &= ~(D_DD|D_DL); 1215 break; 1216 } 1217 case SP_END_SECT: 1218 { 1219 fputs ("</sect2>", out); 1220 break; 1221 } 1222 case SP_STR: 1223 { 1224 if (docstat & D_TAB) 1225 sgml_fputs (str, out); 1226 else 1227 { 1228 while (*str) 1229 { 1230 for (; *str; str++) 1231 { 1232 if (!strncmp (str, "``", 2)) 1233 { 1234 fputs ("<quote>", out); 1235 str++; 1236 } 1237 else if (!strncmp (str, "''", 2)) 1238 { 1239 fputs ("</quote>", out); 1240 str++; 1241 } 1242 else 1243 sgml_fputc (*str, out); 1244 } 1245 } 1246 } 1247 break; 1248 } 1249 } 1250 break; 1251 } 1252 /* make gcc happy (unreached) */ 1253 default: 1254 break; 1255 } 1256 1257 return docstat; 1258} 1259 1260void print_ref (FILE *out, int output_dollar, const char *ref) 1261{ 1262 switch (OutputFormat) 1263 { 1264 case F_CONF: 1265 case F_MAN: 1266 if (output_dollar) 1267 putc ('$', out); 1268 fputs (ref, out); 1269 break; 1270 1271 case F_SGML: 1272 fputs ("<link linkend=\"", out); 1273 sgml_id_fputs (ref, out); 1274 fputs ("\">", out); 1275 if (output_dollar) 1276 fputc ('$', out); 1277 sgml_fputs (ref, out); 1278 fputs ("</link>", out); 1279 break; 1280 1281 default: 1282 break; 1283 } 1284} 1285 1286static int commit_buff (char *buff, char **d, FILE *out, int docstat) 1287{ 1288 if (*d > buff) 1289 { 1290 **d = '\0'; 1291 docstat = print_it (SP_STR, buff, out, docstat); 1292 *d = buff; 1293 } 1294 1295 return docstat; 1296} 1297 1298static int handle_docline (char *l, FILE *out, int docstat) 1299{ 1300 char buff[BUFFSIZE]; 1301 char *s, *d; 1302 l = skip_ws (l); 1303 1304 if (Debug) 1305 fprintf (stderr, "%s: handle_docline `%s'\n", Progname, l); 1306 1307 if (!strncmp (l, ".pp", 3)) 1308 return print_it (SP_NEWPAR, NULL, out, docstat); 1309 else if (!strncmp (l, ".ts", 3)) 1310 return print_it (SP_START_TAB, NULL, out, docstat); 1311 else if (!strncmp (l, ".te", 3)) 1312 return print_it (SP_END_TAB, NULL, out, docstat); 1313 else if (!strncmp (l, ".dl", 3)) 1314 return print_it (SP_START_DL, NULL, out, docstat); 1315 else if (!strncmp (l, ".de", 3)) 1316 return print_it (SP_END_DL, NULL, out, docstat); 1317 else if (!strncmp (l, ".il", 3)) 1318 return print_it (SP_START_IL, NULL, out, docstat); 1319 else if (!strncmp (l, ".ie", 3)) 1320 return print_it (SP_END_IL, NULL, out, docstat); 1321 else if (!strncmp (l, ". ", 2)) 1322 *l = ' '; 1323 1324 for (s = l, d = buff; *s; s++) 1325 { 1326 if (!strncmp (s, "\\(as", 4)) 1327 { 1328 *d++ = '*'; 1329 s += 3; 1330 } 1331 else if (!strncmp (s, "\\(rs", 4)) 1332 { 1333 *d++ = '\\'; 1334 s += 3; 1335 } 1336 else if (!strncmp (s, "\\fI", 3)) 1337 { 1338 docstat = commit_buff (buff, &d, out, docstat); 1339 docstat = print_it (SP_START_EM, NULL, out, docstat); 1340 s += 2; 1341 } 1342 else if (!strncmp (s, "\\fB", 3)) 1343 { 1344 docstat = commit_buff (buff, &d, out, docstat); 1345 docstat = print_it (SP_START_BF, NULL, out, docstat); 1346 s += 2; 1347 } 1348 else if (!strncmp (s, "\\fC", 3)) 1349 { 1350 docstat = commit_buff (buff, &d, out, docstat); 1351 docstat = print_it (SP_START_TT, NULL, out, docstat); 1352 s += 2; 1353 } 1354 else if (!strncmp (s, "\\fP", 3)) 1355 { 1356 docstat = commit_buff (buff, &d, out, docstat); 1357 docstat = print_it (SP_END_FT, NULL, out, docstat); 1358 s += 2; 1359 } 1360 else if (!strncmp (s, ".dt", 3)) 1361 { 1362 if (docstat & D_DD) 1363 { 1364 docstat = commit_buff (buff, &d, out, docstat); 1365 docstat = print_it (SP_END_DD, NULL, out, docstat); 1366 } 1367 docstat = commit_buff (buff, &d, out, docstat); 1368 docstat = print_it (SP_DT, NULL, out, docstat); 1369 s += 3; 1370 } 1371 else if (!strncmp (s, ".dd", 3)) 1372 { 1373 if ((docstat & D_IL) && (docstat & D_DD)) 1374 { 1375 docstat = commit_buff (buff, &d, out, docstat); 1376 docstat = print_it (SP_END_DD, NULL, out, docstat); 1377 } 1378 docstat = commit_buff (buff, &d, out, docstat); 1379 docstat = print_it (SP_DD, NULL, out, docstat); 1380 s += 3; 1381 } 1382 else if (*s == '$') 1383 { 1384 int output_dollar = 0; 1385 char *ref; 1386 char save; 1387 1388 ++s; 1389 if (*s == '$') 1390 { 1391 output_dollar = 1; 1392 ++s; 1393 } 1394 if (*s == '$') 1395 { 1396 *d++ = '$'; 1397 } 1398 else 1399 { 1400 ref = s; 1401 while (isalnum ((unsigned char) *s) || (*s && strchr("-_<>", *s))) 1402 ++s; 1403 1404 docstat = commit_buff (buff, &d, out, docstat); 1405 save = *s; 1406 *s = 0; 1407 print_ref (out, output_dollar, ref); 1408 *s = save; 1409 --s; 1410 } 1411 } 1412 else 1413 *d++ = *s; 1414 } 1415 1416 docstat = commit_buff (buff, &d, out, docstat); 1417 return print_it (SP_NEWLINE, NULL, out, docstat); 1418}