1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005, 2013, 2015, 2016 g10 Code GmbH
3 * Copyright (C) 2006, 2008, 2011 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 3 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, see <https://www.gnu.org/licenses/>.
20 This is a simple texinfo to man page converter. It needs some
21 special markup in th e texinfo and tries best to get a create man
22 page. It has been designed for the GnuPG man pages and thus only
23 a few texinfo commands are supported.
25 To use this you need to add the following macros into your texinfo
37 They are used by yat2m to select parts of the Texinfo which should
38 go into the man page. These macros need to be used without leading
39 left space. Processing starts after a "manpage" macro has been
40 seen. "mansect" identifies the section and yat2m make sure to
41 emit the sections in the proper order. Note that @mansect skips
42 the next input line if that line begins with @section, @subsection or
45 To insert verbatim troff markup, the following texinfo code may be
52 alternativly a special comment may be used:
54 @c man:.B whatever you want
56 This is useful in case you need just one line. If you want to
57 include parts only in the man page but keep the texinfo
58 translation you may use:
61 stuff to be rendered only on man pages
64 or to exclude stuff from man pages:
67 stuff not to be rendered on man pages
70 the keyword @section is ignored, however @subsection gets rendered
71 as ".SS". @menu is completely skipped. Several man pages may be
72 extracted from one file, either using the --store or the --select
75 If you want to indent tables in the source use this style:
85 Don't change the indentation within a table and keep the same
86 number of white space at the start of the line. yat2m simply
87 detects the number of white spaces in front of an @item and remove
88 this number of spaces from all following lines until a new @item
89 is found or there are less spaces than for the last @item.
91 Note that @* does only work correctly if used at the end of an
108 # define MY_GCC_VERSION (__GNUC__ * 10000 \
109 + __GNUC_MINOR__ * 100 \
110 + __GNUC_PATCHLEVEL__)
112 # define MY_GCC_VERSION 0
115 #if MY_GCC_VERSION >= 20500
116 # define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
117 # define ATTR_NR_PRINTF(f, a) __attribute__ ((noreturn, format(printf,f,a)))
119 # define ATTR_PRINTF(f, a)
120 # define ATTR_NR_PRINTF(f, a)
122 #if MY_GCC_VERSION >= 30200
123 # define ATTR_MALLOC __attribute__ ((__malloc__))
131 #define VERSION "1.0"
133 /* The maximum length of a line including the linefeed and one extra
135 #define LINESIZE 1024
137 /* Number of allowed condition nestings. */
138 #define MAX_CONDITION_NESTING 10
144 static const char *opt_source
;
145 static const char *opt_release
;
146 static const char *opt_date
;
147 static const char *opt_select
;
148 static const char *opt_include
;
149 static int opt_store
;
151 /* Flag to keep track whether any error occurred. */
152 static int any_error
;
155 /* Object to keep macro definitions. */
158 struct macro_s
*next
;
159 char *value
; /* Malloced value. */
162 typedef struct macro_s
*macro_t
;
164 /* List of all defined macros. */
165 static macro_t macrolist
;
167 /* List of variables set by @set. */
168 static macro_t variablelist
;
170 /* List of global macro names. The value part is not used. */
171 static macro_t predefinedmacrolist
;
173 /* Object to keep track of @isset and @ifclear. */
176 int manverb
; /* "manverb" needs special treatment. */
177 int isset
; /* This is an @isset condition. */
178 char name
[1]; /* Name of the condition macro. */
180 typedef struct condition_s
*condition_t
;
182 /* The stack used to evaluate conditions. And the current states. */
183 static condition_t condition_stack
[MAX_CONDITION_NESTING
];
184 static int condition_stack_idx
;
185 static int cond_is_active
; /* State of ifset/ifclear */
186 static int cond_in_verbatim
; /* State of "manverb". */
189 /* Object to store one line of content. */
192 struct line_buffer_s
*next
;
193 int verbatim
; /* True if LINE contains verbatim data. The default
194 is Texinfo source. */
197 typedef struct line_buffer_s
*line_buffer_t
;
200 /* Object to collect the data of a section. */
201 struct section_buffer_s
203 char *name
; /* Malloced name of the section. This may be
204 NULL to indicate this slot is not used. */
205 line_buffer_t lines
; /* Linked list with the lines of the section. */
206 line_buffer_t
*lines_tail
; /* Helper for faster appending to the
208 line_buffer_t last_line
; /* Points to the last line appended. */
210 typedef struct section_buffer_s
*section_buffer_t
;
212 /* Variable to keep info about the current page together. */
215 /* Filename of the current page or NULL if no page is active. Malloced. */
218 /* Number of allocated elements in SECTIONS below. */
220 /* Array with the data of the sections. */
221 section_buffer_t sections
;
226 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
228 static const char * const standard_sections
[] =
229 { "NAME", "SYNOPSIS", "DESCRIPTION",
230 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
231 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
232 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
233 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL
};
236 /*-- Local prototypes. --*/
237 static void proc_texi_buffer (FILE *fp
, const char *line
, size_t len
,
238 int *table_level
, int *eol_action
);
240 static void die (const char *format
, ...) ATTR_NR_PRINTF(1,2);
241 static void err (const char *format
, ...) ATTR_PRINTF(1,2);
242 static void inf (const char *format
, ...) ATTR_PRINTF(1,2);
243 static void *xmalloc (size_t n
) ATTR_MALLOC
;
244 static void *xcalloc (size_t n
, size_t m
) ATTR_MALLOC
;
250 /* Print diagnostic message and exit with failure. */
252 die (const char *format
, ...)
257 fprintf (stderr
, "%s: ", PGM
);
259 va_start (arg_ptr
, format
);
260 vfprintf (stderr
, format
, arg_ptr
);
268 /* Print diagnostic message. */
270 err (const char *format
, ...)
275 if (strncmp (format
, "%s:%d:", 6))
276 fprintf (stderr
, "%s: ", PGM
);
278 va_start (arg_ptr
, format
);
279 vfprintf (stderr
, format
, arg_ptr
);
285 /* Print diagnostic message. */
287 inf (const char *format
, ...)
292 fprintf (stderr
, "%s: ", PGM
);
294 va_start (arg_ptr
, format
);
295 vfprintf (stderr
, format
, arg_ptr
);
304 void *p
= malloc (n
);
306 die ("out of core: %s", strerror (errno
));
311 xcalloc (size_t n
, size_t m
)
313 void *p
= calloc (n
, m
);
315 die ("out of core: %s", strerror (errno
));
320 xrealloc (void *old
, size_t n
)
322 void *p
= realloc (old
, n
);
324 die ("out of core: %s", strerror (errno
));
329 xstrdup (const char *string
)
331 void *p
= malloc (strlen (string
)+1);
333 die ("out of core: %s", strerror (errno
));
339 /* Uppercase the ascii characters in STRING. */
341 ascii_strupr (char *string
)
345 for (p
= string
; *p
; p
++)
352 /* Return the current date as an ISO string. */
356 static char buffer
[11+5];
360 if (opt_date
&& *opt_date
)
361 atime
= strtoul (opt_date
, NULL
, 10);
365 strcpy (buffer
, "????" "-??" "-??");
368 tp
= gmtime (&atime
);
369 sprintf (buffer
,"%04d-%02d-%02d",
370 1900+tp
->tm_year
, tp
->tm_mon
+1, tp
->tm_mday
);
376 /* Add NAME to the list of predefined macros which are global for all
379 add_predefined_macro (const char *name
)
383 for (m
=predefinedmacrolist
; m
; m
= m
->next
)
384 if (!strcmp (m
->name
, name
))
388 m
= xcalloc (1, sizeof *m
+ strlen (name
));
389 strcpy (m
->name
, name
);
390 m
->next
= predefinedmacrolist
;
391 predefinedmacrolist
= m
;
396 /* Create or update a macro with name MACRONAME and set its values TO
397 MACROVALUE. Note that ownership of the macro value is transferred
400 set_macro (const char *macroname
, char *macrovalue
)
404 for (m
=macrolist
; m
; m
= m
->next
)
405 if (!strcmp (m
->name
, macroname
))
411 m
= xcalloc (1, sizeof *m
+ strlen (macroname
));
412 strcpy (m
->name
, macroname
);
416 m
->value
= macrovalue
;
421 /* Create or update a variable with name and value given in NAMEANDVALUE. */
423 set_variable (char *nameandvalue
)
429 for (p
= nameandvalue
; *p
&& *p
!= ' ' && *p
!= '\t'; p
++)
436 while (*p
== ' ' || *p
== '\t')
441 for (m
=variablelist
; m
; m
= m
->next
)
442 if (!strcmp (m
->name
, nameandvalue
))
448 m
= xcalloc (1, sizeof *m
+ strlen (nameandvalue
));
449 strcpy (m
->name
, nameandvalue
);
450 m
->next
= variablelist
;
453 m
->value
= xstrdup (value
);
457 /* Return true if the macro or variable NAME is set, i.e. not the
458 empty string and not evaluating to 0. */
460 macro_set_p (const char *name
)
464 for (m
= macrolist
; m
; m
= m
->next
)
465 if (!strcmp (m
->name
, name
))
468 for (m
= variablelist
; m
; m
= m
->next
)
469 if (!strcmp (m
->name
, name
))
471 if (!m
|| !m
->value
|| !*m
->value
)
473 if ((*m
->value
& 0x80) || !isdigit (*m
->value
))
474 return 1; /* Not a digit but some other string. */
475 return !!atoi (m
->value
);
479 /* Evaluate the current conditions. */
481 evaluate_conditions (const char *fname
, int lnr
)
485 /* for (i=0; i < condition_stack_idx; i++) */
486 /* inf ("%s:%d: stack[%d] %s %s %c", */
487 /* fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
488 /* condition_stack[i]->name, */
489 /* (macro_set_p (condition_stack[i]->name) */
490 /* ^ !condition_stack[i]->isset)? 't':'f'); */
493 cond_in_verbatim
= 0;
494 if (condition_stack_idx
)
496 for (i
=0; i
< condition_stack_idx
; i
++)
498 if (condition_stack
[i
]->manverb
)
499 cond_in_verbatim
= (macro_set_p (condition_stack
[i
]->name
)
500 ^ !condition_stack
[i
]->isset
);
501 else if (!(macro_set_p (condition_stack
[i
]->name
)
502 ^ !condition_stack
[i
]->isset
))
510 /* inf ("%s:%d: active=%d verbatim=%d", */
511 /* fname, lnr, cond_is_active, cond_in_verbatim); */
515 /* Push a condition with condition macro NAME onto the stack. If
516 ISSET is true, a @isset condition is pushed. */
518 push_condition (const char *name
, int isset
, const char *fname
, int lnr
)
523 if (condition_stack_idx
>= MAX_CONDITION_NESTING
)
525 err ("%s:%d: condition nested too deep", fname
, lnr
);
529 if (!strcmp (name
, "manverb"))
533 err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname
, lnr
);
539 cond
= xcalloc (1, sizeof *cond
+ strlen (name
));
540 cond
->manverb
= manverb
;
542 strcpy (cond
->name
, name
);
544 condition_stack
[condition_stack_idx
++] = cond
;
545 evaluate_conditions (fname
, lnr
);
549 /* Remove the last condition from the stack. ISSET is used for error
552 pop_condition (int isset
, const char *fname
, int lnr
)
554 if (!condition_stack_idx
)
556 err ("%s:%d: unbalanced \"@end %s\"",
557 fname
, lnr
, isset
?"isset":"isclear");
560 condition_stack_idx
--;
561 free (condition_stack
[condition_stack_idx
]);
562 condition_stack
[condition_stack_idx
] = NULL
;
563 evaluate_conditions (fname
, lnr
);
568 /* Return a section buffer for the section NAME. Allocate a new buffer
569 if this is a new section. Keep track of the sections in THEPAGE.
570 This function may reallocate the section array in THEPAGE. */
571 static section_buffer_t
572 get_section_buffer (const char *name
)
575 section_buffer_t sect
;
577 /* If there is no section we put everything into the required NAME
578 section. Given that this is the first one listed it is likely
579 that error are easily visible. */
583 for (i
=0; i
< thepage
.n_sections
; i
++)
585 sect
= thepage
.sections
+ i
;
586 if (sect
->name
&& !strcmp (name
, sect
->name
))
589 for (i
=0; i
< thepage
.n_sections
; i
++)
590 if (!thepage
.sections
[i
].name
)
592 if (thepage
.n_sections
&& i
< thepage
.n_sections
)
593 sect
= thepage
.sections
+ i
;
596 /* We need to allocate or reallocate the section array. */
597 size_t old_n
= thepage
.n_sections
;
601 thepage
.sections
= xcalloc (new_n
, sizeof *thepage
.sections
);
604 thepage
.sections
= xrealloc (thepage
.sections
,
606 * sizeof *thepage
.sections
));
607 memset (thepage
.sections
+ old_n
, 0,
608 new_n
* sizeof *thepage
.sections
);
610 thepage
.n_sections
+= new_n
;
612 /* Setup the tail pointers. */
613 for (i
=old_n
; i
< thepage
.n_sections
; i
++)
615 sect
= thepage
.sections
+ i
;
616 sect
->lines_tail
= §
->lines
;
618 sect
= thepage
.sections
+ old_n
;
621 /* Store the name. */
622 assert (!sect
->name
);
623 sect
->name
= xstrdup (name
);
629 /* Add the content of LINE to the section named SECTNAME. */
631 add_content (const char *sectname
, char *line
, int verbatim
)
633 section_buffer_t sect
;
636 sect
= get_section_buffer (sectname
);
637 if (sect
->last_line
&& !sect
->last_line
->verbatim
== !verbatim
)
639 /* Lets append that line to the last one. We do this to keep
640 all lines of the same kind (i.e.verbatim or not) together in
644 lb
= sect
->last_line
;
645 n1
= strlen (lb
->line
);
646 n
= n1
+ 1 + strlen (line
) + 1;
647 lb
->line
= xrealloc (lb
->line
, n
);
648 strcpy (lb
->line
+n1
, "\n");
649 strcpy (lb
->line
+n1
+1, line
);
653 lb
= xcalloc (1, sizeof *lb
);
654 lb
->verbatim
= verbatim
;
655 lb
->line
= xstrdup (line
);
656 sect
->last_line
= lb
;
657 *sect
->lines_tail
= lb
;
658 sect
->lines_tail
= &lb
->next
;
663 /* Prepare for a new man page using the filename NAME. */
665 start_page (char *name
)
668 inf ("starting page '%s'", name
);
669 assert (!thepage
.name
);
670 thepage
.name
= xstrdup (name
);
671 thepage
.n_sections
= 0;
675 /* Write the .TH entry of the current page. Return -1 if there is a
676 problem with the page. */
682 fputs (".\\\" Created from Texinfo source by yat2m " VERSION
"\n", fp
);
684 name
= ascii_strupr (xstrdup (thepage
.name
));
685 p
= strrchr (name
, '.');
688 err ("no section name in man page '%s'", thepage
.name
);
693 fprintf (fp
, ".TH %s %s %s \"%s\" \"%s\"\n",
694 name
, p
, isodatestring (), opt_release
, opt_source
);
700 /* Process the texinfo command COMMAND (without the leading @) and
701 write output if needed to FP. REST is the remainer of the line
702 which should either point to an opening brace or to a white space.
703 The function returns the number of characters already processed
704 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
705 control the indentation of tables. */
707 proc_texi_cmd (FILE *fp
, const char *command
, const char *rest
, size_t len
,
708 int *table_level
, int *eol_action
)
711 const char *name
; /* Name of the command. */
712 int what
; /* What to do with this command. */
713 const char *lead_in
; /* String to print with a opening brace. */
714 const char *lead_out
;/* String to print with the closing brace. */
716 { "command", 0, "\\fB", "\\fR" },
717 { "code", 0, "\\fB", "\\fR" },
718 { "url", 0, "\\fB", "\\fR" },
719 { "sc", 0, "\\fB", "\\fR" },
720 { "var", 0, "\\fI", "\\fR" },
721 { "samp", 0, "\\(aq", "\\(aq" },
722 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
723 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
726 { "option", 0, "\\fB", "\\fR" },
727 { "example", 1, ".RS 2\n.nf\n" },
728 { "smallexample", 1, ".RS 2\n.nf\n" },
732 { "ref", 0, "[", "]" },
733 { "xref", 0, "See: [", "]" },
734 { "pxref", 0, "see: [", "]" },
735 { "uref", 0, "(\\fB", "\\fR)" },
736 { "footnote",0, " ([", "])" },
737 { "emph", 0, "\\fI", "\\fR" },
747 { "subsection", 6, "\n.SS " },
749 { "item", 2, ".TP\n.B " },
750 { "itemx", 2, ".TQ\n.B " },
753 { "bullet", 0, "* " },
757 { "quotation",1, ".RS\n\\fB" },
764 const char *lead_out
= NULL
;
767 for (i
=0; cmdtbl
[i
].name
&& strcmp (cmdtbl
[i
].name
, command
); i
++)
771 s
= cmdtbl
[i
].lead_in
;
774 lead_out
= cmdtbl
[i
].lead_out
;
775 switch (cmdtbl
[i
].what
)
777 case 1: /* Throw away the entire line. */
778 s
= memchr (rest
, '\n', len
);
779 return s
? (s
-rest
)+1 : len
;
780 case 2: /* Handle @item. */
782 case 3: /* Handle table. */
783 if (++(*table_level
) > 1)
785 /* Now throw away the entire line. */
786 s
= memchr (rest
, '\n', len
);
787 return s
? (s
-rest
)+1 : len
;
789 case 4: /* Handle end. */
790 for (s
=rest
, n
=len
; n
&& (*s
== ' ' || *s
== '\t'); s
++, n
--)
792 if (n
>= 5 && !memcmp (s
, "table", 5)
793 && (!n
|| s
[5] == ' ' || s
[5] == '\t' || s
[5] == '\n'))
795 if ((*table_level
)-- > 1)
800 else if (n
>= 7 && !memcmp (s
, "example", 7)
801 && (!n
|| s
[7] == ' ' || s
[7] == '\t' || s
[7] == '\n'))
803 fputs (".fi\n.RE\n", fp
);
805 else if (n
>= 12 && !memcmp (s
, "smallexample", 12)
806 && (!n
|| s
[12] == ' ' || s
[12] == '\t' || s
[12] == '\n'))
808 fputs (".fi\n.RE\n", fp
);
810 else if (n
>= 9 && !memcmp (s
, "quotation", 9)
811 && (!n
|| s
[9] == ' ' || s
[9] == '\t' || s
[9] == '\n'))
813 fputs ("\\fR\n.RE\n", fp
);
815 /* Now throw away the entire line. */
816 s
= memchr (rest
, '\n', len
);
817 return s
? (s
-rest
)+1 : len
;
818 case 5: /* Handle special comments. */
819 for (s
=rest
, n
=len
; n
&& (*s
== ' ' || *s
== '\t'); s
++, n
--)
821 if (n
>= 4 && !memcmp (s
, "man:", 4))
823 for (s
+=4, n
-=4; n
&& *s
!= '\n'; n
--, s
++)
827 /* Now throw away the entire line. */
828 s
= memchr (rest
, '\n', len
);
829 return s
? (s
-rest
)+1 : len
;
840 err ("opening brace for command '%s' missing", command
);
845 /* Find closing brace. */
846 for (s
=rest
+1, n
=1; *s
&& n
< len
; s
++, n
++)
851 err ("closing brace for command '%s' not found", command
);
856 size_t len
= s
- (rest
+ 1);
859 for (m
= variablelist
; m
; m
= m
->next
)
860 if (strlen (m
->name
) == len
861 &&!strncmp (m
->name
, rest
+1, len
))
864 fputs (m
->value
, fp
);
866 inf ("texinfo variable '%.*s' is not set",
879 for (m
= macrolist
; m
; m
= m
->next
)
880 if (!strcmp (m
->name
, command
))
884 proc_texi_buffer (fp
, m
->value
, strlen (m
->value
),
885 table_level
, eol_action
);
886 ignore_args
= 1; /* Parameterized macros are not yet supported. */
889 inf ("texinfo command '%s' not supported (%.*s)", command
,
890 (int)((s
= memchr (rest
, '\n', len
)), (s
? (s
-rest
) : len
)), rest
);
895 /* Find matching closing brace. */
896 for (s
=rest
+1, n
=1, i
=1; i
&& *s
&& n
< len
; s
++, n
++)
903 err ("closing brace for command '%s' not found", command
);
906 if (n
> 2 && !ignore_args
)
907 proc_texi_buffer (fp
, rest
+1, n
-2, table_level
, eol_action
);
913 fputs (lead_out
, fp
);
920 /* Process the string LINE with LEN bytes of Texinfo content. */
922 proc_texi_buffer (FILE *fp
, const char *line
, size_t len
,
923 int *table_level
, int *eol_action
)
931 for (s
=line
; *s
&& len
; s
++, len
--)
939 case '@': case '{': case '}':
940 putc (*s
, fp
); in_cmd
= 0;
942 case ':': /* Not ending a sentence flag. */
945 case '.': case '!': case '?': /* Ending a sentence. */
946 putc (*s
, fp
); in_cmd
= 0;
948 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
949 putc (*s
, fp
); in_cmd
= 0;
953 cmdbuf
[cmdidx
++] = *s
;
958 else if (*s
== '{' || *s
== ' ' || *s
== '\t' || *s
== '\n')
961 n
= proc_texi_cmd (fp
, cmdbuf
, s
, len
, table_level
, eol_action
);
967 else if (cmdidx
< sizeof cmdbuf
-1)
968 cmdbuf
[cmdidx
++] = *s
;
971 err ("texinfo command too long - ignored");
981 case 1: /* Create a dummy paragraph. */
982 fputs ("\n\\ \n", fp
);
998 n
= proc_texi_cmd (fp
, cmdbuf
, s
, len
, table_level
, eol_action
);
1002 /* in_cmd = 0; -- doc only */
1007 /* Do something with the Texinfo line LINE. */
1009 parse_texi_line (FILE *fp
, const char *line
, int *table_level
)
1013 /* A quick test whether there are any texinfo commands. */
1014 if (!strchr (line
, '@'))
1020 proc_texi_buffer (fp
, line
, strlen (line
), table_level
, &eol_action
);
1025 /* Write all the lines LINES to FP. */
1027 write_content (FILE *fp
, line_buffer_t lines
)
1030 int table_level
= 0;
1032 for (line
= lines
; line
; line
= line
->next
)
1036 fputs (line
->line
, fp
);
1041 /* fputs ("TEXI---", fp); */
1042 /* fputs (line->line, fp); */
1043 /* fputs ("---\n", fp); */
1044 parse_texi_line (fp
, line
->line
, &table_level
);
1052 is_standard_section (const char *name
)
1057 for (i
=0; (s
=standard_sections
[i
]); i
++)
1058 if (!strcmp (s
, name
))
1064 /* Finish a page; that is sort the data and write it out to the file. */
1069 section_buffer_t sect
= NULL
;
1075 return; /* No page active. */
1078 inf ("finishing page '%s'", thepage
.name
);
1082 if (!strcmp (opt_select
, thepage
.name
))
1084 inf ("selected '%s'", thepage
.name
);
1089 fp
= fopen ( "/dev/null", "w" );
1091 die ("failed to open /dev/null: %s\n", strerror (errno
));
1096 inf ("writing '%s'", thepage
.name
);
1097 fp
= fopen ( thepage
.name
, "w" );
1099 die ("failed to create '%s': %s\n", thepage
.name
, strerror (errno
));
1107 for (idx
=0; (s
=standard_sections
[idx
]); idx
++)
1109 for (i
=0; i
< thepage
.n_sections
; i
++)
1111 sect
= thepage
.sections
+ i
;
1112 if (sect
->name
&& !strcmp (s
, sect
->name
))
1115 if (i
== thepage
.n_sections
)
1120 fprintf (fp
, ".SH %s\n", sect
->name
);
1121 write_content (fp
, sect
->lines
);
1122 /* Now continue with all non standard sections directly
1123 following this one. */
1124 for (i
++; i
< thepage
.n_sections
; i
++)
1126 sect
= thepage
.sections
+ i
;
1127 if (sect
->name
&& is_standard_section (sect
->name
))
1131 fprintf (fp
, ".SH %s\n", sect
->name
);
1132 write_content (fp
, sect
->lines
);
1143 free (thepage
.name
);
1144 thepage
.name
= NULL
;
1145 /* FIXME: Cleanup the content. */
1151 /* Parse one Texinfo file and create manpages according to the
1152 embedded instructions. */
1154 parse_file (const char *fname
, FILE *fp
, char **section_name
, int in_pause
)
1158 /* Fixme: The following state variables don't carry over to include
1160 int skip_to_end
= 0; /* Used to skip over menu entries. */
1161 int skip_sect_line
= 0; /* Skip after @mansect. */
1162 int item_indent
= 0; /* How far is the current @item indented. */
1164 /* Helper to define a macro. */
1165 char *macroname
= NULL
;
1166 char *macrovalue
= NULL
;
1167 size_t macrovaluesize
= 0;
1168 size_t macrovalueused
= 0;
1170 line
= xmalloc (LINESIZE
);
1171 while (fgets (line
, LINESIZE
, fp
))
1173 size_t n
= strlen (line
);
1178 if (!n
|| line
[n
-1] != '\n')
1180 err ("%s:%d: trailing linefeed missing, line too long or "
1181 "embedded Nul character", fname
, lnr
);
1186 /* Kludge to allow indentation of tables. */
1187 for (p
=line
; *p
== ' ' || *p
== '\t'; p
++)
1191 if (*p
== '@' && !strncmp (p
+1, "item", 4))
1192 item_indent
= p
- line
; /* Set a new indent level. */
1193 else if (p
- line
< item_indent
)
1194 item_indent
= 0; /* Switch off indention. */
1198 memmove (line
, line
+item_indent
, n
- item_indent
+ 1);
1206 for (p
=line
+1, n
=1; *p
&& *p
!= ' ' && *p
!= '\t'; p
++)
1208 while (*p
== ' ' || *p
== '\t')
1214 /* Take action on macro. */
1217 if (n
== 4 && !memcmp (line
, "@end", 4)
1218 && (line
[4]==' '||line
[4]=='\t'||!line
[4])
1219 && !strncmp (p
, "macro", 5)
1220 && (p
[5]==' '||p
[5]=='\t'||!p
[5]))
1223 macrovalue
[--macrovalueused
] = 0; /* Kill the last LF. */
1224 macrovalue
[macrovalueused
] = 0; /* Terminate macro. */
1225 macrovalue
= xrealloc (macrovalue
, macrovalueused
+1);
1227 set_macro (macroname
, macrovalue
);
1234 if (macrovalueused
+ strlen (line
) + 2 >= macrovaluesize
)
1236 macrovaluesize
+= strlen (line
) + 256;
1237 macrovalue
= xrealloc (macrovalue
, macrovaluesize
);
1239 strcpy (macrovalue
+macrovalueused
, line
);
1240 macrovalueused
+= strlen (line
);
1241 macrovalue
[macrovalueused
++] = '\n';
1247 if (n
>= 5 && !memcmp (line
, "@node", 5)
1248 && (line
[5]==' '||line
[5]=='\t'||!line
[5]))
1250 /* Completey ignore @node lines. */
1258 if (!strncmp (line
, "@section", 8)
1259 || !strncmp (line
, "@subsection", 11)
1260 || !strncmp (line
, "@chapheading", 12))
1264 /* We only parse lines we need and ignore the rest. There are a
1265 few macros used to control this as well as one @ifset
1266 command. Parts we know about are saved away into containers
1267 separate for each section. */
1269 /* First process ifset/ifclear commands. */
1272 if (n
== 6 && !memcmp (line
, "@ifset", 6)
1273 && (line
[6]==' '||line
[6]=='\t'))
1275 for (p
=line
+7; *p
== ' ' || *p
== '\t'; p
++)
1279 err ("%s:%d: name missing after \"@ifset\"", fname
, lnr
);
1282 for (pend
=p
; *pend
&& *pend
!= ' ' && *pend
!= '\t'; pend
++)
1284 *pend
= 0; /* Ignore rest of the line. */
1285 push_condition (p
, 1, fname
, lnr
);
1288 else if (n
== 8 && !memcmp (line
, "@ifclear", 8)
1289 && (line
[8]==' '||line
[8]=='\t'))
1291 for (p
=line
+9; *p
== ' ' || *p
== '\t'; p
++)
1295 err ("%s:%d: name missing after \"@ifsclear\"", fname
, lnr
);
1298 for (pend
=p
; *pend
&& *pend
!= ' ' && *pend
!= '\t'; pend
++)
1300 *pend
= 0; /* Ignore rest of the line. */
1301 push_condition (p
, 0, fname
, lnr
);
1304 else if (n
== 4 && !memcmp (line
, "@end", 4)
1305 && (line
[4]==' '||line
[4]=='\t')
1306 && !strncmp (p
, "ifset", 5)
1307 && (p
[5]==' '||p
[5]=='\t'||!p
[5]))
1309 pop_condition (1, fname
, lnr
);
1312 else if (n
== 4 && !memcmp (line
, "@end", 4)
1313 && (line
[4]==' '||line
[4]=='\t')
1314 && !strncmp (p
, "ifclear", 7)
1315 && (p
[7]==' '||p
[7]=='\t'||!p
[7]))
1317 pop_condition (0, fname
, lnr
);
1322 /* Take action on ifset/ifclear. */
1323 if (!cond_is_active
)
1326 /* Process commands. */
1330 && n
== 4 && !memcmp (line
, "@end", 4)
1331 && (line
[4]==' '||line
[4]=='\t'||!line
[4]))
1335 else if (cond_in_verbatim
)
1339 else if (n
== 6 && !memcmp (line
, "@macro", 6))
1341 macroname
= xstrdup (p
);
1342 macrovalue
= xmalloc ((macrovaluesize
= 1024));
1345 else if (n
== 4 && !memcmp (line
, "@set", 4))
1349 else if (n
== 8 && !memcmp (line
, "@manpage", 8))
1351 free (*section_name
);
1352 *section_name
= NULL
;
1357 else if (n
== 8 && !memcmp (line
, "@mansect", 8))
1360 err ("%s:%d: section outside of a man page", fname
, lnr
);
1363 free (*section_name
);
1364 *section_name
= ascii_strupr (xstrdup (p
));
1369 else if (n
== 9 && !memcmp (line
, "@manpause", 9))
1372 err ("%s:%d: pausing outside of a man section", fname
, lnr
);
1374 err ("%s:%d: already pausing", fname
, lnr
);
1378 else if (n
== 8 && !memcmp (line
, "@mancont", 8))
1381 err ("%s:%d: continue outside of a man section", fname
, lnr
);
1383 err ("%s:%d: continue while not pausing", fname
, lnr
);
1387 else if (n
== 5 && !memcmp (line
, "@menu", 5)
1388 && (line
[5]==' '||line
[5]=='\t'||!line
[5]))
1392 else if (n
== 8 && !memcmp (line
, "@include", 8)
1393 && (line
[8]==' '||line
[8]=='\t'||!line
[8]))
1395 char *incname
= xstrdup (p
);
1396 FILE *incfp
= fopen (incname
, "r");
1398 if (!incfp
&& opt_include
&& *opt_include
&& *p
!= '/')
1401 incname
= xmalloc (strlen (opt_include
) + 1
1403 strcpy (incname
, opt_include
);
1404 if ( incname
[strlen (incname
)-1] != '/' )
1405 strcat (incname
, "/");
1406 strcat (incname
, p
);
1407 incfp
= fopen (incname
, "r");
1411 err ("can't open include file '%s': %s",
1412 incname
, strerror (errno
));
1415 parse_file (incname
, incfp
, section_name
, in_pause
);
1420 else if (n
== 4 && !memcmp (line
, "@bye", 4)
1421 && (line
[4]==' '||line
[4]=='\t'||!line
[4]))
1425 else if (!skip_to_end
)
1428 else if (!skip_to_end
)
1431 if (got_line
&& cond_in_verbatim
)
1432 add_content (*section_name
, line
, 1);
1433 else if (got_line
&& thepage
.name
&& *section_name
&& !in_pause
)
1434 add_content (*section_name
, line
, 0);
1438 err ("%s:%d: read error: %s", fname
, lnr
, strerror (errno
));
1446 top_parse_file (const char *fname
, FILE *fp
)
1448 char *section_name
= NULL
; /* Name of the current section or NULL
1449 if not in a section. */
1454 macro_t next
= macrolist
->next
;
1455 free (macrolist
->value
);
1459 while (variablelist
)
1461 macro_t next
= variablelist
->next
;
1462 free (variablelist
->value
);
1463 free (variablelist
);
1464 variablelist
= next
;
1466 for (m
=predefinedmacrolist
; m
; m
= m
->next
)
1467 set_macro (m
->name
, xstrdup ("1"));
1469 cond_in_verbatim
= 0;
1471 parse_file (fname
, fp
, §ion_name
, 0);
1472 free (section_name
);
1478 main (int argc
, char **argv
)
1485 /* Define default macros. The trick is that these macros are not
1486 defined when using the actual texinfo renderer. */
1487 add_predefined_macro ("isman");
1488 add_predefined_macro ("manverb");
1490 /* Option parsing. */
1495 while (argc
&& last_argc
!= argc
)
1498 if (!strcmp (*argv
, "--"))
1503 else if (!strcmp (*argv
, "--help"))
1506 "Usage: " PGM
" [OPTION] [FILE]\n"
1507 "Extract man pages from a Texinfo source.\n\n"
1508 " --source NAME use NAME as source field\n"
1509 " --release STRING use STRING as the release field\n"
1510 " --date EPOCH use EPOCH as publication date\n"
1511 " --store write output using @manpage name\n"
1512 " --select NAME only output pages with @manpage NAME\n"
1513 " --verbose enable extra informational output\n"
1514 " --debug enable additional debug output\n"
1515 " --help display this help and exit\n"
1516 " -I DIR also search in include DIR\n"
1517 " -D gpgone the only usable define\n\n"
1518 "With no FILE, or when FILE is -, read standard input.\n\n"
1519 "Report bugs to <bugs@g10code.com>.");
1522 else if (!strcmp (*argv
, "--version"))
1524 puts (PGM
" " VERSION
"\n"
1525 "Copyright (C) 2005 g10 Code GmbH\n"
1526 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1527 "This is free software, and you are welcome to redistribute it\n"
1528 "under certain conditions. See the file COPYING for details.");
1531 else if (!strcmp (*argv
, "--verbose"))
1536 else if (!strcmp (*argv
, "--quiet"))
1541 else if (!strcmp (*argv
, "--debug"))
1543 verbose
= debug
= 1;
1546 else if (!strcmp (*argv
, "--source"))
1555 else if (!strcmp (*argv
, "--release"))
1560 opt_release
= *argv
;
1564 else if (!strcmp (*argv
, "--date"))
1573 else if (!strcmp (*argv
, "--store"))
1578 else if (!strcmp (*argv
, "--select"))
1583 opt_select
= strrchr (*argv
, '/');
1591 else if (!strcmp (*argv
, "-I"))
1596 opt_include
= *argv
;
1600 else if (!strcmp (*argv
, "-D"))
1605 add_predefined_macro (*argv
);
1612 die ("usage: " PGM
" [OPTION] [FILE] (try --help for more information)\n");
1614 /* Start processing. */
1615 if (argc
&& strcmp (*argv
, "-"))
1617 FILE *fp
= fopen (*argv
, "rb");
1619 die ("%s:0: can't open file: %s", *argv
, strerror (errno
));
1620 top_parse_file (*argv
, fp
);
1624 top_parse_file ("-", stdin
);
1632 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"