2006-09-06 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / doc / yat2m.c
blobc47e2fe372dfac0209b386edd44b892672ef03a4
1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005 g10 Code GmbH
3 * Copyright (C) 2006 2006 Free Software Foundation, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
22 This is a simple textinfo to man page converter. It needs some
23 special markup in th e texinfo and tries best to get a create man
24 page. It has been designed for the GnuPG man pages and thus only
25 a few texinfo commands are supported.
27 To use this you need to add the following macros into your texinfo
28 source:
30 @macro manpage {a}
31 @end macro
32 @macro mansect {a}
33 @end macro
34 @macro manpause
35 @end macro
36 @macro mancont
37 @end macro
39 They are used by yat2m to select parts of the Texinfo which should
40 go into the man page. These macros need to be used without leading
41 left space. Processing starts after a "manpage" macro has been
42 seen. "mansect" identifies the section and yat2m make sure to
43 emit the sections in the proper order. Note that @mansect skips
44 the next input line if that line begins with @section, @subsection or
45 @chapheading.
47 To insert verbatim troff markup, the follwing texinfo code may be
48 used:
50 @ifset manverb
51 .B whateever you want
52 @end ifset
54 alternativly a special comment may be used:
56 @c man:.B whatever you want
58 This is useful in case you need just one line. If you want to
59 include parts only in the man page but keep the texinfo
60 translation you may use:
62 @ifset isman
63 stuff to be rendered only on man pages
64 @end ifset
66 or to exclude stuff from man pages:
68 @ifclear isman
69 stuff not to be rendered on man pages
70 @end ifclear
72 the keyword @section is ignored, however @subsection gets rendered
73 as ".SS". @menu is completely skipped. Several man pages may be
74 extracted from one file, either using the --store or the --select
75 option.
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <stddef.h>
83 #include <string.h>
84 #include <errno.h>
85 #include <stdarg.h>
86 #include <assert.h>
87 #include <ctype.h>
88 #include <time.h>
91 #define PGM "yat2m"
92 #define VERSION "0.5"
94 /* The maximum length of a line including the linefeed and one extra
95 character. */
96 #define LINESIZE 1024
98 /* Option flags. */
99 static int verbose;
100 static int quiet;
101 static int debug;
102 static const char *opt_source;
103 static const char *opt_release;
104 static const char *opt_select;
105 static const char *opt_include;
106 static int opt_store;
109 /* Flag to keep track whether any error occurred. */
110 static int any_error;
113 /* Object to store one line of content. */
114 struct line_buffer_s
116 struct line_buffer_s *next;
117 int verbatim; /* True if LINE contains verbatim data. The default
118 is Texinfo source. */
119 char *line;
121 typedef struct line_buffer_s *line_buffer_t;
124 /* Object to collect the data of a section. */
125 struct section_buffer_s
127 char *name; /* Malloced name of the section. This may be
128 NULL to indicate this slot is not used. */
129 line_buffer_t lines; /* Linked list with the lines of the section. */
130 line_buffer_t *lines_tail; /* Helper for faster appending to the
131 linked list. */
132 line_buffer_t last_line; /* Points to the last line appended. */
134 typedef struct section_buffer_s *section_buffer_t;
136 /* Variable to keep info about the current page together. */
137 static struct
139 /* Filename of the current page or NULL if no page is active. Malloced. */
140 char *name;
142 /* Number of allocated elements in SECTIONS below. */
143 size_t n_sections;
144 /* Array with the data of the sections. */
145 section_buffer_t sections;
147 } thepage;
150 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
151 specific. */
152 static const char * const standard_sections[] =
153 { "NAME", "SYNOPSIS", "DESCRIPTION",
154 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
155 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
156 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
157 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
160 /*-- Local prototypes. --*/
161 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
162 int *table_level, int *eol_action);
166 /* Print diagnostic message and exit with failure. */
167 static void
168 die (const char *format, ...)
170 va_list arg_ptr;
172 fflush (stdout);
173 fprintf (stderr, "%s: ", PGM);
175 va_start (arg_ptr, format);
176 vfprintf (stderr, format, arg_ptr);
177 va_end (arg_ptr);
178 putc ('\n', stderr);
180 exit (1);
184 /* Print diagnostic message. */
185 static void
186 err (const char *format, ...)
188 va_list arg_ptr;
190 fflush (stdout);
191 if (strncmp (format, "%s:%d:", 6))
192 fprintf (stderr, "%s: ", PGM);
194 va_start (arg_ptr, format);
195 vfprintf (stderr, format, arg_ptr);
196 va_end (arg_ptr);
197 putc ('\n', stderr);
198 any_error = 1;
201 /* Print diagnostic message. */
202 static void
203 inf (const char *format, ...)
205 va_list arg_ptr;
207 fflush (stdout);
208 fprintf (stderr, "%s: ", PGM);
210 va_start (arg_ptr, format);
211 vfprintf (stderr, format, arg_ptr);
212 va_end (arg_ptr);
213 putc ('\n', stderr);
217 static void *
218 xmalloc (size_t n)
220 void *p = malloc (n);
221 if (!p)
222 die ("out of core: %s", strerror (errno));
223 return p;
226 static void *
227 xcalloc (size_t n, size_t m)
229 void *p = calloc (n, m);
230 if (!p)
231 die ("out of core: %s", strerror (errno));
232 return p;
235 static void *
236 xrealloc (void *old, size_t n)
238 void *p = realloc (old, n);
239 if (!p)
240 die ("out of core: %s", strerror (errno));
241 return p;
244 static char *
245 xstrdup (const char *string)
247 void *p = malloc (strlen (string)+1);
248 if (!p)
249 die ("out of core: %s", strerror (errno));
250 strcpy (p, string);
251 return p;
255 /* Uppercase the ascii characters in STRING. */
256 static char *
257 ascii_strupr (char *string)
259 char *p;
261 for (p = string; *p; p++)
262 if (!(*p & 0x80))
263 *p = toupper (*p);
264 return string;
268 /* Return the current date as an ISO string. */
269 const char *
270 isodatestring (void)
272 static char buffer[11+5];
273 struct tm *tp;
274 time_t atime = time (NULL);
276 if (atime < 0)
277 strcpy (buffer, "????" "-??" "-??");
278 else
280 tp = gmtime (&atime);
281 sprintf (buffer,"%04d-%02d-%02d",
282 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
284 return buffer;
289 /* Return a section buffer for the section NAME. Allocate a new buffer
290 if this is a new section. Keep track of the sections in THEPAGE.
291 This function may reallocate the section array in THEPAGE. */
292 static section_buffer_t
293 get_section_buffer (const char *name)
295 int i;
296 section_buffer_t sect;
298 /* If there is no section we put everything into the required NAME
299 section. Given that this is the first one listed it is likely
300 that error are easily visible. */
301 if (!name)
302 name = "NAME";
304 for (i=0; i < thepage.n_sections; i++)
306 sect = thepage.sections + i;
307 if (sect->name && !strcmp (name, sect->name))
308 return sect;
310 for (i=0; i < thepage.n_sections; i++)
311 if (!thepage.sections[i].name)
312 break;
313 if (i < thepage.n_sections)
314 sect = thepage.sections + i;
315 else
317 /* We need to allocate or reallocate the section array. */
318 size_t old_n = thepage.n_sections;
319 size_t new_n = 20;
321 if (!old_n)
322 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
323 else
325 thepage.sections = xrealloc (thepage.sections,
326 ((old_n + new_n)
327 * sizeof *thepage.sections));
328 memset (thepage.sections + old_n, 0,
329 new_n * sizeof *thepage.sections);
331 thepage.n_sections += new_n;
333 /* Setup the tail pointers. */
334 for (i=old_n; i < thepage.n_sections; i++)
336 sect = thepage.sections + i;
337 sect->lines_tail = &sect->lines;
339 sect = thepage.sections + old_n;
342 /* Store the name. */
343 assert (!sect->name);
344 sect->name = xstrdup (name);
345 return sect;
350 /* Add the content of LINE to the section named SECTNAME. */
351 static void
352 add_content (const char *sectname, char *line, int verbatim)
354 section_buffer_t sect;
355 line_buffer_t lb;
357 sect = get_section_buffer (sectname);
358 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
360 /* Lets append that line to the last one. We do this to keep
361 all lines of the same kind (i.e.verbatim or not) together in
362 one large buffer. */
363 size_t n1, n;
365 lb = sect->last_line;
366 n1 = strlen (lb->line);
367 n = n1 + 1 + strlen (line) + 1;
368 lb->line = xrealloc (lb->line, n);
369 strcpy (lb->line+n1, "\n");
370 strcpy (lb->line+n1+1, line);
372 else
374 lb = xcalloc (1, sizeof *lb);
375 lb->verbatim = verbatim;
376 lb->line = xstrdup (line);
377 sect->last_line = lb;
378 *sect->lines_tail = lb;
379 sect->lines_tail = &lb->next;
384 /* Prepare for a new man page using the filename NAME. */
385 static void
386 start_page (char *name)
388 if (verbose)
389 inf ("starting page `%s'", name);
390 assert (!thepage.name);
391 thepage.name = xstrdup (name);
392 thepage.n_sections = 0;
396 /* Write the .TH entry of the current page. Return -1 if there is a
397 problem with the page. */
398 static int
399 write_th (FILE *fp)
401 char *name, *p;
403 name = ascii_strupr (xstrdup (thepage.name));
404 p = strrchr (name, '.');
405 if (!p || !p[1])
407 err ("no section name in man page `%s'", thepage.name);
408 free (name);
409 return -1;
411 *p++ = 0;
412 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
413 name, p, isodatestring (), opt_release, opt_source);
414 return 0;
418 /* Process the texinfo command COMMAND (without the leading @) and
419 write output if needed to FP. REST is the remainer of the line
420 which should either point to an opening brace or to a white space.
421 The function returns the number of characters already processed
422 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
423 control the indentation of tables. */
424 static size_t
425 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
426 int *table_level, int *eol_action)
428 static struct {
429 const char *name; /* Name of the command. */
430 int what; /* What to do with this command. */
431 const char *lead_in; /* String to print with a opening brace. */
432 const char *lead_out;/* String to print with the closing brace. */
433 } cmdtbl[] = {
434 { "command", 0, "\\fB", "\\fR" },
435 { "code", 0, "\\fB", "\\fR" },
436 { "sc", 0, "\\fB", "\\fR" },
437 { "var", 0, "\\fI", "\\fR" },
438 { "samp", 0, "\n'", "'\n" },
439 { "file", 0, "`\\fI","\\fR'" },
440 { "env", 0, "`\\fI","\\fR'" },
441 { "acronym", 0 },
442 { "dfn", 0 },
443 { "option", 0, "\\fB", "\\fR" },
444 { "example", 1, ".RS 2\n.nf\n" },
445 { "smallexample", 1, ".RS 2\n.nf\n" },
446 { "asis", 7 },
447 { "anchor", 7 },
448 { "cartouche", 1 },
449 { "xref", 0, "see: [", "]" },
450 { "pxref", 0, "see: [", "]" },
451 { "uref", 0, "(\\fB", "\\fR)" },
452 { "footnote",0, " ([", "])" },
453 { "emph", 0, "\\fI", "\\fR" },
454 { "w", 1 },
455 { "c", 5 },
456 { "opindex", 1 },
457 { "cpindex", 1 },
458 { "cindex", 1 },
459 { "node", 1 },
460 { "noindent", 0 },
461 { "section", 1 },
462 { "chapter", 1 },
463 { "subsection", 6, "\n.SS " },
464 { "chapheading", 0},
465 { "item", 2, ".TP\n.B " },
466 { "itemx", 2, ".TP\n.B " },
467 { "table", 3 },
468 { "end", 4 },
469 { "quotation",1, ".RS\n\\fB" },
470 { "ifset", 1 },
471 { "ifclear", 1 },
472 { NULL }
474 size_t n;
475 int i;
476 const char *s;
477 const char *lead_out = NULL;
478 int ignore_args = 0;
480 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
482 if (cmdtbl[i].name)
484 s = cmdtbl[i].lead_in;
485 if (s)
486 fputs (s, fp);
487 lead_out = cmdtbl[i].lead_out;
488 switch (cmdtbl[i].what)
490 case 1: /* Throw away the entire line. */
491 s = memchr (rest, '\n', len);
492 return s? (s-rest)+1 : len;
493 case 2: /* Handle @item. */
494 break;
495 case 3: /* Handle table. */
496 if (++(*table_level) > 1)
497 fputs (".RS\n", fp);
498 /* Now throw away the entire line. */
499 s = memchr (rest, '\n', len);
500 return s? (s-rest)+1 : len;
501 break;
502 case 4: /* Handle end. */
503 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
505 if (n >= 5 && !memcmp (s, "table", 5)
506 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
508 if ((*table_level)-- > 1)
509 fputs (".RE\n", fp);
511 else if (n >= 7 && !memcmp (s, "example", 7)
512 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
514 fputs (".fi\n.RE\n", fp);
516 else if (n >= 12 && !memcmp (s, "smallexample", 12)
517 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
519 fputs (".fi\n.RE\n", fp);
521 else if (n >= 9 && !memcmp (s, "quotation", 9)
522 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
524 fputs ("\\fR\n.RE\n", fp);
526 else if (n >= 5 && !memcmp (s, "ifset", 5)
527 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
529 fputs ("\\fR\n.RE\n", fp);
531 /* Now throw away the entire line. */
532 s = memchr (rest, '\n', len);
533 return s? (s-rest)+1 : len;
534 case 5: /* Handle special comments. */
535 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
537 if (n >= 4 && !memcmp (s, "man:", 4))
539 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
540 putc (*s, fp);
541 putc ('\n', fp);
543 /* Now throw away the entire line. */
544 s = memchr (rest, '\n', len);
545 return s? (s-rest)+1 : len;
546 case 6:
547 *eol_action = 1;
548 break;
549 case 7:
550 ignore_args = 1;
551 break;
552 default:
553 break;
556 else
558 inf ("texinfo command `%s' not supported (%.*s)", command,
559 ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
562 if (*rest == '{')
564 /* Find matching closing brace. */
565 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
566 if (*s == '{')
567 i++;
568 else if (*s == '}')
569 i--;
570 if (i)
572 err ("closing brace for command `%s' not found", command);
573 return len;
575 if (n > 2 && !ignore_args)
576 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
578 else
579 n = 0;
581 if (lead_out)
582 fputs (lead_out, fp);
584 return n;
589 /* Process the string LINE with LEN bytes of Texinfo content. */
590 static void
591 proc_texi_buffer (FILE *fp, const char *line, size_t len,
592 int *table_level, int *eol_action)
594 const char *s;
595 char cmdbuf[256];
596 int cmdidx = 0;
597 int in_cmd = 0;
598 size_t n;
600 for (s=line; *s && len; s++, len--)
602 if (in_cmd)
604 if (in_cmd == 1)
606 switch (*s)
608 case '@': case '{': case '}':
609 putc (*s, fp); in_cmd = 0;
610 break;
611 case ':': /* Not ending a sentence flag. */
612 in_cmd = 0;
613 break;
614 case '.': case '!': case '?': /* Ending a sentence. */
615 putc (*s, fp); in_cmd = 0;
616 break;
617 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
618 putc (*s, fp); in_cmd = 0;
619 break;
620 default:
621 cmdidx = 0;
622 cmdbuf[cmdidx++] = *s;
623 in_cmd++;
624 break;
627 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
629 cmdbuf[cmdidx] = 0;
630 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
631 assert (n <= len);
632 s += n; len -= n;
633 s--; len++;
634 in_cmd = 0;
636 else if (cmdidx < sizeof cmdbuf -1)
637 cmdbuf[cmdidx++] = *s;
638 else
640 err ("texinfo command too long - ignored");
641 in_cmd = 0;
644 else if (*s == '@')
645 in_cmd = 1;
646 else if (*s == '\n')
648 switch (*eol_action)
650 case 1: /* Create a dummy paragraph. */
651 fputs ("\n\\ \n", fp);
652 break;
653 default:
654 putc (*s, fp);
656 *eol_action = 0;
658 else
659 putc (*s, fp);
664 /* Do something with the Texinfo line LINE. */
665 static void
666 parse_texi_line (FILE *fp, const char *line, int *table_level)
668 int eol_action = 0;
670 /* A quick test whether there are any texinfo commands. */
671 if (!strchr (line, '@'))
673 fputs (line, fp);
674 putc ('\n', fp);
675 return;
677 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
678 putc ('\n', fp);
682 /* Write all the lines LINES to FP. */
683 static void
684 write_content (FILE *fp, line_buffer_t lines)
686 line_buffer_t line;
687 int table_level = 0;
689 for (line = lines; line; line = line->next)
691 if (line->verbatim)
693 fputs (line->line, fp);
694 putc ('\n', fp);
696 else
698 /* fputs ("TEXI---", fp); */
699 /* fputs (line->line, fp); */
700 /* fputs ("---\n", fp); */
701 parse_texi_line (fp, line->line, &table_level);
708 static int
709 is_standard_section (const char *name)
711 int i;
712 const char *s;
714 for (i=0; (s=standard_sections[i]); i++)
715 if (!strcmp (s, name))
716 return 1;
717 return 0;
721 /* Finish a page; that is sort the data and write it out to the file. */
722 static void
723 finish_page (void)
725 FILE *fp;
726 section_buffer_t sect;
727 int idx;
728 const char *s;
729 int i;
731 if (!thepage.name)
732 return; /* No page active. */
734 if (verbose)
735 inf ("finishing page `%s'", thepage.name);
737 if (opt_select)
739 if (!strcmp (opt_select, thepage.name))
741 inf ("selected `%s'", thepage.name );
742 fp = stdout;
744 else
746 fp = fopen ( "/dev/null", "w" );
747 if (!fp)
748 die ("failed to open /dev/null: %s\n", strerror (errno));
751 else if (opt_store)
753 inf ("writing `%s'", thepage.name );
754 fp = fopen ( thepage.name, "w" );
755 if (!fp)
756 die ("failed to create `%s': %s\n", thepage.name, strerror (errno));
758 else
759 fp = stdout;
761 if (write_th (fp))
762 goto leave;
764 for (idx=0; (s=standard_sections[idx]); idx++)
766 for (i=0; i < thepage.n_sections; i++)
768 sect = thepage.sections + i;
769 if (sect->name && !strcmp (s, sect->name))
770 break;
772 if (i == thepage.n_sections)
773 sect = NULL;
775 if (sect)
777 fprintf (fp, ".SH %s\n", sect->name);
778 write_content (fp, sect->lines);
779 /* Now continue with all non standard sections directly
780 following this one. */
781 for (i++; i < thepage.n_sections; i++)
783 sect = thepage.sections + i;
784 if (sect->name && is_standard_section (sect->name))
785 break;
786 if (sect->name)
788 fprintf (fp, ".SH %s\n", sect->name);
789 write_content (fp, sect->lines);
797 leave:
798 if (fp != stdout)
799 fclose (fp);
800 free (thepage.name);
801 thepage.name = NULL;
802 /* FIXME: Cleanup the content. */
808 /* Parse one Texinfo file and create manpages according to the
809 embedded instructions. */
810 static void
811 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
813 char *line;
814 int lnr = 0;
815 int in_verbatim = 0;
816 int skip_to_end = 0; /* Used to skip over menu entries. */
817 int skip_sect_line = 0; /* Skip after @mansect. */
819 line = xmalloc (LINESIZE);
820 while (fgets (line, LINESIZE, fp))
822 size_t n = strlen (line);
823 int got_line = 0;
824 char *p;
826 lnr++;
827 if (!n || line[n-1] != '\n')
829 err ("%s:$d: trailing linefeed missing, line too long or "
830 "embedded Nul character", fname, lnr);
831 break;
833 line[--n] = 0;
835 if (skip_sect_line)
837 skip_sect_line = 0;
838 if (!strncmp (line, "@section", 8)
839 || !strncmp (line, "@subsection", 11)
840 || !strncmp (line, "@chapheading", 12))
841 continue;
844 /* We only parse lines we need and ignore the rest. There are a
845 few macros used to control this as well as one @ifset
846 command. Parts we know about are saved away into containers
847 separate for each section. */
848 if (*line == '@')
850 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
851 n++;
852 while (*p == ' ' || *p == '\t')
853 p++;
855 if (skip_to_end
856 && n == 4 && !memcmp (line, "@end", 4)
857 && (line[4]==' '||line[4]=='\t'||!line[4]))
859 skip_to_end = 0;
861 else if (n == 6 && !memcmp (line, "@ifset", 6)
862 && !strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
864 if (in_verbatim)
865 err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
866 else
867 in_verbatim = 1;
869 else if (in_verbatim && n == 4 && !memcmp (line, "@end", 4)
870 && !strncmp (p, "ifset", 5)
871 && (p[5]==' '||p[5]=='\t'||!p[5]))
873 in_verbatim = 0;
875 else if (in_verbatim)
877 got_line = 1;
879 else if (n == 8 && !memcmp (line, "@manpage", 8))
881 free (*section_name);
882 *section_name = NULL;
883 finish_page ();
884 start_page (p);
885 in_pause = 0;
887 else if (n == 8 && !memcmp (line, "@mansect", 8))
889 if (!thepage.name)
890 err ("%s:%d: section outside of a man page", fname, lnr);
891 else
893 free (*section_name);
894 *section_name = ascii_strupr (xstrdup (p));
895 in_pause = 0;
896 skip_sect_line = 1;
899 else if (n == 9 && !memcmp (line, "@manpause", 9))
901 if (!*section_name)
902 err ("%s:%d: pausing outside of a man section", fname, lnr);
903 else if (in_pause)
904 err ("%s:%d: already pausing", fname, lnr);
905 else
906 in_pause = 1;
908 else if (n == 8 && !memcmp (line, "@mancont", 8))
910 if (!*section_name)
911 err ("%s:%d: continue outside of a man section", fname, lnr);
912 else if (!in_pause)
913 err ("%s:%d: continue while not pausing", fname, lnr);
914 else
915 in_pause = 0;
917 else if (n == 5 && !memcmp (line, "@menu", 5)
918 && (line[5]==' '||line[5]=='\t'||!line[5]))
920 skip_to_end = 1;
922 else if (n == 8 && !memcmp (line, "@ifclear", 8)
923 && !strncmp (p, "isman", 5) && (p[5]==' '||p[5]=='\t'||!p[5]))
925 skip_to_end = 1;
927 else if (n == 8 && !memcmp (line, "@include", 8)
928 && (line[8]==' '||line[8]=='\t'||!line[8]))
930 char *incname = xstrdup (p);
931 FILE *incfp = fopen (incname, "r");
933 if (!incfp && opt_include && *opt_include && *p != '/')
935 free (incname);
936 incname = xmalloc (strlen (opt_include) + 1
937 + strlen (p) + 1);
938 strcpy (incname, opt_include);
939 if ( incname[strlen (incname)-1] != '/' )
940 strcat (incname, "/");
941 strcat (incname, p);
942 incfp = fopen (incname, "r");
945 if (!incfp)
946 err ("can't open include file `%s':%s",
947 incname, strerror (errno));
948 else
950 parse_file (incname, incfp, section_name, in_pause);
951 fclose (incfp);
953 free (incname);
955 else if (!skip_to_end)
956 got_line = 1;
958 else if (!skip_to_end)
959 got_line = 1;
961 if (got_line && in_verbatim)
962 add_content (*section_name, line, 1);
963 else if (got_line && thepage.name && *section_name && !in_pause)
964 add_content (*section_name, line, 0);
967 if (ferror (fp))
968 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
969 free (line);
973 static void
974 top_parse_file (const char *fname, FILE *fp)
976 char *section_name = NULL; /* Name of the current section or NULL
977 if not in a section. */
978 parse_file (fname, fp, &section_name, 0);
979 free (section_name);
980 finish_page ();
984 int
985 main (int argc, char **argv)
987 int last_argc = -1;
989 opt_source = "GNU";
990 opt_release = "";
992 if (argc)
994 argc--; argv++;
996 while (argc && last_argc != argc )
998 last_argc = argc;
999 if (!strcmp (*argv, "--"))
1001 argc--; argv++;
1002 break;
1004 else if (!strcmp (*argv, "--help"))
1006 puts (
1007 "Usage: " PGM " [OPTION] [FILE]\n"
1008 "Extract man pages from a Texinfo source.\n\n"
1009 " --source NAME use NAME as source field\n"
1010 " --release STRING use STRING as the release field\n"
1011 " --store write output using @manpage name\n"
1012 " --select NAME only output pages with @manpage NAME\n"
1013 " --verbose enable extra informational output\n"
1014 " --debug enable additional debug output\n"
1015 " --help display this help and exit\n"
1016 " -I DIR also search in include DIR\n\n"
1017 "With no FILE, or when FILE is -, read standard input.\n\n"
1018 "Report bugs to <bugs@g10code.com>.");
1019 exit (0);
1021 else if (!strcmp (*argv, "--version"))
1023 puts (PGM " " VERSION "\n"
1024 "Copyright (C) 2005 g10 Code GmbH\n"
1025 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1026 "This is free software, and you are welcome to redistribute it\n"
1027 "under certain conditions. See the file COPYING for details.");
1028 exit (0);
1030 else if (!strcmp (*argv, "--verbose"))
1032 verbose = 1;
1033 argc--; argv++;
1035 else if (!strcmp (*argv, "--quiet"))
1037 quiet = 1;
1038 argc--; argv++;
1040 else if (!strcmp (*argv, "--debug"))
1042 verbose = debug = 1;
1043 argc--; argv++;
1045 else if (!strcmp (*argv, "--source"))
1047 argc--; argv++;
1048 if (argc)
1050 opt_source = *argv;
1051 argc--; argv++;
1054 else if (!strcmp (*argv, "--release"))
1056 argc--; argv++;
1057 if (argc)
1059 opt_release = *argv;
1060 argc--; argv++;
1063 else if (!strcmp (*argv, "--store"))
1065 opt_store = 1;
1066 argc--; argv++;
1068 else if (!strcmp (*argv, "--select"))
1070 argc--; argv++;
1071 if (argc)
1073 opt_select = strrchr (*argv, '/');
1074 if (opt_select)
1075 opt_select++;
1076 else
1077 opt_select = *argv;
1078 argc--; argv++;
1081 else if (!strcmp (*argv, "-I"))
1083 argc--; argv++;
1084 if (argc)
1086 opt_include = *argv;
1087 argc--; argv++;
1092 if (argc > 1)
1093 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1095 /* Start processing. */
1096 if (argc && strcmp (*argv, "-"))
1098 FILE *fp = fopen (*argv, "rb");
1099 if (!fp)
1100 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1101 top_parse_file (*argv, fp);
1102 fclose (fp);
1104 else
1105 top_parse_file ("-", stdin);
1107 return !!any_error;
1112 Local Variables:
1113 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1114 End: