Remove pth dependency
[platform/upstream/gpg2.git] / doc / yat2m.c
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.
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
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  **********************************************/
24
25 /*
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.
30
31     To use this you need to add the following macros into your texinfo
32     source:
33
34       @macro manpage {a}
35       @end macro
36       @macro mansect {a}
37       @end macro
38       @macro manpause
39       @end macro
40       @macro mancont
41       @end macro
42
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
49     @chapheading.
50
51     To insert verbatim troff markup, the following texinfo code may be
52     used:
53
54       @ifset manverb
55       .B whateever you want
56       @end ifset
57
58     alternatively a special comment may be used:
59
60       @c man:.B whatever you want
61
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:
65
66       @ifset isman
67       stuff to be rendered only on man pages
68       @end ifset
69
70     or to exclude stuff from man pages:
71
72       @ifclear isman
73       stuff not to be rendered on man pages
74       @end ifclear
75
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
79     option.
80
81     If you want to indent tables in the source use this style:
82
83       @table foo
84         @item
85         @item
86         @table
87           @item
88         @end
89       @end
90
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.
96
97     Note that @* does only work correctly if used at the end of an
98     input line.
99
100 */
101
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <stddef.h>
105 #include <string.h>
106 #include <errno.h>
107 #include <stdarg.h>
108 #include <assert.h>
109 #include <ctype.h>
110 #include <time.h>
111
112
113 #if __GNUC__
114 # define MY_GCC_VERSION (__GNUC__ * 10000 \
115                          + __GNUC_MINOR__ * 100         \
116                          + __GNUC_PATCHLEVEL__)
117 #else
118 # define MY_GCC_VERSION 0
119 #endif
120
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)))
124 #else
125 # define ATTR_PRINTF(f, a)
126 # define ATTR_NR_PRINTF(f, a)
127 #endif
128 #if MY_GCC_VERSION >= 30200
129 # define ATTR_MALLOC  __attribute__ ((__malloc__))
130 #else
131 # define ATTR_MALLOC
132 #endif
133
134
135
136 #define PGM "yat2m"
137 #define VERSION "1.0"
138
139 /* The maximum length of a line including the linefeed and one extra
140    character. */
141 #define LINESIZE 1024
142
143 /* Number of allowed condition nestings.  */
144 #define MAX_CONDITION_NESTING  10
145
146 /* Option flags. */
147 static int verbose;
148 static int quiet;
149 static int debug;
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;
156
157 /* Flag to keep track whether any error occurred.  */
158 static int any_error;
159
160
161 /* Object to keep macro definitions.  */
162 struct macro_s
163 {
164   struct macro_s *next;
165   char *value;    /* Malloced value. */
166   char name[1];
167 };
168 typedef struct macro_s *macro_t;
169
170 /* List of all defined macros. */
171 static macro_t macrolist;
172
173 /* List of variables set by @set. */
174 static macro_t variablelist;
175
176 /* List of global macro names.  The value part is not used.  */
177 static macro_t predefinedmacrolist;
178
179 /* Object to keep track of @isset and @ifclear.  */
180 struct condition_s
181 {
182   int manverb;   /* "manverb" needs special treatment.  */
183   int isset;     /* This is an @isset condition.  */
184   char name[1];  /* Name of the condition macro.  */
185 };
186 typedef struct condition_s *condition_t;
187
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".  */
193
194
195 /* Object to store one line of content.  */
196 struct line_buffer_s
197 {
198   struct line_buffer_s *next;
199   int verbatim;  /* True if LINE contains verbatim data.  The default
200                     is Texinfo source.  */
201   char *line;
202 };
203 typedef struct line_buffer_s *line_buffer_t;
204
205
206 /* Object to collect the data of a section.  */
207 struct section_buffer_s
208 {
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
213                                 linked list.  */
214   line_buffer_t last_line;   /* Points to the last line appended.  */
215 };
216 typedef struct section_buffer_s *section_buffer_t;
217
218 /* Variable to keep info about the current page together.  */
219 static struct
220 {
221   /* Filename of the current page or NULL if no page is active.  Malloced. */
222   char *name;
223
224   /* Number of allocated elements in SECTIONS below.  */
225   size_t n_sections;
226   /* Array with the data of the sections.  */
227   section_buffer_t sections;
228
229 } thepage;
230
231
232 /* The list of standard section names.  COMMANDS and ASSUAN are GnuPG
233    specific. */
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 };
240
241
242 /*-- Local prototypes.  --*/
243 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
244                               int *table_level, int *eol_action);
245
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;
251
252
253
254 /*-- Functions --*/
255
256 /* Print diagnostic message and exit with failure. */
257 static void
258 die (const char *format, ...)
259 {
260   va_list arg_ptr;
261
262   fflush (stdout);
263   fprintf (stderr, "%s: ", PGM);
264
265   va_start (arg_ptr, format);
266   vfprintf (stderr, format, arg_ptr);
267   va_end (arg_ptr);
268   putc ('\n', stderr);
269
270   exit (1);
271 }
272
273
274 /* Print diagnostic message. */
275 static void
276 err (const char *format, ...)
277 {
278   va_list arg_ptr;
279
280   fflush (stdout);
281   if (strncmp (format, "%s:%d:", 6))
282     fprintf (stderr, "%s: ", PGM);
283
284   va_start (arg_ptr, format);
285   vfprintf (stderr, format, arg_ptr);
286   va_end (arg_ptr);
287   putc ('\n', stderr);
288   any_error = 1;
289 }
290
291 /* Print diagnostic message. */
292 static void
293 inf (const char *format, ...)
294 {
295   va_list arg_ptr;
296
297   fflush (stdout);
298   fprintf (stderr, "%s: ", PGM);
299
300   va_start (arg_ptr, format);
301   vfprintf (stderr, format, arg_ptr);
302   va_end (arg_ptr);
303   putc ('\n', stderr);
304 }
305
306
307 static void *
308 xmalloc (size_t n)
309 {
310   void *p = malloc (n);
311   if (!p)
312     die ("out of core: %s", strerror (errno));
313   return p;
314 }
315
316 static void *
317 xcalloc (size_t n, size_t m)
318 {
319   void *p = calloc (n, m);
320   if (!p)
321     die ("out of core: %s", strerror (errno));
322   return p;
323 }
324
325 static void *
326 xrealloc (void *old, size_t n)
327 {
328   void *p = realloc (old, n);
329   if (!p)
330     die ("out of core: %s", strerror (errno));
331   return p;
332 }
333
334 static char *
335 xstrdup (const char *string)
336 {
337   void *p = malloc (strlen (string)+1);
338   if (!p)
339     die ("out of core: %s", strerror (errno));
340   strcpy (p, string);
341   return p;
342 }
343
344
345 /* Uppercase the ascii characters in STRING.  */
346 static char *
347 ascii_strupr (char *string)
348 {
349   char *p;
350
351   for (p = string; *p; p++)
352     if (!(*p & 0x80))
353       *p = toupper (*p);
354   return string;
355 }
356
357
358 /* Return the current date as an ISO string.  */
359 const char *
360 isodatestring (void)
361 {
362   static char buffer[11+5];
363   struct tm *tp;
364   time_t atime;
365
366   if (opt_date && *opt_date)
367     atime = strtoul (opt_date, NULL, 10);
368   else
369     atime = time (NULL);
370   if (atime < 0)
371     strcpy (buffer, "????" "-??" "-??");
372   else
373     {
374       tp = gmtime (&atime);
375       sprintf (buffer,"%04d-%02d-%02d",
376                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
377     }
378   return buffer;
379 }
380
381
382 /* Add NAME to the list of predefined macros which are global for all
383    files.  */
384 static void
385 add_predefined_macro (const char *name)
386 {
387   macro_t m;
388
389   for (m=predefinedmacrolist; m; m = m->next)
390     if (!strcmp (m->name, name))
391       break;
392   if (!m)
393     {
394       m = xcalloc (1, sizeof *m + strlen (name));
395       strcpy (m->name, name);
396       m->next = predefinedmacrolist;
397       predefinedmacrolist = m;
398     }
399 }
400
401
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
404    to this function.  */
405 static void
406 set_macro (const char *macroname, char *macrovalue)
407 {
408   macro_t m;
409
410   for (m=macrolist; m; m = m->next)
411     if (!strcmp (m->name, macroname))
412       break;
413   if (m)
414     free (m->value);
415   else
416     {
417       m = xcalloc (1, sizeof *m + strlen (macroname));
418       strcpy (m->name, macroname);
419       m->next = macrolist;
420       macrolist = m;
421     }
422   m->value = macrovalue;
423   macrovalue = NULL;
424 }
425
426
427 /* Create or update a variable with name and value given in NAMEANDVALUE.  */
428 static void
429 set_variable (char *nameandvalue)
430 {
431   macro_t m;
432   const char *value;
433   char *p;
434
435   for (p = nameandvalue; *p && *p != ' ' && *p != '\t'; p++)
436     ;
437   if (!*p)
438     value = "";
439   else
440     {
441       *p++ = 0;
442       while (*p == ' ' || *p == '\t')
443         p++;
444       value = p;
445     }
446
447   for (m=variablelist; m; m = m->next)
448     if (!strcmp (m->name, nameandvalue))
449       break;
450   if (m)
451     free (m->value);
452   else
453     {
454       m = xcalloc (1, sizeof *m + strlen (nameandvalue));
455       strcpy (m->name, nameandvalue);
456       m->next = variablelist;
457       variablelist = m;
458     }
459   m->value = xstrdup (value);
460 }
461
462
463 /* Return true if the macro or variable NAME is set, i.e. not the
464    empty string and not evaluating to 0.  */
465 static int
466 macro_set_p (const char *name)
467 {
468   macro_t m;
469
470   for (m = macrolist; m ; m = m->next)
471     if (!strcmp (m->name, name))
472       break;
473   if (!m)
474     for (m = variablelist; m ; m = m->next)
475       if (!strcmp (m->name, name))
476         break;
477   if (!m || !m->value || !*m->value)
478     return 0;
479   if ((*m->value & 0x80) || !isdigit (*m->value))
480     return 1; /* Not a digit but some other string.  */
481   return !!atoi (m->value);
482 }
483
484
485 /* Evaluate the current conditions.  */
486 static void
487 evaluate_conditions (const char *fname, int lnr)
488 {
489   int i;
490
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'); */
497
498   cond_is_active = 1;
499   cond_in_verbatim = 0;
500   if (condition_stack_idx)
501     {
502       for (i=0; i < condition_stack_idx; i++)
503         {
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))
509             {
510               cond_is_active = 0;
511               break;
512             }
513         }
514     }
515
516   /* inf ("%s:%d:   active=%d verbatim=%d", */
517   /*      fname, lnr, cond_is_active, cond_in_verbatim); */
518 }
519
520
521 /* Push a condition with condition macro NAME onto the stack.  If
522    ISSET is true, a @isset condition is pushed.  */
523 static void
524 push_condition (const char *name, int isset, const char *fname, int lnr)
525 {
526   condition_t cond;
527   int manverb = 0;
528
529   if (condition_stack_idx >= MAX_CONDITION_NESTING)
530     {
531       err ("%s:%d: condition nested too deep", fname, lnr);
532       return;
533     }
534
535   if (!strcmp (name, "manverb"))
536     {
537       if (!isset)
538         {
539           err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname, lnr);
540           return;
541         }
542       manverb = 1;
543     }
544
545   cond = xcalloc (1, sizeof *cond + strlen (name));
546   cond->manverb = manverb;
547   cond->isset = isset;
548   strcpy (cond->name, name);
549
550   condition_stack[condition_stack_idx++] = cond;
551   evaluate_conditions (fname, lnr);
552 }
553
554
555 /* Remove the last condition from the stack.  ISSET is used for error
556    reporting.  */
557 static void
558 pop_condition (int isset, const char *fname, int lnr)
559 {
560   if (!condition_stack_idx)
561     {
562       err ("%s:%d: unbalanced \"@end %s\"",
563            fname, lnr, isset?"isset":"isclear");
564       return;
565     }
566   condition_stack_idx--;
567   free (condition_stack[condition_stack_idx]);
568   condition_stack[condition_stack_idx] = NULL;
569   evaluate_conditions (fname, lnr);
570 }
571
572
573 \f
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)
579 {
580   int i;
581   section_buffer_t sect;
582
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.  */
586   if (!name)
587     name = "NAME";
588
589   for (i=0; i < thepage.n_sections; i++)
590     {
591       sect = thepage.sections + i;
592       if (sect->name && !strcmp (name, sect->name))
593         return sect;
594     }
595   for (i=0; i < thepage.n_sections; i++)
596     if (!thepage.sections[i].name)
597       break;
598   if (thepage.n_sections && i < thepage.n_sections)
599     sect = thepage.sections + i;
600   else
601     {
602       /* We need to allocate or reallocate the section array.  */
603       size_t old_n = thepage.n_sections;
604       size_t new_n = 20;
605
606       if (!old_n)
607         thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
608       else
609         {
610           thepage.sections = xrealloc (thepage.sections,
611                                        ((old_n + new_n)
612                                         * sizeof *thepage.sections));
613           memset (thepage.sections + old_n, 0,
614                   new_n * sizeof *thepage.sections);
615         }
616       thepage.n_sections += new_n;
617
618       /* Setup the tail pointers.  */
619       for (i=old_n; i < thepage.n_sections; i++)
620         {
621           sect = thepage.sections + i;
622           sect->lines_tail = &sect->lines;
623         }
624       sect = thepage.sections + old_n;
625     }
626
627   /* Store the name.  */
628   assert (!sect->name);
629   sect->name = xstrdup (name);
630   return sect;
631 }
632
633
634
635 /* Add the content of LINE to the section named SECTNAME.  */
636 static void
637 add_content (const char *sectname, char *line, int verbatim)
638 {
639   section_buffer_t sect;
640   line_buffer_t lb;
641
642   sect = get_section_buffer (sectname);
643   if (sect->last_line && !sect->last_line->verbatim == !verbatim)
644     {
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
647          one large buffer.  */
648       size_t n1, n;
649
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);
656     }
657   else
658     {
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;
665     }
666 }
667
668
669 /* Prepare for a new man page using the filename NAME. */
670 static void
671 start_page (char *name)
672 {
673   if (verbose)
674     inf ("starting page '%s'", name);
675   assert (!thepage.name);
676   thepage.name = xstrdup (name);
677   thepage.n_sections = 0;
678 }
679
680
681 /* Write the .TH entry of the current page.  Return -1 if there is a
682    problem with the page. */
683 static int
684 write_th (FILE *fp)
685 {
686   char *name, *p;
687
688   fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
689
690   name = ascii_strupr (xstrdup (thepage.name));
691   p = strrchr (name, '.');
692   if (!p || !p[1])
693     {
694       err ("no section name in man page '%s'", thepage.name);
695       free (name);
696       return -1;
697     }
698   *p++ = 0;
699   fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
700            name, p, isodatestring (), opt_release, opt_source);
701   free (name);
702   return 0;
703 }
704
705
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.  */
712 static size_t
713 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
714                int *table_level, int *eol_action)
715 {
716   static struct {
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. */
721   } cmdtbl[] = {
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" },
731     { "acronym", 0 },
732     { "dfn",     0 },
733     { "option",  0, "\\fB", "\\fR"   },
734     { "example", 1, ".RS 2\n.nf\n" },
735     { "smallexample", 1, ".RS 2\n.nf\n" },
736     { "asis",    7 },
737     { "anchor",  7 },
738     { "cartouche", 1 },
739     { "ref",     0, "[", "]" },
740     { "xref",    0, "See: [", "]" },
741     { "pxref",   0, "see: [", "]" },
742     { "uref",    0, "(\\fB", "\\fR)" },
743     { "footnote",0, " ([", "])" },
744     { "emph",    0, "\\fI", "\\fR" },
745     { "w",       1 },
746     { "c",       5 },
747     { "efindex", 1 },
748     { "opindex", 1 },
749     { "cpindex", 1 },
750     { "cindex",  1 },
751     { "noindent", 0 },
752     { "section", 1 },
753     { "chapter", 1 },
754     { "subsection", 6, "\n.SS " },
755     { "chapheading", 0},
756     { "item",    2, ".TP\n.B " },
757     { "itemx",   2, ".TQ\n.B " },
758     { "table",   3 },
759     { "itemize",   3 },
760     { "bullet",  0, "* " },
761     { "*",       0, "\n.br"},
762     { "/",       0 },
763     { "end",     4 },
764     { "quotation",1, ".RS\n\\fB" },
765     { "value", 8 },
766     { NULL }
767   };
768   size_t n;
769   int i;
770   const char *s;
771   const char *lead_out = NULL;
772   int ignore_args = 0;
773
774   for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
775     ;
776   if (cmdtbl[i].name)
777     {
778       s = cmdtbl[i].lead_in;
779       if (s)
780         fputs (s, fp);
781       lead_out = cmdtbl[i].lead_out;
782       switch (cmdtbl[i].what)
783         {
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.  */
788           break;
789         case 3: /* Handle table.  */
790           if (++(*table_level) > 1)
791             fputs (".RS\n", fp);
792           /* Now throw away the entire line. */
793           s = memchr (rest, '\n', len);
794           return s? (s-rest)+1 : len;
795           break;
796         case 4: /* Handle end.  */
797           for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
798             ;
799           if (n >= 5 && !memcmp (s, "table", 5)
800               && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
801             {
802               if ((*table_level)-- > 1)
803                 fputs (".RE\n", fp);
804               else
805                 fputs (".P\n", fp);
806             }
807           else if (n >= 7 && !memcmp (s, "example", 7)
808               && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
809             {
810               fputs (".fi\n.RE\n", fp);
811             }
812           else if (n >= 12 && !memcmp (s, "smallexample", 12)
813               && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
814             {
815               fputs (".fi\n.RE\n", fp);
816             }
817           else if (n >= 9 && !memcmp (s, "quotation", 9)
818               && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
819             {
820               fputs ("\\fR\n.RE\n", fp);
821             }
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--)
827             ;
828           if (n >= 4 && !memcmp (s, "man:", 4))
829             {
830               for (s+=4, n-=4; n && *s != '\n'; n--, s++)
831                 putc (*s, fp);
832               putc ('\n', fp);
833             }
834           /* Now throw away the entire line. */
835           s = memchr (rest, '\n', len);
836           return s? (s-rest)+1 : len;
837         case 6:
838           *eol_action = 1;
839           break;
840         case 7:
841           ignore_args = 1;
842           break;
843         case 8:
844           ignore_args = 1;
845           if (*rest != '{')
846             {
847               err ("opening brace for command '%s' missing", command);
848               return len;
849             }
850           else
851             {
852               /* Find closing brace.  */
853               for (s=rest+1, n=1; *s && n < len; s++, n++)
854                 if (*s == '}')
855                   break;
856               if (*s != '}')
857                 {
858                   err ("closing brace for command '%s' not found", command);
859                   return len;
860                 }
861               else
862                 {
863                   size_t len = s - (rest + 1);
864                   macro_t m;
865
866                   for (m = variablelist; m; m = m->next)
867                     if (strlen (m->name) == len
868                         &&!strncmp (m->name, rest+1, len))
869                       break;
870                   if (m)
871                     fputs (m->value, fp);
872                   else
873                     inf ("texinfo variable '%.*s' is not set",
874                          (int)len, rest+1);
875                 }
876             }
877           break;
878         default:
879           break;
880         }
881     }
882   else /* macro */
883     {
884       macro_t m;
885
886       for (m = macrolist; m ; m = m->next)
887         if (!strcmp (m->name, command))
888             break;
889       if (m)
890         {
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. */
894         }
895       else
896         inf ("texinfo command '%s' not supported (%.*s)", command,
897              (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
898     }
899
900   if (*rest == '{')
901     {
902       /* Find matching closing brace.  */
903       for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
904         if (*s == '{')
905           i++;
906         else if (*s == '}')
907           i--;
908       if (i)
909         {
910           err ("closing brace for command '%s' not found", command);
911           return len;
912         }
913       if (n > 2 && !ignore_args)
914         proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
915     }
916   else
917     n = 0;
918
919   if (lead_out)
920     fputs (lead_out, fp);
921
922   return n;
923 }
924
925
926
927 /* Process the string LINE with LEN bytes of Texinfo content. */
928 static void
929 proc_texi_buffer (FILE *fp, const char *line, size_t len,
930                   int *table_level, int *eol_action)
931 {
932   const char *s;
933   char cmdbuf[256];
934   int cmdidx = 0;
935   int in_cmd = 0;
936   size_t n;
937
938   for (s=line; *s && len; s++, len--)
939     {
940       if (in_cmd)
941         {
942           if (in_cmd == 1)
943             {
944               switch (*s)
945                 {
946                 case '@': case '{': case '}':
947                   putc (*s, fp); in_cmd = 0;
948                   break;
949                 case ':': /* Not ending a sentence flag.  */
950                   in_cmd = 0;
951                   break;
952                 case '.': case '!': case '?': /* Ending a sentence. */
953                   putc (*s, fp); in_cmd = 0;
954                   break;
955                 case ' ': case '\t': case '\n': /* Non collapsing spaces.  */
956                   putc (*s, fp); in_cmd = 0;
957                   break;
958                 default:
959                   cmdidx = 0;
960                   cmdbuf[cmdidx++] = *s;
961                   in_cmd++;
962                   break;
963                 }
964             }
965           else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
966             {
967               cmdbuf[cmdidx] = 0;
968               n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
969               assert (n <= len);
970               s += n; len -= n;
971               s--; len++;
972               in_cmd = 0;
973             }
974           else if (cmdidx < sizeof cmdbuf -1)
975             cmdbuf[cmdidx++] = *s;
976           else
977             {
978               err ("texinfo command too long - ignored");
979               in_cmd = 0;
980             }
981         }
982       else if (*s == '@')
983         in_cmd = 1;
984       else if (*s == '\n')
985         {
986           switch (*eol_action)
987             {
988             case 1: /* Create a dummy paragraph. */
989               fputs ("\n\\ \n", fp);
990               break;
991             default:
992               putc (*s, fp);
993             }
994           *eol_action = 0;
995         }
996       else if (*s == '\\')
997         fputs ("\\\\", fp);
998       else
999         putc (*s, fp);
1000     }
1001
1002   if (in_cmd > 1)
1003     {
1004       cmdbuf[cmdidx] = 0;
1005       n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
1006       assert (n <= len);
1007       s += n; len -= n;
1008       s--; len++;
1009       /* in_cmd = 0; -- doc only */
1010     }
1011 }
1012
1013
1014 /* Do something with the Texinfo line LINE.  */
1015 static void
1016 parse_texi_line (FILE *fp, const char *line, int *table_level)
1017 {
1018   int eol_action = 0;
1019
1020   /* A quick test whether there are any texinfo commands.  */
1021   if (!strchr (line, '@'))
1022     {
1023       fputs (line, fp);
1024       putc ('\n', fp);
1025       return;
1026     }
1027   proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
1028   putc ('\n', fp);
1029 }
1030
1031
1032 /* Write all the lines LINES to FP.  */
1033 static void
1034 write_content (FILE *fp, line_buffer_t lines)
1035 {
1036   line_buffer_t line;
1037   int table_level = 0;
1038
1039   for (line = lines; line; line = line->next)
1040     {
1041       if (line->verbatim)
1042         {
1043           fputs (line->line, fp);
1044           putc ('\n', fp);
1045         }
1046       else
1047         {
1048 /*           fputs ("TEXI---", fp); */
1049 /*           fputs (line->line, fp); */
1050 /*           fputs ("---\n", fp); */
1051           parse_texi_line (fp, line->line, &table_level);
1052         }
1053     }
1054 }
1055
1056
1057
1058 static int
1059 is_standard_section (const char *name)
1060 {
1061   int i;
1062   const char *s;
1063
1064   for (i=0; (s=standard_sections[i]); i++)
1065     if (!strcmp (s, name))
1066       return 1;
1067   return 0;
1068 }
1069
1070
1071 /* Finish a page; that is sort the data and write it out to the file.  */
1072 static void
1073 finish_page (void)
1074 {
1075   FILE *fp;
1076   section_buffer_t sect = NULL;
1077   int idx;
1078   const char *s;
1079   int i;
1080
1081   if (!thepage.name)
1082     return; /* No page active.  */
1083
1084   if (verbose)
1085     inf ("finishing page '%s'", thepage.name);
1086
1087   if (opt_select)
1088     {
1089       if (!strcmp (opt_select, thepage.name))
1090         {
1091           inf ("selected '%s'", thepage.name );
1092           fp = stdout;
1093         }
1094       else
1095         {
1096           fp = fopen ( "/dev/null", "w" );
1097           if (!fp)
1098             die ("failed to open /dev/null: %s\n", strerror (errno));
1099         }
1100     }
1101   else if (opt_store)
1102     {
1103       inf ("writing '%s'", thepage.name );
1104       fp = fopen ( thepage.name, "w" );
1105       if (!fp)
1106         die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
1107     }
1108   else
1109     fp = stdout;
1110
1111   if (write_th (fp))
1112     goto leave;
1113
1114   for (idx=0; (s=standard_sections[idx]); idx++)
1115     {
1116       for (i=0; i < thepage.n_sections; i++)
1117         {
1118           sect = thepage.sections + i;
1119           if (sect->name && !strcmp (s, sect->name))
1120             break;
1121         }
1122       if (i == thepage.n_sections)
1123         sect = NULL;
1124
1125       if (sect)
1126         {
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++)
1132             {
1133               sect = thepage.sections + i;
1134               if (sect->name && is_standard_section (sect->name))
1135                 break;
1136               if (sect->name)
1137                 {
1138                   fprintf (fp, ".SH %s\n", sect->name);
1139                   write_content (fp, sect->lines);
1140                 }
1141             }
1142
1143         }
1144     }
1145
1146
1147  leave:
1148   if (fp != stdout)
1149     fclose (fp);
1150   free (thepage.name);
1151   thepage.name = NULL;
1152   /* FIXME: Cleanup the content.  */
1153 }
1154
1155
1156
1157
1158 /* Parse one Texinfo file and create manpages according to the
1159    embedded instructions.  */
1160 static void
1161 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
1162 {
1163   char *line;
1164   int lnr = 0;
1165   /* Fixme: The following state variables don't carry over to include
1166      files. */
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.  */
1170
1171   /* Helper to define a macro. */
1172   char *macroname = NULL;
1173   char *macrovalue = NULL;
1174   size_t macrovaluesize = 0;
1175   size_t macrovalueused = 0;
1176
1177   line = xmalloc (LINESIZE);
1178   while (fgets (line, LINESIZE, fp))
1179     {
1180       size_t n = strlen (line);
1181       int got_line = 0;
1182       char *p, *pend;
1183
1184       lnr++;
1185       if (!n || line[n-1] != '\n')
1186         {
1187           err ("%s:%d: trailing linefeed missing, line too long or "
1188                "embedded Nul character", fname, lnr);
1189           break;
1190         }
1191       line[--n] = 0;
1192
1193       /* Kludge to allow indentation of tables.  */
1194       for (p=line; *p == ' ' || *p == '\t'; p++)
1195         ;
1196       if (*p)
1197         {
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.  */
1202
1203           if (item_indent)
1204             {
1205               memmove (line, line+item_indent, n - item_indent + 1);
1206               n -= item_indent;
1207             }
1208         }
1209
1210
1211       if (*line == '@')
1212         {
1213           for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
1214             n++;
1215           while (*p == ' ' || *p == '\t')
1216             p++;
1217         }
1218       else
1219         p = line;
1220
1221       /* Take action on macro.  */
1222       if (macroname)
1223         {
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]))
1228             {
1229               if (macrovalueused)
1230                 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
1231               macrovalue[macrovalueused] = 0;     /* Terminate macro. */
1232               macrovalue = xrealloc (macrovalue, macrovalueused+1);
1233
1234               set_macro (macroname, macrovalue);
1235               macrovalue = NULL;
1236               free (macroname);
1237               macroname = NULL;
1238             }
1239           else
1240             {
1241               if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
1242                 {
1243                   macrovaluesize += strlen (line) + 256;
1244                   macrovalue = xrealloc (macrovalue,  macrovaluesize);
1245                 }
1246               strcpy (macrovalue+macrovalueused, line);
1247               macrovalueused += strlen (line);
1248               macrovalue[macrovalueused++] = '\n';
1249             }
1250           continue;
1251         }
1252
1253
1254       if (n >= 5 && !memcmp (line, "@node", 5)
1255           && (line[5]==' '||line[5]=='\t'||!line[5]))
1256         {
1257           /* Completey ignore @node lines.  */
1258           continue;
1259         }
1260
1261
1262       if (skip_sect_line)
1263         {
1264           skip_sect_line = 0;
1265           if (!strncmp (line, "@section", 8)
1266               || !strncmp (line, "@subsection", 11)
1267               || !strncmp (line, "@chapheading", 12))
1268             continue;
1269         }
1270
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. */
1275
1276       /* First process ifset/ifclear commands. */
1277       if (*line == '@')
1278         {
1279           if (n == 6 && !memcmp (line, "@ifset", 6)
1280                    && (line[6]==' '||line[6]=='\t'))
1281             {
1282               for (p=line+7; *p == ' ' || *p == '\t'; p++)
1283                 ;
1284               if (!*p)
1285                 {
1286                   err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
1287                   continue;
1288                 }
1289               for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1290                 ;
1291               *pend = 0;  /* Ignore rest of the line.  */
1292               push_condition (p, 1, fname, lnr);
1293               continue;
1294             }
1295           else if (n == 8 && !memcmp (line, "@ifclear", 8)
1296                    && (line[8]==' '||line[8]=='\t'))
1297             {
1298               for (p=line+9; *p == ' ' || *p == '\t'; p++)
1299                 ;
1300               if (!*p)
1301                 {
1302                   err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
1303                   continue;
1304                 }
1305               for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1306                 ;
1307               *pend = 0;  /* Ignore rest of the line.  */
1308               push_condition (p, 0, fname, lnr);
1309               continue;
1310             }
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]))
1315             {
1316               pop_condition (1, fname, lnr);
1317               continue;
1318             }
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]))
1323             {
1324               pop_condition (0, fname, lnr);
1325               continue;
1326             }
1327         }
1328
1329       /* Take action on ifset/ifclear.  */
1330       if (!cond_is_active)
1331         continue;
1332
1333       /* Process commands. */
1334       if (*line == '@')
1335         {
1336           if (skip_to_end
1337               && n == 4 && !memcmp (line, "@end", 4)
1338               && (line[4]==' '||line[4]=='\t'||!line[4]))
1339             {
1340               skip_to_end = 0;
1341             }
1342           else if (cond_in_verbatim)
1343             {
1344                 got_line = 1;
1345             }
1346           else if (n == 6 && !memcmp (line, "@macro", 6))
1347             {
1348               macroname = xstrdup (p);
1349               macrovalue = xmalloc ((macrovaluesize = 1024));
1350               macrovalueused = 0;
1351             }
1352           else if (n == 4 && !memcmp (line, "@set", 4))
1353             {
1354               set_variable (p);
1355             }
1356           else if (n == 8 && !memcmp (line, "@manpage", 8))
1357             {
1358               free (*section_name);
1359               *section_name = NULL;
1360               finish_page ();
1361               start_page (p);
1362               in_pause = 0;
1363             }
1364           else if (n == 8 && !memcmp (line, "@mansect", 8))
1365             {
1366               if (!thepage.name)
1367                 err ("%s:%d: section outside of a man page", fname, lnr);
1368               else
1369                 {
1370                   free (*section_name);
1371                   *section_name = ascii_strupr (xstrdup (p));
1372                   in_pause = 0;
1373                   skip_sect_line = 1;
1374                 }
1375             }
1376           else if (n == 9 && !memcmp (line, "@manpause", 9))
1377             {
1378               if (!*section_name)
1379                 err ("%s:%d: pausing outside of a man section", fname, lnr);
1380               else if (in_pause)
1381                 err ("%s:%d: already pausing", fname, lnr);
1382               else
1383                 in_pause = 1;
1384             }
1385           else if (n == 8 && !memcmp (line, "@mancont", 8))
1386             {
1387               if (!*section_name)
1388                 err ("%s:%d: continue outside of a man section", fname, lnr);
1389               else if (!in_pause)
1390                 err ("%s:%d: continue while not pausing", fname, lnr);
1391               else
1392                 in_pause = 0;
1393             }
1394           else if (n == 5 && !memcmp (line, "@menu", 5)
1395                    && (line[5]==' '||line[5]=='\t'||!line[5]))
1396             {
1397               skip_to_end = 1;
1398             }
1399           else if (n == 8 && !memcmp (line, "@include", 8)
1400                    && (line[8]==' '||line[8]=='\t'||!line[8]))
1401             {
1402               char *incname = xstrdup (p);
1403               FILE *incfp = fopen (incname, "r");
1404
1405               if (!incfp && opt_include && *opt_include && *p != '/')
1406                 {
1407                   free (incname);
1408                   incname = xmalloc (strlen (opt_include) + 1
1409                                      + strlen (p) + 1);
1410                   strcpy (incname, opt_include);
1411                   if ( incname[strlen (incname)-1] != '/' )
1412                     strcat (incname, "/");
1413                   strcat (incname, p);
1414                   incfp = fopen (incname, "r");
1415                 }
1416
1417               if (!incfp)
1418                 err ("can't open include file '%s': %s",
1419                      incname, strerror (errno));
1420               else
1421                 {
1422                   parse_file (incname, incfp, section_name, in_pause);
1423                   fclose (incfp);
1424                 }
1425               free (incname);
1426             }
1427           else if (n == 4 && !memcmp (line, "@bye", 4)
1428                    && (line[4]==' '||line[4]=='\t'||!line[4]))
1429             {
1430               break;
1431             }
1432           else if (!skip_to_end)
1433             got_line = 1;
1434         }
1435       else if (!skip_to_end)
1436         got_line = 1;
1437
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);
1442
1443     }
1444   if (ferror (fp))
1445     err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1446   free (macroname);
1447   free (macrovalue);
1448   free (line);
1449 }
1450
1451
1452 static void
1453 top_parse_file (const char *fname, FILE *fp)
1454 {
1455   char *section_name = NULL;  /* Name of the current section or NULL
1456                                  if not in a section.  */
1457   macro_t m;
1458
1459   while (macrolist)
1460     {
1461       macro_t next = macrolist->next;
1462       free (macrolist->value);
1463       free (macrolist);
1464       macrolist = next;
1465     }
1466   while (variablelist)
1467     {
1468       macro_t next = variablelist->next;
1469       free (variablelist->value);
1470       free (variablelist);
1471       variablelist = next;
1472     }
1473   for (m=predefinedmacrolist; m; m = m->next)
1474     set_macro (m->name, xstrdup ("1"));
1475   cond_is_active = 1;
1476   cond_in_verbatim = 0;
1477
1478   parse_file (fname, fp, &section_name, 0);
1479   free (section_name);
1480   finish_page ();
1481 }
1482
1483
1484 int
1485 main (int argc, char **argv)
1486 {
1487   int last_argc = -1;
1488   const char *s;
1489
1490   opt_source = "GNU";
1491   opt_release = "";
1492
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");
1497
1498   /* Option parsing.  */
1499   if (argc)
1500     {
1501       argc--; argv++;
1502     }
1503   while (argc && last_argc != argc )
1504     {
1505       last_argc = argc;
1506       if (!strcmp (*argv, "--"))
1507         {
1508           argc--; argv++;
1509           break;
1510         }
1511       else if (!strcmp (*argv, "--help"))
1512         {
1513           puts (
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>.");
1528           exit (0);
1529         }
1530       else if (!strcmp (*argv, "--version"))
1531         {
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.");
1537           exit (0);
1538         }
1539       else if (!strcmp (*argv, "--verbose"))
1540         {
1541           verbose = 1;
1542           argc--; argv++;
1543         }
1544       else if (!strcmp (*argv, "--quiet"))
1545         {
1546           quiet = 1;
1547           argc--; argv++;
1548         }
1549       else if (!strcmp (*argv, "--debug"))
1550         {
1551           verbose = debug = 1;
1552           argc--; argv++;
1553         }
1554       else if (!strcmp (*argv, "--source"))
1555         {
1556           argc--; argv++;
1557           if (argc)
1558             {
1559               opt_source = *argv;
1560               argc--; argv++;
1561             }
1562         }
1563       else if (!strcmp (*argv, "--release"))
1564         {
1565           argc--; argv++;
1566           if (argc)
1567             {
1568               opt_release = *argv;
1569               argc--; argv++;
1570             }
1571         }
1572       else if (!strcmp (*argv, "--date"))
1573         {
1574           argc--; argv++;
1575           if (argc)
1576             {
1577               opt_date = *argv;
1578               argc--; argv++;
1579             }
1580         }
1581       else if (!strcmp (*argv, "--store"))
1582         {
1583           opt_store = 1;
1584           argc--; argv++;
1585         }
1586       else if (!strcmp (*argv, "--select"))
1587         {
1588           argc--; argv++;
1589           if (argc)
1590             {
1591               opt_select = strrchr (*argv, '/');
1592               if (opt_select)
1593                 opt_select++;
1594               else
1595                 opt_select = *argv;
1596               argc--; argv++;
1597             }
1598         }
1599       else if (!strcmp (*argv, "-I"))
1600         {
1601           argc--; argv++;
1602           if (argc)
1603             {
1604               opt_include = *argv;
1605               argc--; argv++;
1606             }
1607         }
1608       else if (!strcmp (*argv, "-D"))
1609         {
1610           argc--; argv++;
1611           if (argc)
1612             {
1613               add_predefined_macro (*argv);
1614               argc--; argv++;
1615             }
1616         }
1617     }
1618
1619   if (argc > 1)
1620     die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1621
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)
1625     opt_date = s;
1626
1627   /* Start processing. */
1628   if (argc && strcmp (*argv, "-"))
1629     {
1630       FILE *fp = fopen (*argv, "rb");
1631       if (!fp)
1632         die ("%s:0: can't open file: %s", *argv, strerror (errno));
1633       top_parse_file (*argv, fp);
1634       fclose (fp);
1635     }
1636   else
1637     top_parse_file ("-", stdin);
1638
1639   return !!any_error;
1640 }
1641
1642
1643 /*
1644 Local Variables:
1645 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1646 End:
1647 */