1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005, 2013, 2015, 2016, 2017 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/>.
19 /**********************************************
20 * Note: The canonical source of this tool **
21 * is part of libgpg-error and it **
22 * installs yat2m on the build system. **
23 **********************************************/
26 This is a simple texinfo to man page converter. It needs some
27 special markup in th e texinfo and tries best to get a create man
28 page. It has been designed for the GnuPG man pages and thus only
29 a few texinfo commands are supported.
31 To use this you need to add the following macros into your texinfo
43 They are used by yat2m to select parts of the Texinfo which should
44 go into the man page. These macros need to be used without leading
45 left space. Processing starts after a "manpage" macro has been
46 seen. "mansect" identifies the section and yat2m make sure to
47 emit the sections in the proper order. Note that @mansect skips
48 the next input line if that line begins with @section, @subsection or
51 To insert verbatim troff markup, the following texinfo code may be
58 alternatively a special comment may be used:
60 @c man:.B whatever you want
62 This is useful in case you need just one line. If you want to
63 include parts only in the man page but keep the texinfo
64 translation you may use:
67 stuff to be rendered only on man pages
70 or to exclude stuff from man pages:
73 stuff not to be rendered on man pages
76 the keyword @section is ignored, however @subsection gets rendered
77 as ".SS". @menu is completely skipped. Several man pages may be
78 extracted from one file, either using the --store or the --select
81 If you want to indent tables in the source use this style:
91 Don't change the indentation within a table and keep the same
92 number of white space at the start of the line. yat2m simply
93 detects the number of white spaces in front of an @item and remove
94 this number of spaces from all following lines until a new @item
95 is found or there are less spaces than for the last @item.
97 Note that @* does only work correctly if used at the end of an
114 # define MY_GCC_VERSION (__GNUC__ * 10000 \
115 + __GNUC_MINOR__ * 100 \
116 + __GNUC_PATCHLEVEL__)
118 # define MY_GCC_VERSION 0
121 #if MY_GCC_VERSION >= 20500
122 # define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
123 # define ATTR_NR_PRINTF(f, a) __attribute__ ((__noreturn__, format(printf,f,a)))
125 # define ATTR_PRINTF(f, a)
126 # define ATTR_NR_PRINTF(f, a)
128 #if MY_GCC_VERSION >= 30200
129 # define ATTR_MALLOC __attribute__ ((__malloc__))
137 #define VERSION "1.0"
139 /* The maximum length of a line including the linefeed and one extra
141 #define LINESIZE 1024
143 /* Number of allowed condition nestings. */
144 #define MAX_CONDITION_NESTING 10
150 static const char *opt_source;
151 static const char *opt_release;
152 static const char *opt_date;
153 static const char *opt_select;
154 static const char *opt_include;
155 static int opt_store;
157 /* Flag to keep track whether any error occurred. */
158 static int any_error;
161 /* Object to keep macro definitions. */
164 struct macro_s *next;
165 char *value; /* Malloced value. */
168 typedef struct macro_s *macro_t;
170 /* List of all defined macros. */
171 static macro_t macrolist;
173 /* List of variables set by @set. */
174 static macro_t variablelist;
176 /* List of global macro names. The value part is not used. */
177 static macro_t predefinedmacrolist;
179 /* Object to keep track of @isset and @ifclear. */
182 int manverb; /* "manverb" needs special treatment. */
183 int isset; /* This is an @isset condition. */
184 char name[1]; /* Name of the condition macro. */
186 typedef struct condition_s *condition_t;
188 /* The stack used to evaluate conditions. And the current states. */
189 static condition_t condition_stack[MAX_CONDITION_NESTING];
190 static int condition_stack_idx;
191 static int cond_is_active; /* State of ifset/ifclear */
192 static int cond_in_verbatim; /* State of "manverb". */
195 /* Object to store one line of content. */
198 struct line_buffer_s *next;
199 int verbatim; /* True if LINE contains verbatim data. The default
200 is Texinfo source. */
203 typedef struct line_buffer_s *line_buffer_t;
206 /* Object to collect the data of a section. */
207 struct section_buffer_s
209 char *name; /* Malloced name of the section. This may be
210 NULL to indicate this slot is not used. */
211 line_buffer_t lines; /* Linked list with the lines of the section. */
212 line_buffer_t *lines_tail; /* Helper for faster appending to the
214 line_buffer_t last_line; /* Points to the last line appended. */
216 typedef struct section_buffer_s *section_buffer_t;
218 /* Variable to keep info about the current page together. */
221 /* Filename of the current page or NULL if no page is active. Malloced. */
224 /* Number of allocated elements in SECTIONS below. */
226 /* Array with the data of the sections. */
227 section_buffer_t sections;
232 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
234 static const char * const standard_sections[] =
235 { "NAME", "SYNOPSIS", "DESCRIPTION",
236 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
237 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
238 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
239 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
242 /*-- Local prototypes. --*/
243 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
244 int *table_level, int *eol_action);
246 static void die (const char *format, ...) ATTR_NR_PRINTF(1,2);
247 static void err (const char *format, ...) ATTR_PRINTF(1,2);
248 static void inf (const char *format, ...) ATTR_PRINTF(1,2);
249 static void *xmalloc (size_t n) ATTR_MALLOC;
250 static void *xcalloc (size_t n, size_t m) ATTR_MALLOC;
256 /* Print diagnostic message and exit with failure. */
258 die (const char *format, ...)
263 fprintf (stderr, "%s: ", PGM);
265 va_start (arg_ptr, format);
266 vfprintf (stderr, format, arg_ptr);
274 /* Print diagnostic message. */
276 err (const char *format, ...)
281 if (strncmp (format, "%s:%d:", 6))
282 fprintf (stderr, "%s: ", PGM);
284 va_start (arg_ptr, format);
285 vfprintf (stderr, format, arg_ptr);
291 /* Print diagnostic message. */
293 inf (const char *format, ...)
298 fprintf (stderr, "%s: ", PGM);
300 va_start (arg_ptr, format);
301 vfprintf (stderr, format, arg_ptr);
310 void *p = malloc (n);
312 die ("out of core: %s", strerror (errno));
317 xcalloc (size_t n, size_t m)
319 void *p = calloc (n, m);
321 die ("out of core: %s", strerror (errno));
326 xrealloc (void *old, size_t n)
328 void *p = realloc (old, n);
330 die ("out of core: %s", strerror (errno));
335 xstrdup (const char *string)
337 void *p = malloc (strlen (string)+1);
339 die ("out of core: %s", strerror (errno));
345 /* Uppercase the ascii characters in STRING. */
347 ascii_strupr (char *string)
351 for (p = string; *p; p++)
358 /* Return the current date as an ISO string. */
362 static char buffer[11+5];
366 if (opt_date && *opt_date)
367 atime = strtoul (opt_date, NULL, 10);
371 strcpy (buffer, "????" "-??" "-??");
374 tp = gmtime (&atime);
375 sprintf (buffer,"%04d-%02d-%02d",
376 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
382 /* Add NAME to the list of predefined macros which are global for all
385 add_predefined_macro (const char *name)
389 for (m=predefinedmacrolist; m; m = m->next)
390 if (!strcmp (m->name, name))
394 m = xcalloc (1, sizeof *m + strlen (name));
395 strcpy (m->name, name);
396 m->next = predefinedmacrolist;
397 predefinedmacrolist = m;
402 /* Create or update a macro with name MACRONAME and set its values TO
403 MACROVALUE. Note that ownership of the macro value is transferred
406 set_macro (const char *macroname, char *macrovalue)
410 for (m=macrolist; m; m = m->next)
411 if (!strcmp (m->name, macroname))
417 m = xcalloc (1, sizeof *m + strlen (macroname));
418 strcpy (m->name, macroname);
422 m->value = macrovalue;
427 /* Create or update a variable with name and value given in NAMEANDVALUE. */
429 set_variable (char *nameandvalue)
435 for (p = nameandvalue; *p && *p != ' ' && *p != '\t'; p++)
442 while (*p == ' ' || *p == '\t')
447 for (m=variablelist; m; m = m->next)
448 if (!strcmp (m->name, nameandvalue))
454 m = xcalloc (1, sizeof *m + strlen (nameandvalue));
455 strcpy (m->name, nameandvalue);
456 m->next = variablelist;
459 m->value = xstrdup (value);
463 /* Return true if the macro or variable NAME is set, i.e. not the
464 empty string and not evaluating to 0. */
466 macro_set_p (const char *name)
470 for (m = macrolist; m ; m = m->next)
471 if (!strcmp (m->name, name))
474 for (m = variablelist; m ; m = m->next)
475 if (!strcmp (m->name, name))
477 if (!m || !m->value || !*m->value)
479 if ((*m->value & 0x80) || !isdigit (*m->value))
480 return 1; /* Not a digit but some other string. */
481 return !!atoi (m->value);
485 /* Evaluate the current conditions. */
487 evaluate_conditions (const char *fname, int lnr)
491 /* for (i=0; i < condition_stack_idx; i++) */
492 /* inf ("%s:%d: stack[%d] %s %s %c", */
493 /* fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
494 /* condition_stack[i]->name, */
495 /* (macro_set_p (condition_stack[i]->name) */
496 /* ^ !condition_stack[i]->isset)? 't':'f'); */
499 cond_in_verbatim = 0;
500 if (condition_stack_idx)
502 for (i=0; i < condition_stack_idx; i++)
504 if (condition_stack[i]->manverb)
505 cond_in_verbatim = (macro_set_p (condition_stack[i]->name)
506 ^ !condition_stack[i]->isset);
507 else if (!(macro_set_p (condition_stack[i]->name)
508 ^ !condition_stack[i]->isset))
516 /* inf ("%s:%d: active=%d verbatim=%d", */
517 /* fname, lnr, cond_is_active, cond_in_verbatim); */
521 /* Push a condition with condition macro NAME onto the stack. If
522 ISSET is true, a @isset condition is pushed. */
524 push_condition (const char *name, int isset, const char *fname, int lnr)
529 if (condition_stack_idx >= MAX_CONDITION_NESTING)
531 err ("%s:%d: condition nested too deep", fname, lnr);
535 if (!strcmp (name, "manverb"))
539 err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname, lnr);
545 cond = xcalloc (1, sizeof *cond + strlen (name));
546 cond->manverb = manverb;
548 strcpy (cond->name, name);
550 condition_stack[condition_stack_idx++] = cond;
551 evaluate_conditions (fname, lnr);
555 /* Remove the last condition from the stack. ISSET is used for error
558 pop_condition (int isset, const char *fname, int lnr)
560 if (!condition_stack_idx)
562 err ("%s:%d: unbalanced \"@end %s\"",
563 fname, lnr, isset?"isset":"isclear");
566 condition_stack_idx--;
567 free (condition_stack[condition_stack_idx]);
568 condition_stack[condition_stack_idx] = NULL;
569 evaluate_conditions (fname, lnr);
574 /* Return a section buffer for the section NAME. Allocate a new buffer
575 if this is a new section. Keep track of the sections in THEPAGE.
576 This function may reallocate the section array in THEPAGE. */
577 static section_buffer_t
578 get_section_buffer (const char *name)
581 section_buffer_t sect;
583 /* If there is no section we put everything into the required NAME
584 section. Given that this is the first one listed it is likely
585 that error are easily visible. */
589 for (i=0; i < thepage.n_sections; i++)
591 sect = thepage.sections + i;
592 if (sect->name && !strcmp (name, sect->name))
595 for (i=0; i < thepage.n_sections; i++)
596 if (!thepage.sections[i].name)
598 if (thepage.n_sections && i < thepage.n_sections)
599 sect = thepage.sections + i;
602 /* We need to allocate or reallocate the section array. */
603 size_t old_n = thepage.n_sections;
607 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
610 thepage.sections = xrealloc (thepage.sections,
612 * sizeof *thepage.sections));
613 memset (thepage.sections + old_n, 0,
614 new_n * sizeof *thepage.sections);
616 thepage.n_sections += new_n;
618 /* Setup the tail pointers. */
619 for (i=old_n; i < thepage.n_sections; i++)
621 sect = thepage.sections + i;
622 sect->lines_tail = §->lines;
624 sect = thepage.sections + old_n;
627 /* Store the name. */
628 assert (!sect->name);
629 sect->name = xstrdup (name);
635 /* Add the content of LINE to the section named SECTNAME. */
637 add_content (const char *sectname, char *line, int verbatim)
639 section_buffer_t sect;
642 sect = get_section_buffer (sectname);
643 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
645 /* Lets append that line to the last one. We do this to keep
646 all lines of the same kind (i.e.verbatim or not) together in
650 lb = sect->last_line;
651 n1 = strlen (lb->line);
652 n = n1 + 1 + strlen (line) + 1;
653 lb->line = xrealloc (lb->line, n);
654 strcpy (lb->line+n1, "\n");
655 strcpy (lb->line+n1+1, line);
659 lb = xcalloc (1, sizeof *lb);
660 lb->verbatim = verbatim;
661 lb->line = xstrdup (line);
662 sect->last_line = lb;
663 *sect->lines_tail = lb;
664 sect->lines_tail = &lb->next;
669 /* Prepare for a new man page using the filename NAME. */
671 start_page (char *name)
674 inf ("starting page '%s'", name);
675 assert (!thepage.name);
676 thepage.name = xstrdup (name);
677 thepage.n_sections = 0;
681 /* Write the .TH entry of the current page. Return -1 if there is a
682 problem with the page. */
688 fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
690 name = ascii_strupr (xstrdup (thepage.name));
691 p = strrchr (name, '.');
694 err ("no section name in man page '%s'", thepage.name);
699 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
700 name, p, isodatestring (), opt_release, opt_source);
706 /* Process the texinfo command COMMAND (without the leading @) and
707 write output if needed to FP. REST is the remainder of the line
708 which should either point to an opening brace or to a white space.
709 The function returns the number of characters already processed
710 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
711 control the indentation of tables. */
713 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
714 int *table_level, int *eol_action)
717 const char *name; /* Name of the command. */
718 int what; /* What to do with this command. */
719 const char *lead_in; /* String to print with a opening brace. */
720 const char *lead_out;/* String to print with the closing brace. */
722 { "command", 0, "\\fB", "\\fR" },
723 { "code", 0, "\\fB", "\\fR" },
724 { "url", 0, "\\fB", "\\fR" },
725 { "sc", 0, "\\fB", "\\fR" },
726 { "var", 0, "\\fI", "\\fR" },
727 { "samp", 0, "\\(oq", "\\(cq" },
728 { "kbd", 0, "\\(oq", "\\(cq" },
729 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
730 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
733 { "option", 0, "\\fB", "\\fR" },
734 { "example", 1, ".RS 2\n.nf\n" },
735 { "smallexample", 1, ".RS 2\n.nf\n" },
739 { "ref", 0, "[", "]" },
740 { "xref", 0, "See: [", "]" },
741 { "pxref", 0, "see: [", "]" },
742 { "uref", 0, "(\\fB", "\\fR)" },
743 { "footnote",0, " ([", "])" },
744 { "emph", 0, "\\fI", "\\fR" },
754 { "subsection", 6, "\n.SS " },
756 { "item", 2, ".TP\n.B " },
757 { "itemx", 2, ".TQ\n.B " },
760 { "bullet", 0, "* " },
764 { "quotation",1, ".RS\n\\fB" },
771 const char *lead_out = NULL;
774 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
778 s = cmdtbl[i].lead_in;
781 lead_out = cmdtbl[i].lead_out;
782 switch (cmdtbl[i].what)
784 case 1: /* Throw away the entire line. */
785 s = memchr (rest, '\n', len);
786 return s? (s-rest)+1 : len;
787 case 2: /* Handle @item. */
789 case 3: /* Handle table. */
790 if (++(*table_level) > 1)
792 /* Now throw away the entire line. */
793 s = memchr (rest, '\n', len);
794 return s? (s-rest)+1 : len;
796 case 4: /* Handle end. */
797 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
799 if (n >= 5 && !memcmp (s, "table", 5)
800 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
802 if ((*table_level)-- > 1)
807 else if (n >= 7 && !memcmp (s, "example", 7)
808 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
810 fputs (".fi\n.RE\n", fp);
812 else if (n >= 12 && !memcmp (s, "smallexample", 12)
813 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
815 fputs (".fi\n.RE\n", fp);
817 else if (n >= 9 && !memcmp (s, "quotation", 9)
818 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
820 fputs ("\\fR\n.RE\n", fp);
822 /* Now throw away the entire line. */
823 s = memchr (rest, '\n', len);
824 return s? (s-rest)+1 : len;
825 case 5: /* Handle special comments. */
826 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
828 if (n >= 4 && !memcmp (s, "man:", 4))
830 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
834 /* Now throw away the entire line. */
835 s = memchr (rest, '\n', len);
836 return s? (s-rest)+1 : len;
847 err ("opening brace for command '%s' missing", command);
852 /* Find closing brace. */
853 for (s=rest+1, n=1; *s && n < len; s++, n++)
858 err ("closing brace for command '%s' not found", command);
863 size_t len = s - (rest + 1);
866 for (m = variablelist; m; m = m->next)
867 if (strlen (m->name) == len
868 &&!strncmp (m->name, rest+1, len))
871 fputs (m->value, fp);
873 inf ("texinfo variable '%.*s' is not set",
886 for (m = macrolist; m ; m = m->next)
887 if (!strcmp (m->name, command))
891 proc_texi_buffer (fp, m->value, strlen (m->value),
892 table_level, eol_action);
893 ignore_args = 1; /* Parameterized macros are not yet supported. */
896 inf ("texinfo command '%s' not supported (%.*s)", command,
897 (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
902 /* Find matching closing brace. */
903 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
910 err ("closing brace for command '%s' not found", command);
913 if (n > 2 && !ignore_args)
914 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
920 fputs (lead_out, fp);
927 /* Process the string LINE with LEN bytes of Texinfo content. */
929 proc_texi_buffer (FILE *fp, const char *line, size_t len,
930 int *table_level, int *eol_action)
938 for (s=line; *s && len; s++, len--)
946 case '@': case '{': case '}':
947 putc (*s, fp); in_cmd = 0;
949 case ':': /* Not ending a sentence flag. */
952 case '.': case '!': case '?': /* Ending a sentence. */
953 putc (*s, fp); in_cmd = 0;
955 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
956 putc (*s, fp); in_cmd = 0;
960 cmdbuf[cmdidx++] = *s;
965 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
968 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
974 else if (cmdidx < sizeof cmdbuf -1)
975 cmdbuf[cmdidx++] = *s;
978 err ("texinfo command too long - ignored");
988 case 1: /* Create a dummy paragraph. */
989 fputs ("\n\\ \n", fp);
1005 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
1009 /* in_cmd = 0; -- doc only */
1014 /* Do something with the Texinfo line LINE. */
1016 parse_texi_line (FILE *fp, const char *line, int *table_level)
1020 /* A quick test whether there are any texinfo commands. */
1021 if (!strchr (line, '@'))
1027 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
1032 /* Write all the lines LINES to FP. */
1034 write_content (FILE *fp, line_buffer_t lines)
1037 int table_level = 0;
1039 for (line = lines; line; line = line->next)
1043 fputs (line->line, fp);
1048 /* fputs ("TEXI---", fp); */
1049 /* fputs (line->line, fp); */
1050 /* fputs ("---\n", fp); */
1051 parse_texi_line (fp, line->line, &table_level);
1059 is_standard_section (const char *name)
1064 for (i=0; (s=standard_sections[i]); i++)
1065 if (!strcmp (s, name))
1071 /* Finish a page; that is sort the data and write it out to the file. */
1076 section_buffer_t sect = NULL;
1082 return; /* No page active. */
1085 inf ("finishing page '%s'", thepage.name);
1089 if (!strcmp (opt_select, thepage.name))
1091 inf ("selected '%s'", thepage.name );
1096 fp = fopen ( "/dev/null", "w" );
1098 die ("failed to open /dev/null: %s\n", strerror (errno));
1103 inf ("writing '%s'", thepage.name );
1104 fp = fopen ( thepage.name, "w" );
1106 die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
1114 for (idx=0; (s=standard_sections[idx]); idx++)
1116 for (i=0; i < thepage.n_sections; i++)
1118 sect = thepage.sections + i;
1119 if (sect->name && !strcmp (s, sect->name))
1122 if (i == thepage.n_sections)
1127 fprintf (fp, ".SH %s\n", sect->name);
1128 write_content (fp, sect->lines);
1129 /* Now continue with all non standard sections directly
1130 following this one. */
1131 for (i++; i < thepage.n_sections; i++)
1133 sect = thepage.sections + i;
1134 if (sect->name && is_standard_section (sect->name))
1138 fprintf (fp, ".SH %s\n", sect->name);
1139 write_content (fp, sect->lines);
1150 free (thepage.name);
1151 thepage.name = NULL;
1152 /* FIXME: Cleanup the content. */
1158 /* Parse one Texinfo file and create manpages according to the
1159 embedded instructions. */
1161 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
1165 /* Fixme: The following state variables don't carry over to include
1167 int skip_to_end = 0; /* Used to skip over menu entries. */
1168 int skip_sect_line = 0; /* Skip after @mansect. */
1169 int item_indent = 0; /* How far is the current @item indented. */
1171 /* Helper to define a macro. */
1172 char *macroname = NULL;
1173 char *macrovalue = NULL;
1174 size_t macrovaluesize = 0;
1175 size_t macrovalueused = 0;
1177 line = xmalloc (LINESIZE);
1178 while (fgets (line, LINESIZE, fp))
1180 size_t n = strlen (line);
1185 if (!n || line[n-1] != '\n')
1187 err ("%s:%d: trailing linefeed missing, line too long or "
1188 "embedded Nul character", fname, lnr);
1193 /* Kludge to allow indentation of tables. */
1194 for (p=line; *p == ' ' || *p == '\t'; p++)
1198 if (*p == '@' && !strncmp (p+1, "item", 4))
1199 item_indent = p - line; /* Set a new indent level. */
1200 else if (p - line < item_indent)
1201 item_indent = 0; /* Switch off indentation. */
1205 memmove (line, line+item_indent, n - item_indent + 1);
1213 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
1215 while (*p == ' ' || *p == '\t')
1221 /* Take action on macro. */
1224 if (n == 4 && !memcmp (line, "@end", 4)
1225 && (line[4]==' '||line[4]=='\t'||!line[4])
1226 && !strncmp (p, "macro", 5)
1227 && (p[5]==' '||p[5]=='\t'||!p[5]))
1230 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
1231 macrovalue[macrovalueused] = 0; /* Terminate macro. */
1232 macrovalue = xrealloc (macrovalue, macrovalueused+1);
1234 set_macro (macroname, macrovalue);
1241 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
1243 macrovaluesize += strlen (line) + 256;
1244 macrovalue = xrealloc (macrovalue, macrovaluesize);
1246 strcpy (macrovalue+macrovalueused, line);
1247 macrovalueused += strlen (line);
1248 macrovalue[macrovalueused++] = '\n';
1254 if (n >= 5 && !memcmp (line, "@node", 5)
1255 && (line[5]==' '||line[5]=='\t'||!line[5]))
1257 /* Completey ignore @node lines. */
1265 if (!strncmp (line, "@section", 8)
1266 || !strncmp (line, "@subsection", 11)
1267 || !strncmp (line, "@chapheading", 12))
1271 /* We only parse lines we need and ignore the rest. There are a
1272 few macros used to control this as well as one @ifset
1273 command. Parts we know about are saved away into containers
1274 separate for each section. */
1276 /* First process ifset/ifclear commands. */
1279 if (n == 6 && !memcmp (line, "@ifset", 6)
1280 && (line[6]==' '||line[6]=='\t'))
1282 for (p=line+7; *p == ' ' || *p == '\t'; p++)
1286 err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
1289 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1291 *pend = 0; /* Ignore rest of the line. */
1292 push_condition (p, 1, fname, lnr);
1295 else if (n == 8 && !memcmp (line, "@ifclear", 8)
1296 && (line[8]==' '||line[8]=='\t'))
1298 for (p=line+9; *p == ' ' || *p == '\t'; p++)
1302 err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
1305 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1307 *pend = 0; /* Ignore rest of the line. */
1308 push_condition (p, 0, fname, lnr);
1311 else if (n == 4 && !memcmp (line, "@end", 4)
1312 && (line[4]==' '||line[4]=='\t')
1313 && !strncmp (p, "ifset", 5)
1314 && (p[5]==' '||p[5]=='\t'||!p[5]))
1316 pop_condition (1, fname, lnr);
1319 else if (n == 4 && !memcmp (line, "@end", 4)
1320 && (line[4]==' '||line[4]=='\t')
1321 && !strncmp (p, "ifclear", 7)
1322 && (p[7]==' '||p[7]=='\t'||!p[7]))
1324 pop_condition (0, fname, lnr);
1329 /* Take action on ifset/ifclear. */
1330 if (!cond_is_active)
1333 /* Process commands. */
1337 && n == 4 && !memcmp (line, "@end", 4)
1338 && (line[4]==' '||line[4]=='\t'||!line[4]))
1342 else if (cond_in_verbatim)
1346 else if (n == 6 && !memcmp (line, "@macro", 6))
1348 macroname = xstrdup (p);
1349 macrovalue = xmalloc ((macrovaluesize = 1024));
1352 else if (n == 4 && !memcmp (line, "@set", 4))
1356 else if (n == 8 && !memcmp (line, "@manpage", 8))
1358 free (*section_name);
1359 *section_name = NULL;
1364 else if (n == 8 && !memcmp (line, "@mansect", 8))
1367 err ("%s:%d: section outside of a man page", fname, lnr);
1370 free (*section_name);
1371 *section_name = ascii_strupr (xstrdup (p));
1376 else if (n == 9 && !memcmp (line, "@manpause", 9))
1379 err ("%s:%d: pausing outside of a man section", fname, lnr);
1381 err ("%s:%d: already pausing", fname, lnr);
1385 else if (n == 8 && !memcmp (line, "@mancont", 8))
1388 err ("%s:%d: continue outside of a man section", fname, lnr);
1390 err ("%s:%d: continue while not pausing", fname, lnr);
1394 else if (n == 5 && !memcmp (line, "@menu", 5)
1395 && (line[5]==' '||line[5]=='\t'||!line[5]))
1399 else if (n == 8 && !memcmp (line, "@include", 8)
1400 && (line[8]==' '||line[8]=='\t'||!line[8]))
1402 char *incname = xstrdup (p);
1403 FILE *incfp = fopen (incname, "r");
1405 if (!incfp && opt_include && *opt_include && *p != '/')
1408 incname = xmalloc (strlen (opt_include) + 1
1410 strcpy (incname, opt_include);
1411 if ( incname[strlen (incname)-1] != '/' )
1412 strcat (incname, "/");
1413 strcat (incname, p);
1414 incfp = fopen (incname, "r");
1418 err ("can't open include file '%s': %s",
1419 incname, strerror (errno));
1422 parse_file (incname, incfp, section_name, in_pause);
1427 else if (n == 4 && !memcmp (line, "@bye", 4)
1428 && (line[4]==' '||line[4]=='\t'||!line[4]))
1432 else if (!skip_to_end)
1435 else if (!skip_to_end)
1438 if (got_line && cond_in_verbatim)
1439 add_content (*section_name, line, 1);
1440 else if (got_line && thepage.name && *section_name && !in_pause)
1441 add_content (*section_name, line, 0);
1445 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1453 top_parse_file (const char *fname, FILE *fp)
1455 char *section_name = NULL; /* Name of the current section or NULL
1456 if not in a section. */
1461 macro_t next = macrolist->next;
1462 free (macrolist->value);
1466 while (variablelist)
1468 macro_t next = variablelist->next;
1469 free (variablelist->value);
1470 free (variablelist);
1471 variablelist = next;
1473 for (m=predefinedmacrolist; m; m = m->next)
1474 set_macro (m->name, xstrdup ("1"));
1476 cond_in_verbatim = 0;
1478 parse_file (fname, fp, §ion_name, 0);
1479 free (section_name);
1485 main (int argc, char **argv)
1493 /* Define default macros. The trick is that these macros are not
1494 defined when using the actual texinfo renderer. */
1495 add_predefined_macro ("isman");
1496 add_predefined_macro ("manverb");
1498 /* Option parsing. */
1503 while (argc && last_argc != argc )
1506 if (!strcmp (*argv, "--"))
1511 else if (!strcmp (*argv, "--help"))
1514 "Usage: " PGM " [OPTION] [FILE]\n"
1515 "Extract man pages from a Texinfo source.\n\n"
1516 " --source NAME use NAME as source field\n"
1517 " --release STRING use STRING as the release field\n"
1518 " --date EPOCH use EPOCH as publication date\n"
1519 " --store write output using @manpage name\n"
1520 " --select NAME only output pages with @manpage NAME\n"
1521 " --verbose enable extra informational output\n"
1522 " --debug enable additional debug output\n"
1523 " --help display this help and exit\n"
1524 " -I DIR also search in include DIR\n"
1525 " -D gpgone the only usable define\n\n"
1526 "With no FILE, or when FILE is -, read standard input.\n\n"
1527 "Report bugs to <bugs@g10code.com>.");
1530 else if (!strcmp (*argv, "--version"))
1532 puts (PGM " " VERSION "\n"
1533 "Copyright (C) 2005 g10 Code GmbH\n"
1534 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1535 "This is free software, and you are welcome to redistribute it\n"
1536 "under certain conditions. See the file COPYING for details.");
1539 else if (!strcmp (*argv, "--verbose"))
1544 else if (!strcmp (*argv, "--quiet"))
1549 else if (!strcmp (*argv, "--debug"))
1551 verbose = debug = 1;
1554 else if (!strcmp (*argv, "--source"))
1563 else if (!strcmp (*argv, "--release"))
1568 opt_release = *argv;
1572 else if (!strcmp (*argv, "--date"))
1581 else if (!strcmp (*argv, "--store"))
1586 else if (!strcmp (*argv, "--select"))
1591 opt_select = strrchr (*argv, '/');
1599 else if (!strcmp (*argv, "-I"))
1604 opt_include = *argv;
1608 else if (!strcmp (*argv, "-D"))
1613 add_predefined_macro (*argv);
1620 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1622 /* Take care of supplied timestamp for reproducible builds. See
1623 * https://reproducible-builds.org/specs/source-date-epoch/ */
1624 if (!opt_date && (s = getenv ("SOURCE_DATE_EPOCH")) && *s)
1627 /* Start processing. */
1628 if (argc && strcmp (*argv, "-"))
1630 FILE *fp = fopen (*argv, "rb");
1632 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1633 top_parse_file (*argv, fp);
1637 top_parse_file ("-", stdin);
1645 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"