1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005, 2013 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 <http://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 VERSION "1.0"
110 /* The maximum length of a line including the linefeed and one extra
112 #define LINESIZE 1024
114 /* Number of allowed condition nestings. */
115 #define MAX_CONDITION_NESTING 10
121 static const char *opt_source
;
122 static const char *opt_release
;
123 static const char *opt_select
;
124 static const char *opt_include
;
125 static int opt_store
;
127 /* Flag to keep track whether any error occurred. */
128 static int any_error
;
131 /* Object to keep macro definitions. */
134 struct macro_s
*next
;
135 char *value
; /* Malloced value. */
138 typedef struct macro_s
*macro_t
;
140 /* List of all defined macros. */
141 static macro_t macrolist
;
143 /* List of variables set by @set. */
144 static macro_t variablelist
;
146 /* List of global macro names. The value part is not used. */
147 static macro_t predefinedmacrolist
;
149 /* Object to keep track of @isset and @ifclear. */
152 int manverb
; /* "manverb" needs special treatment. */
153 int isset
; /* This is an @isset condition. */
154 char name
[1]; /* Name of the condition macro. */
156 typedef struct condition_s
*condition_t
;
158 /* The stack used to evaluate conditions. And the current states. */
159 static condition_t condition_stack
[MAX_CONDITION_NESTING
];
160 static int condition_stack_idx
;
161 static int cond_is_active
; /* State of ifset/ifclear */
162 static int cond_in_verbatim
; /* State of "manverb". */
165 /* Object to store one line of content. */
168 struct line_buffer_s
*next
;
169 int verbatim
; /* True if LINE contains verbatim data. The default
170 is Texinfo source. */
173 typedef struct line_buffer_s
*line_buffer_t
;
176 /* Object to collect the data of a section. */
177 struct section_buffer_s
179 char *name
; /* Malloced name of the section. This may be
180 NULL to indicate this slot is not used. */
181 line_buffer_t lines
; /* Linked list with the lines of the section. */
182 line_buffer_t
*lines_tail
; /* Helper for faster appending to the
184 line_buffer_t last_line
; /* Points to the last line appended. */
186 typedef struct section_buffer_s
*section_buffer_t
;
188 /* Variable to keep info about the current page together. */
191 /* Filename of the current page or NULL if no page is active. Malloced. */
194 /* Number of allocated elements in SECTIONS below. */
196 /* Array with the data of the sections. */
197 section_buffer_t sections
;
202 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
204 static const char * const standard_sections
[] =
205 { "NAME", "SYNOPSIS", "DESCRIPTION",
206 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
207 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
208 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
209 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL
};
212 /*-- Local prototypes. --*/
213 static void proc_texi_buffer (FILE *fp
, const char *line
, size_t len
,
214 int *table_level
, int *eol_action
);
218 /* Print diagnostic message and exit with failure. */
220 die (const char *format
, ...)
225 fprintf (stderr
, "%s: ", PGM
);
227 va_start (arg_ptr
, format
);
228 vfprintf (stderr
, format
, arg_ptr
);
236 /* Print diagnostic message. */
238 err (const char *format
, ...)
243 if (strncmp (format
, "%s:%d:", 6))
244 fprintf (stderr
, "%s: ", PGM
);
246 va_start (arg_ptr
, format
);
247 vfprintf (stderr
, format
, arg_ptr
);
253 /* Print diagnostic message. */
255 inf (const char *format
, ...)
260 fprintf (stderr
, "%s: ", PGM
);
262 va_start (arg_ptr
, format
);
263 vfprintf (stderr
, format
, arg_ptr
);
272 void *p
= malloc (n
);
274 die ("out of core: %s", strerror (errno
));
279 xcalloc (size_t n
, size_t m
)
281 void *p
= calloc (n
, m
);
283 die ("out of core: %s", strerror (errno
));
288 xrealloc (void *old
, size_t n
)
290 void *p
= realloc (old
, n
);
292 die ("out of core: %s", strerror (errno
));
297 xstrdup (const char *string
)
299 void *p
= malloc (strlen (string
)+1);
301 die ("out of core: %s", strerror (errno
));
307 /* Uppercase the ascii characters in STRING. */
309 ascii_strupr (char *string
)
313 for (p
= string
; *p
; p
++)
320 /* Return the current date as an ISO string. */
324 static char buffer
[11+5];
326 time_t atime
= time (NULL
);
329 strcpy (buffer
, "????" "-??" "-??");
332 tp
= gmtime (&atime
);
333 sprintf (buffer
,"%04d-%02d-%02d",
334 1900+tp
->tm_year
, tp
->tm_mon
+1, tp
->tm_mday
);
340 /* Add NAME to the list of predefined macros which are global for all
343 add_predefined_macro (const char *name
)
347 for (m
=predefinedmacrolist
; m
; m
= m
->next
)
348 if (!strcmp (m
->name
, name
))
352 m
= xcalloc (1, sizeof *m
+ strlen (name
));
353 strcpy (m
->name
, name
);
354 m
->next
= predefinedmacrolist
;
355 predefinedmacrolist
= m
;
360 /* Create or update a macro with name MACRONAME and set its values TO
361 MACROVALUE. Note that ownership of the macro value is transferred
364 set_macro (const char *macroname
, char *macrovalue
)
368 for (m
=macrolist
; m
; m
= m
->next
)
369 if (!strcmp (m
->name
, macroname
))
375 m
= xcalloc (1, sizeof *m
+ strlen (macroname
));
376 strcpy (m
->name
, macroname
);
380 m
->value
= macrovalue
;
385 /* Create or update a variable with name and value given in NAMEANDVALUE. */
387 set_variable (char *nameandvalue
)
393 for (p
= nameandvalue
; *p
&& *p
!= ' ' && *p
!= '\t'; p
++)
400 while (*p
== ' ' || *p
== '\t')
405 for (m
=variablelist
; m
; m
= m
->next
)
406 if (!strcmp (m
->name
, nameandvalue
))
412 m
= xcalloc (1, sizeof *m
+ strlen (nameandvalue
));
413 strcpy (m
->name
, nameandvalue
);
414 m
->next
= variablelist
;
417 m
->value
= xstrdup (value
);
421 /* Return true if the macro or variable NAME is set, i.e. not the
422 empty string and not evaluating to 0. */
424 macro_set_p (const char *name
)
428 for (m
= macrolist
; m
; m
= m
->next
)
429 if (!strcmp (m
->name
, name
))
432 for (m
= variablelist
; m
; m
= m
->next
)
433 if (!strcmp (m
->name
, name
))
435 if (!m
|| !m
->value
|| !*m
->value
)
437 if ((*m
->value
& 0x80) || !isdigit (*m
->value
))
438 return 1; /* Not a digit but some other string. */
439 return !!atoi (m
->value
);
443 /* Evaluate the current conditions. */
445 evaluate_conditions (const char *fname
, int lnr
)
449 /* for (i=0; i < condition_stack_idx; i++) */
450 /* inf ("%s:%d: stack[%d] %s %s %c", */
451 /* fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
452 /* condition_stack[i]->name, */
453 /* (macro_set_p (condition_stack[i]->name) */
454 /* ^ !condition_stack[i]->isset)? 't':'f'); */
457 cond_in_verbatim
= 0;
458 if (condition_stack_idx
)
460 for (i
=0; i
< condition_stack_idx
; i
++)
462 if (condition_stack
[i
]->manverb
)
463 cond_in_verbatim
= (macro_set_p (condition_stack
[i
]->name
)
464 ^ !condition_stack
[i
]->isset
);
465 else if (!(macro_set_p (condition_stack
[i
]->name
)
466 ^ !condition_stack
[i
]->isset
))
474 /* inf ("%s:%d: active=%d verbatim=%d", */
475 /* fname, lnr, cond_is_active, cond_in_verbatim); */
479 /* Push a condition with condition macro NAME onto the stack. If
480 ISSET is true, a @isset condition is pushed. */
482 push_condition (const char *name
, int isset
, const char *fname
, int lnr
)
487 if (condition_stack_idx
>= MAX_CONDITION_NESTING
)
489 err ("%s:%d: condition nested too deep", fname
, lnr
);
493 if (!strcmp (name
, "manverb"))
497 err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname
, lnr
);
503 cond
= xcalloc (1, sizeof *cond
+ strlen (name
));
504 cond
->manverb
= manverb
;
506 strcpy (cond
->name
, name
);
508 condition_stack
[condition_stack_idx
++] = cond
;
509 evaluate_conditions (fname
, lnr
);
513 /* Remove the last condition from the stack. ISSET is used for error
516 pop_condition (int isset
, const char *fname
, int lnr
)
518 if (!condition_stack_idx
)
520 err ("%s:%d: unbalanced \"@end %s\"",
521 fname
, lnr
, isset
?"isset":"isclear");
524 condition_stack_idx
--;
525 free (condition_stack
[condition_stack_idx
]);
526 condition_stack
[condition_stack_idx
] = NULL
;
527 evaluate_conditions (fname
, lnr
);
532 /* Return a section buffer for the section NAME. Allocate a new buffer
533 if this is a new section. Keep track of the sections in THEPAGE.
534 This function may reallocate the section array in THEPAGE. */
535 static section_buffer_t
536 get_section_buffer (const char *name
)
539 section_buffer_t sect
;
541 /* If there is no section we put everything into the required NAME
542 section. Given that this is the first one listed it is likely
543 that error are easily visible. */
547 for (i
=0; i
< thepage
.n_sections
; i
++)
549 sect
= thepage
.sections
+ i
;
550 if (sect
->name
&& !strcmp (name
, sect
->name
))
553 for (i
=0; i
< thepage
.n_sections
; i
++)
554 if (!thepage
.sections
[i
].name
)
556 if (i
< thepage
.n_sections
)
557 sect
= thepage
.sections
+ i
;
560 /* We need to allocate or reallocate the section array. */
561 size_t old_n
= thepage
.n_sections
;
565 thepage
.sections
= xcalloc (new_n
, sizeof *thepage
.sections
);
568 thepage
.sections
= xrealloc (thepage
.sections
,
570 * sizeof *thepage
.sections
));
571 memset (thepage
.sections
+ old_n
, 0,
572 new_n
* sizeof *thepage
.sections
);
574 thepage
.n_sections
+= new_n
;
576 /* Setup the tail pointers. */
577 for (i
=old_n
; i
< thepage
.n_sections
; i
++)
579 sect
= thepage
.sections
+ i
;
580 sect
->lines_tail
= §
->lines
;
582 sect
= thepage
.sections
+ old_n
;
585 /* Store the name. */
586 assert (!sect
->name
);
587 sect
->name
= xstrdup (name
);
593 /* Add the content of LINE to the section named SECTNAME. */
595 add_content (const char *sectname
, char *line
, int verbatim
)
597 section_buffer_t sect
;
600 sect
= get_section_buffer (sectname
);
601 if (sect
->last_line
&& !sect
->last_line
->verbatim
== !verbatim
)
603 /* Lets append that line to the last one. We do this to keep
604 all lines of the same kind (i.e.verbatim or not) together in
608 lb
= sect
->last_line
;
609 n1
= strlen (lb
->line
);
610 n
= n1
+ 1 + strlen (line
) + 1;
611 lb
->line
= xrealloc (lb
->line
, n
);
612 strcpy (lb
->line
+n1
, "\n");
613 strcpy (lb
->line
+n1
+1, line
);
617 lb
= xcalloc (1, sizeof *lb
);
618 lb
->verbatim
= verbatim
;
619 lb
->line
= xstrdup (line
);
620 sect
->last_line
= lb
;
621 *sect
->lines_tail
= lb
;
622 sect
->lines_tail
= &lb
->next
;
627 /* Prepare for a new man page using the filename NAME. */
629 start_page (char *name
)
632 inf ("starting page '%s'", name
);
633 assert (!thepage
.name
);
634 thepage
.name
= xstrdup (name
);
635 thepage
.n_sections
= 0;
639 /* Write the .TH entry of the current page. Return -1 if there is a
640 problem with the page. */
646 fputs (".\\\" Created from Texinfo source by yat2m " VERSION
"\n", fp
);
648 name
= ascii_strupr (xstrdup (thepage
.name
));
649 p
= strrchr (name
, '.');
652 err ("no section name in man page '%s'", thepage
.name
);
657 fprintf (fp
, ".TH %s %s %s \"%s\" \"%s\"\n",
658 name
, p
, isodatestring (), opt_release
, opt_source
);
664 /* Process the texinfo command COMMAND (without the leading @) and
665 write output if needed to FP. REST is the remainer of the line
666 which should either point to an opening brace or to a white space.
667 The function returns the number of characters already processed
668 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
669 control the indentation of tables. */
671 proc_texi_cmd (FILE *fp
, const char *command
, const char *rest
, size_t len
,
672 int *table_level
, int *eol_action
)
675 const char *name
; /* Name of the command. */
676 int what
; /* What to do with this command. */
677 const char *lead_in
; /* String to print with a opening brace. */
678 const char *lead_out
;/* String to print with the closing brace. */
680 { "command", 0, "\\fB", "\\fR" },
681 { "code", 0, "\\fB", "\\fR" },
682 { "sc", 0, "\\fB", "\\fR" },
683 { "var", 0, "\\fI", "\\fR" },
684 { "samp", 0, "\\(aq", "\\(aq" },
685 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
686 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
689 { "option", 0, "\\fB", "\\fR" },
690 { "example", 1, ".RS 2\n.nf\n" },
691 { "smallexample", 1, ".RS 2\n.nf\n" },
695 { "xref", 0, "see: [", "]" },
696 { "pxref", 0, "see: [", "]" },
697 { "uref", 0, "(\\fB", "\\fR)" },
698 { "footnote",0, " ([", "])" },
699 { "emph", 0, "\\fI", "\\fR" },
708 { "subsection", 6, "\n.SS " },
710 { "item", 2, ".TP\n.B " },
711 { "itemx", 2, ".TP\n.B " },
714 { "bullet", 0, "* " },
718 { "quotation",1, ".RS\n\\fB" },
725 const char *lead_out
= NULL
;
728 for (i
=0; cmdtbl
[i
].name
&& strcmp (cmdtbl
[i
].name
, command
); i
++)
732 s
= cmdtbl
[i
].lead_in
;
735 lead_out
= cmdtbl
[i
].lead_out
;
736 switch (cmdtbl
[i
].what
)
738 case 1: /* Throw away the entire line. */
739 s
= memchr (rest
, '\n', len
);
740 return s
? (s
-rest
)+1 : len
;
741 case 2: /* Handle @item. */
743 case 3: /* Handle table. */
744 if (++(*table_level
) > 1)
746 /* Now throw away the entire line. */
747 s
= memchr (rest
, '\n', len
);
748 return s
? (s
-rest
)+1 : len
;
750 case 4: /* Handle end. */
751 for (s
=rest
, n
=len
; n
&& (*s
== ' ' || *s
== '\t'); s
++, n
--)
753 if (n
>= 5 && !memcmp (s
, "table", 5)
754 && (!n
|| s
[5] == ' ' || s
[5] == '\t' || s
[5] == '\n'))
756 if ((*table_level
)-- > 1)
759 else if (n
>= 7 && !memcmp (s
, "example", 7)
760 && (!n
|| s
[7] == ' ' || s
[7] == '\t' || s
[7] == '\n'))
762 fputs (".fi\n.RE\n", fp
);
764 else if (n
>= 12 && !memcmp (s
, "smallexample", 12)
765 && (!n
|| s
[12] == ' ' || s
[12] == '\t' || s
[12] == '\n'))
767 fputs (".fi\n.RE\n", fp
);
769 else if (n
>= 9 && !memcmp (s
, "quotation", 9)
770 && (!n
|| s
[9] == ' ' || s
[9] == '\t' || s
[9] == '\n'))
772 fputs ("\\fR\n.RE\n", fp
);
774 /* Now throw away the entire line. */
775 s
= memchr (rest
, '\n', len
);
776 return s
? (s
-rest
)+1 : len
;
777 case 5: /* Handle special comments. */
778 for (s
=rest
, n
=len
; n
&& (*s
== ' ' || *s
== '\t'); s
++, n
--)
780 if (n
>= 4 && !memcmp (s
, "man:", 4))
782 for (s
+=4, n
-=4; n
&& *s
!= '\n'; n
--, s
++)
786 /* Now throw away the entire line. */
787 s
= memchr (rest
, '\n', len
);
788 return s
? (s
-rest
)+1 : len
;
799 err ("opening brace for command '%s' missing", command
);
804 /* Find closing brace. */
805 for (s
=rest
+1, n
=1; *s
&& n
< len
; s
++, n
++)
810 err ("closing brace for command '%s' not found", command
);
815 size_t len
= s
- (rest
+ 1);
818 for (m
= variablelist
; m
; m
= m
->next
)
819 if (strlen (m
->name
) == len
820 &&!strncmp (m
->name
, rest
+1, len
))
823 fputs (m
->value
, fp
);
825 inf ("texinfo variable '%.*s' is not set",
838 for (m
= macrolist
; m
; m
= m
->next
)
839 if (!strcmp (m
->name
, command
))
843 proc_texi_buffer (fp
, m
->value
, strlen (m
->value
),
844 table_level
, eol_action
);
845 ignore_args
= 1; /* Parameterized macros are not yet supported. */
848 inf ("texinfo command '%s' not supported (%.*s)", command
,
849 ((s
= memchr (rest
, '\n', len
)), (s
? (s
-rest
) : len
)), rest
);
854 /* Find matching closing brace. */
855 for (s
=rest
+1, n
=1, i
=1; i
&& *s
&& n
< len
; s
++, n
++)
862 err ("closing brace for command '%s' not found", command
);
865 if (n
> 2 && !ignore_args
)
866 proc_texi_buffer (fp
, rest
+1, n
-2, table_level
, eol_action
);
872 fputs (lead_out
, fp
);
879 /* Process the string LINE with LEN bytes of Texinfo content. */
881 proc_texi_buffer (FILE *fp
, const char *line
, size_t len
,
882 int *table_level
, int *eol_action
)
890 for (s
=line
; *s
&& len
; s
++, len
--)
898 case '@': case '{': case '}':
899 putc (*s
, fp
); in_cmd
= 0;
901 case ':': /* Not ending a sentence flag. */
904 case '.': case '!': case '?': /* Ending a sentence. */
905 putc (*s
, fp
); in_cmd
= 0;
907 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
908 putc (*s
, fp
); in_cmd
= 0;
912 cmdbuf
[cmdidx
++] = *s
;
917 else if (*s
== '{' || *s
== ' ' || *s
== '\t' || *s
== '\n')
920 n
= proc_texi_cmd (fp
, cmdbuf
, s
, len
, table_level
, eol_action
);
926 else if (cmdidx
< sizeof cmdbuf
-1)
927 cmdbuf
[cmdidx
++] = *s
;
930 err ("texinfo command too long - ignored");
940 case 1: /* Create a dummy paragraph. */
941 fputs ("\n\\ \n", fp
);
957 n
= proc_texi_cmd (fp
, cmdbuf
, s
, len
, table_level
, eol_action
);
966 /* Do something with the Texinfo line LINE. */
968 parse_texi_line (FILE *fp
, const char *line
, int *table_level
)
972 /* A quick test whether there are any texinfo commands. */
973 if (!strchr (line
, '@'))
979 proc_texi_buffer (fp
, line
, strlen (line
), table_level
, &eol_action
);
984 /* Write all the lines LINES to FP. */
986 write_content (FILE *fp
, line_buffer_t lines
)
991 for (line
= lines
; line
; line
= line
->next
)
995 fputs (line
->line
, fp
);
1000 /* fputs ("TEXI---", fp); */
1001 /* fputs (line->line, fp); */
1002 /* fputs ("---\n", fp); */
1003 parse_texi_line (fp
, line
->line
, &table_level
);
1011 is_standard_section (const char *name
)
1016 for (i
=0; (s
=standard_sections
[i
]); i
++)
1017 if (!strcmp (s
, name
))
1023 /* Finish a page; that is sort the data and write it out to the file. */
1028 section_buffer_t sect
= NULL
;
1034 return; /* No page active. */
1037 inf ("finishing page '%s'", thepage
.name
);
1041 if (!strcmp (opt_select
, thepage
.name
))
1043 inf ("selected '%s'", thepage
.name
);
1048 fp
= fopen ( "/dev/null", "w" );
1050 die ("failed to open /dev/null: %s\n", strerror (errno
));
1055 inf ("writing '%s'", thepage
.name
);
1056 fp
= fopen ( thepage
.name
, "w" );
1058 die ("failed to create '%s': %s\n", thepage
.name
, strerror (errno
));
1066 for (idx
=0; (s
=standard_sections
[idx
]); idx
++)
1068 for (i
=0; i
< thepage
.n_sections
; i
++)
1070 sect
= thepage
.sections
+ i
;
1071 if (sect
->name
&& !strcmp (s
, sect
->name
))
1074 if (i
== thepage
.n_sections
)
1079 fprintf (fp
, ".SH %s\n", sect
->name
);
1080 write_content (fp
, sect
->lines
);
1081 /* Now continue with all non standard sections directly
1082 following this one. */
1083 for (i
++; i
< thepage
.n_sections
; i
++)
1085 sect
= thepage
.sections
+ i
;
1086 if (sect
->name
&& is_standard_section (sect
->name
))
1090 fprintf (fp
, ".SH %s\n", sect
->name
);
1091 write_content (fp
, sect
->lines
);
1102 free (thepage
.name
);
1103 thepage
.name
= NULL
;
1104 /* FIXME: Cleanup the content. */
1110 /* Parse one Texinfo file and create manpages according to the
1111 embedded instructions. */
1113 parse_file (const char *fname
, FILE *fp
, char **section_name
, int in_pause
)
1117 /* Fixme: The following state variables don't carry over to include
1119 int skip_to_end
= 0; /* Used to skip over menu entries. */
1120 int skip_sect_line
= 0; /* Skip after @mansect. */
1121 int item_indent
= 0; /* How far is the current @item indented. */
1123 /* Helper to define a macro. */
1124 char *macroname
= NULL
;
1125 char *macrovalue
= NULL
;
1126 size_t macrovaluesize
= 0;
1127 size_t macrovalueused
= 0;
1129 line
= xmalloc (LINESIZE
);
1130 while (fgets (line
, LINESIZE
, fp
))
1132 size_t n
= strlen (line
);
1137 if (!n
|| line
[n
-1] != '\n')
1139 err ("%s:%d: trailing linefeed missing, line too long or "
1140 "embedded Nul character", fname
, lnr
);
1145 /* Kludge to allow indentation of tables. */
1146 for (p
=line
; *p
== ' ' || *p
== '\t'; p
++)
1150 if (*p
== '@' && !strncmp (p
+1, "item", 4))
1151 item_indent
= p
- line
; /* Set a new indent level. */
1152 else if (p
- line
< item_indent
)
1153 item_indent
= 0; /* Switch off indention. */
1157 memmove (line
, line
+item_indent
, n
- item_indent
+ 1);
1165 for (p
=line
+1, n
=1; *p
&& *p
!= ' ' && *p
!= '\t'; p
++)
1167 while (*p
== ' ' || *p
== '\t')
1173 /* Take action on macro. */
1176 if (n
== 4 && !memcmp (line
, "@end", 4)
1177 && (line
[4]==' '||line
[4]=='\t'||!line
[4])
1178 && !strncmp (p
, "macro", 5)
1179 && (p
[5]==' '||p
[5]=='\t'||!p
[5]))
1182 macrovalue
[--macrovalueused
] = 0; /* Kill the last LF. */
1183 macrovalue
[macrovalueused
] = 0; /* Terminate macro. */
1184 macrovalue
= xrealloc (macrovalue
, macrovalueused
+1);
1186 set_macro (macroname
, macrovalue
);
1193 if (macrovalueused
+ strlen (line
) + 2 >= macrovaluesize
)
1195 macrovaluesize
+= strlen (line
) + 256;
1196 macrovalue
= xrealloc (macrovalue
, macrovaluesize
);
1198 strcpy (macrovalue
+macrovalueused
, line
);
1199 macrovalueused
+= strlen (line
);
1200 macrovalue
[macrovalueused
++] = '\n';
1206 if (n
>= 5 && !memcmp (line
, "@node", 5)
1207 && (line
[5]==' '||line
[5]=='\t'||!line
[5]))
1209 /* Completey ignore @node lines. */
1217 if (!strncmp (line
, "@section", 8)
1218 || !strncmp (line
, "@subsection", 11)
1219 || !strncmp (line
, "@chapheading", 12))
1223 /* We only parse lines we need and ignore the rest. There are a
1224 few macros used to control this as well as one @ifset
1225 command. Parts we know about are saved away into containers
1226 separate for each section. */
1228 /* First process ifset/ifclear commands. */
1231 if (n
== 6 && !memcmp (line
, "@ifset", 6)
1232 && (line
[6]==' '||line
[6]=='\t'))
1234 for (p
=line
+7; *p
== ' ' || *p
== '\t'; p
++)
1238 err ("%s:%d: name missing after \"@ifset\"", fname
, lnr
);
1241 for (pend
=p
; *pend
&& *pend
!= ' ' && *pend
!= '\t'; pend
++)
1243 *pend
= 0; /* Ignore rest of the line. */
1244 push_condition (p
, 1, fname
, lnr
);
1247 else if (n
== 8 && !memcmp (line
, "@ifclear", 8)
1248 && (line
[8]==' '||line
[8]=='\t'))
1250 for (p
=line
+9; *p
== ' ' || *p
== '\t'; p
++)
1254 err ("%s:%d: name missing after \"@ifsclear\"", fname
, lnr
);
1257 for (pend
=p
; *pend
&& *pend
!= ' ' && *pend
!= '\t'; pend
++)
1259 *pend
= 0; /* Ignore rest of the line. */
1260 push_condition (p
, 0, fname
, lnr
);
1263 else if (n
== 4 && !memcmp (line
, "@end", 4)
1264 && (line
[4]==' '||line
[4]=='\t')
1265 && !strncmp (p
, "ifset", 5)
1266 && (p
[5]==' '||p
[5]=='\t'||!p
[5]))
1268 pop_condition (1, fname
, lnr
);
1271 else if (n
== 4 && !memcmp (line
, "@end", 4)
1272 && (line
[4]==' '||line
[4]=='\t')
1273 && !strncmp (p
, "ifclear", 7)
1274 && (p
[7]==' '||p
[7]=='\t'||!p
[7]))
1276 pop_condition (0, fname
, lnr
);
1281 /* Take action on ifset/ifclear. */
1282 if (!cond_is_active
)
1285 /* Process commands. */
1289 && n
== 4 && !memcmp (line
, "@end", 4)
1290 && (line
[4]==' '||line
[4]=='\t'||!line
[4]))
1294 else if (cond_in_verbatim
)
1298 else if (n
== 6 && !memcmp (line
, "@macro", 6))
1300 macroname
= xstrdup (p
);
1301 macrovalue
= xmalloc ((macrovaluesize
= 1024));
1304 else if (n
== 4 && !memcmp (line
, "@set", 4))
1308 else if (n
== 8 && !memcmp (line
, "@manpage", 8))
1310 free (*section_name
);
1311 *section_name
= NULL
;
1316 else if (n
== 8 && !memcmp (line
, "@mansect", 8))
1319 err ("%s:%d: section outside of a man page", fname
, lnr
);
1322 free (*section_name
);
1323 *section_name
= ascii_strupr (xstrdup (p
));
1328 else if (n
== 9 && !memcmp (line
, "@manpause", 9))
1331 err ("%s:%d: pausing outside of a man section", fname
, lnr
);
1333 err ("%s:%d: already pausing", fname
, lnr
);
1337 else if (n
== 8 && !memcmp (line
, "@mancont", 8))
1340 err ("%s:%d: continue outside of a man section", fname
, lnr
);
1342 err ("%s:%d: continue while not pausing", fname
, lnr
);
1346 else if (n
== 5 && !memcmp (line
, "@menu", 5)
1347 && (line
[5]==' '||line
[5]=='\t'||!line
[5]))
1351 else if (n
== 8 && !memcmp (line
, "@include", 8)
1352 && (line
[8]==' '||line
[8]=='\t'||!line
[8]))
1354 char *incname
= xstrdup (p
);
1355 FILE *incfp
= fopen (incname
, "r");
1357 if (!incfp
&& opt_include
&& *opt_include
&& *p
!= '/')
1360 incname
= xmalloc (strlen (opt_include
) + 1
1362 strcpy (incname
, opt_include
);
1363 if ( incname
[strlen (incname
)-1] != '/' )
1364 strcat (incname
, "/");
1365 strcat (incname
, p
);
1366 incfp
= fopen (incname
, "r");
1370 err ("can't open include file '%s': %s",
1371 incname
, strerror (errno
));
1374 parse_file (incname
, incfp
, section_name
, in_pause
);
1379 else if (n
== 4 && !memcmp (line
, "@bye", 4)
1380 && (line
[4]==' '||line
[4]=='\t'||!line
[4]))
1384 else if (!skip_to_end
)
1387 else if (!skip_to_end
)
1390 if (got_line
&& cond_in_verbatim
)
1391 add_content (*section_name
, line
, 1);
1392 else if (got_line
&& thepage
.name
&& *section_name
&& !in_pause
)
1393 add_content (*section_name
, line
, 0);
1397 err ("%s:%d: read error: %s", fname
, lnr
, strerror (errno
));
1405 top_parse_file (const char *fname
, FILE *fp
)
1407 char *section_name
= NULL
; /* Name of the current section or NULL
1408 if not in a section. */
1413 macro_t next
= macrolist
->next
;
1414 free (macrolist
->value
);
1418 while (variablelist
)
1420 macro_t next
= variablelist
->next
;
1421 free (variablelist
->value
);
1422 free (variablelist
);
1423 variablelist
= next
;
1425 for (m
=predefinedmacrolist
; m
; m
= m
->next
)
1426 set_macro (m
->name
, xstrdup ("1"));
1428 cond_in_verbatim
= 0;
1430 parse_file (fname
, fp
, §ion_name
, 0);
1431 free (section_name
);
1437 main (int argc
, char **argv
)
1444 /* Define default macros. The trick is that these macros are not
1445 defined when using the actual texinfo renderer. */
1446 add_predefined_macro ("isman");
1447 add_predefined_macro ("manverb");
1449 /* Option parsing. */
1454 while (argc
&& last_argc
!= argc
)
1457 if (!strcmp (*argv
, "--"))
1462 else if (!strcmp (*argv
, "--help"))
1465 "Usage: " PGM
" [OPTION] [FILE]\n"
1466 "Extract man pages from a Texinfo source.\n\n"
1467 " --source NAME use NAME as source field\n"
1468 " --release STRING use STRING as the release field\n"
1469 " --store write output using @manpage name\n"
1470 " --select NAME only output pages with @manpage NAME\n"
1471 " --verbose enable extra informational output\n"
1472 " --debug enable additional debug output\n"
1473 " --help display this help and exit\n"
1474 " -I DIR also search in include DIR\n"
1475 " -D gpgone the only useable define\n\n"
1476 "With no FILE, or when FILE is -, read standard input.\n\n"
1477 "Report bugs to <bugs@g10code.com>.");
1480 else if (!strcmp (*argv
, "--version"))
1482 puts (PGM
" " VERSION
"\n"
1483 "Copyright (C) 2005 g10 Code GmbH\n"
1484 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1485 "This is free software, and you are welcome to redistribute it\n"
1486 "under certain conditions. See the file COPYING for details.");
1489 else if (!strcmp (*argv
, "--verbose"))
1494 else if (!strcmp (*argv
, "--quiet"))
1499 else if (!strcmp (*argv
, "--debug"))
1501 verbose
= debug
= 1;
1504 else if (!strcmp (*argv
, "--source"))
1513 else if (!strcmp (*argv
, "--release"))
1518 opt_release
= *argv
;
1522 else if (!strcmp (*argv
, "--store"))
1527 else if (!strcmp (*argv
, "--select"))
1532 opt_select
= strrchr (*argv
, '/');
1540 else if (!strcmp (*argv
, "-I"))
1545 opt_include
= *argv
;
1549 else if (!strcmp (*argv
, "-D"))
1554 add_predefined_macro (*argv
);
1561 die ("usage: " PGM
" [OPTION] [FILE] (try --help for more information)\n");
1563 /* Start processing. */
1564 if (argc
&& strcmp (*argv
, "-"))
1566 FILE *fp
= fopen (*argv
, "rb");
1568 die ("%s:0: can't open file: %s", *argv
, strerror (errno
));
1569 top_parse_file (*argv
, fp
);
1573 top_parse_file ("-", stdin
);
1581 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"