gpg: New import option show-only.
[gnupg.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     alternativly 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 remainer 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, "\\(aq", "\\(aq"  },
728     { "file",    0, "\\(oq\\fI","\\fR\\(cq" },
729     { "env",     0, "\\(oq\\fI","\\fR\\(cq" },
730     { "acronym", 0 },
731     { "dfn",     0 },
732     { "option",  0, "\\fB", "\\fR"   },
733     { "example", 1, ".RS 2\n.nf\n" },
734     { "smallexample", 1, ".RS 2\n.nf\n" },
735     { "asis",    7 },
736     { "anchor",  7 },
737     { "cartouche", 1 },
738     { "ref",     0, "[", "]" },
739     { "xref",    0, "See: [", "]" },
740     { "pxref",   0, "see: [", "]" },
741     { "uref",    0, "(\\fB", "\\fR)" },
742     { "footnote",0, " ([", "])" },
743     { "emph",    0, "\\fI", "\\fR" },
744     { "w",       1 },
745     { "c",       5 },
746     { "efindex", 1 },
747     { "opindex", 1 },
748     { "cpindex", 1 },
749     { "cindex",  1 },
750     { "noindent", 0 },
751     { "section", 1 },
752     { "chapter", 1 },
753     { "subsection", 6, "\n.SS " },
754     { "chapheading", 0},
755     { "item",    2, ".TP\n.B " },
756     { "itemx",   2, ".TQ\n.B " },
757     { "table",   3 },
758     { "itemize",   3 },
759     { "bullet",  0, "* " },
760     { "*",       0, "\n.br"},
761     { "/",       0 },
762     { "end",     4 },
763     { "quotation",1, ".RS\n\\fB" },
764     { "value", 8 },
765     { NULL }
766   };
767   size_t n;
768   int i;
769   const char *s;
770   const char *lead_out = NULL;
771   int ignore_args = 0;
772
773   for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
774     ;
775   if (cmdtbl[i].name)
776     {
777       s = cmdtbl[i].lead_in;
778       if (s)
779         fputs (s, fp);
780       lead_out = cmdtbl[i].lead_out;
781       switch (cmdtbl[i].what)
782         {
783         case 1: /* Throw away the entire line.  */
784           s = memchr (rest, '\n', len);
785           return s? (s-rest)+1 : len;
786         case 2: /* Handle @item.  */
787           break;
788         case 3: /* Handle table.  */
789           if (++(*table_level) > 1)
790             fputs (".RS\n", fp);
791           /* Now throw away the entire line. */
792           s = memchr (rest, '\n', len);
793           return s? (s-rest)+1 : len;
794           break;
795         case 4: /* Handle end.  */
796           for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
797             ;
798           if (n >= 5 && !memcmp (s, "table", 5)
799               && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
800             {
801               if ((*table_level)-- > 1)
802                 fputs (".RE\n", fp);
803               else
804                 fputs (".P\n", fp);
805             }
806           else if (n >= 7 && !memcmp (s, "example", 7)
807               && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
808             {
809               fputs (".fi\n.RE\n", fp);
810             }
811           else if (n >= 12 && !memcmp (s, "smallexample", 12)
812               && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
813             {
814               fputs (".fi\n.RE\n", fp);
815             }
816           else if (n >= 9 && !memcmp (s, "quotation", 9)
817               && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
818             {
819               fputs ("\\fR\n.RE\n", fp);
820             }
821           /* Now throw away the entire line. */
822           s = memchr (rest, '\n', len);
823           return s? (s-rest)+1 : len;
824         case 5: /* Handle special comments. */
825           for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
826             ;
827           if (n >= 4 && !memcmp (s, "man:", 4))
828             {
829               for (s+=4, n-=4; n && *s != '\n'; n--, s++)
830                 putc (*s, fp);
831               putc ('\n', fp);
832             }
833           /* Now throw away the entire line. */
834           s = memchr (rest, '\n', len);
835           return s? (s-rest)+1 : len;
836         case 6:
837           *eol_action = 1;
838           break;
839         case 7:
840           ignore_args = 1;
841           break;
842         case 8:
843           ignore_args = 1;
844           if (*rest != '{')
845             {
846               err ("opening brace for command '%s' missing", command);
847               return len;
848             }
849           else
850             {
851               /* Find closing brace.  */
852               for (s=rest+1, n=1; *s && n < len; s++, n++)
853                 if (*s == '}')
854                   break;
855               if (*s != '}')
856                 {
857                   err ("closing brace for command '%s' not found", command);
858                   return len;
859                 }
860               else
861                 {
862                   size_t len = s - (rest + 1);
863                   macro_t m;
864
865                   for (m = variablelist; m; m = m->next)
866                     if (strlen (m->name) == len
867                         &&!strncmp (m->name, rest+1, len))
868                       break;
869                   if (m)
870                     fputs (m->value, fp);
871                   else
872                     inf ("texinfo variable '%.*s' is not set",
873                          (int)len, rest+1);
874                 }
875             }
876           break;
877         default:
878           break;
879         }
880     }
881   else /* macro */
882     {
883       macro_t m;
884
885       for (m = macrolist; m ; m = m->next)
886         if (!strcmp (m->name, command))
887             break;
888       if (m)
889         {
890           proc_texi_buffer (fp, m->value, strlen (m->value),
891                             table_level, eol_action);
892           ignore_args = 1; /* Parameterized macros are not yet supported. */
893         }
894       else
895         inf ("texinfo command '%s' not supported (%.*s)", command,
896              (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
897     }
898
899   if (*rest == '{')
900     {
901       /* Find matching closing brace.  */
902       for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
903         if (*s == '{')
904           i++;
905         else if (*s == '}')
906           i--;
907       if (i)
908         {
909           err ("closing brace for command '%s' not found", command);
910           return len;
911         }
912       if (n > 2 && !ignore_args)
913         proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
914     }
915   else
916     n = 0;
917
918   if (lead_out)
919     fputs (lead_out, fp);
920
921   return n;
922 }
923
924
925
926 /* Process the string LINE with LEN bytes of Texinfo content. */
927 static void
928 proc_texi_buffer (FILE *fp, const char *line, size_t len,
929                   int *table_level, int *eol_action)
930 {
931   const char *s;
932   char cmdbuf[256];
933   int cmdidx = 0;
934   int in_cmd = 0;
935   size_t n;
936
937   for (s=line; *s && len; s++, len--)
938     {
939       if (in_cmd)
940         {
941           if (in_cmd == 1)
942             {
943               switch (*s)
944                 {
945                 case '@': case '{': case '}':
946                   putc (*s, fp); in_cmd = 0;
947                   break;
948                 case ':': /* Not ending a sentence flag.  */
949                   in_cmd = 0;
950                   break;
951                 case '.': case '!': case '?': /* Ending a sentence. */
952                   putc (*s, fp); in_cmd = 0;
953                   break;
954                 case ' ': case '\t': case '\n': /* Non collapsing spaces.  */
955                   putc (*s, fp); in_cmd = 0;
956                   break;
957                 default:
958                   cmdidx = 0;
959                   cmdbuf[cmdidx++] = *s;
960                   in_cmd++;
961                   break;
962                 }
963             }
964           else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
965             {
966               cmdbuf[cmdidx] = 0;
967               n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
968               assert (n <= len);
969               s += n; len -= n;
970               s--; len++;
971               in_cmd = 0;
972             }
973           else if (cmdidx < sizeof cmdbuf -1)
974             cmdbuf[cmdidx++] = *s;
975           else
976             {
977               err ("texinfo command too long - ignored");
978               in_cmd = 0;
979             }
980         }
981       else if (*s == '@')
982         in_cmd = 1;
983       else if (*s == '\n')
984         {
985           switch (*eol_action)
986             {
987             case 1: /* Create a dummy paragraph. */
988               fputs ("\n\\ \n", fp);
989               break;
990             default:
991               putc (*s, fp);
992             }
993           *eol_action = 0;
994         }
995       else if (*s == '\\')
996         fputs ("\\\\", fp);
997       else
998         putc (*s, fp);
999     }
1000
1001   if (in_cmd > 1)
1002     {
1003       cmdbuf[cmdidx] = 0;
1004       n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
1005       assert (n <= len);
1006       s += n; len -= n;
1007       s--; len++;
1008       /* in_cmd = 0; -- doc only */
1009     }
1010 }
1011
1012
1013 /* Do something with the Texinfo line LINE.  */
1014 static void
1015 parse_texi_line (FILE *fp, const char *line, int *table_level)
1016 {
1017   int eol_action = 0;
1018
1019   /* A quick test whether there are any texinfo commands.  */
1020   if (!strchr (line, '@'))
1021     {
1022       fputs (line, fp);
1023       putc ('\n', fp);
1024       return;
1025     }
1026   proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
1027   putc ('\n', fp);
1028 }
1029
1030
1031 /* Write all the lines LINES to FP.  */
1032 static void
1033 write_content (FILE *fp, line_buffer_t lines)
1034 {
1035   line_buffer_t line;
1036   int table_level = 0;
1037
1038   for (line = lines; line; line = line->next)
1039     {
1040       if (line->verbatim)
1041         {
1042           fputs (line->line, fp);
1043           putc ('\n', fp);
1044         }
1045       else
1046         {
1047 /*           fputs ("TEXI---", fp); */
1048 /*           fputs (line->line, fp); */
1049 /*           fputs ("---\n", fp); */
1050           parse_texi_line (fp, line->line, &table_level);
1051         }
1052     }
1053 }
1054
1055
1056
1057 static int
1058 is_standard_section (const char *name)
1059 {
1060   int i;
1061   const char *s;
1062
1063   for (i=0; (s=standard_sections[i]); i++)
1064     if (!strcmp (s, name))
1065       return 1;
1066   return 0;
1067 }
1068
1069
1070 /* Finish a page; that is sort the data and write it out to the file.  */
1071 static void
1072 finish_page (void)
1073 {
1074   FILE *fp;
1075   section_buffer_t sect = NULL;
1076   int idx;
1077   const char *s;
1078   int i;
1079
1080   if (!thepage.name)
1081     return; /* No page active.  */
1082
1083   if (verbose)
1084     inf ("finishing page '%s'", thepage.name);
1085
1086   if (opt_select)
1087     {
1088       if (!strcmp (opt_select, thepage.name))
1089         {
1090           inf ("selected '%s'", thepage.name );
1091           fp = stdout;
1092         }
1093       else
1094         {
1095           fp = fopen ( "/dev/null", "w" );
1096           if (!fp)
1097             die ("failed to open /dev/null: %s\n", strerror (errno));
1098         }
1099     }
1100   else if (opt_store)
1101     {
1102       inf ("writing '%s'", thepage.name );
1103       fp = fopen ( thepage.name, "w" );
1104       if (!fp)
1105         die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
1106     }
1107   else
1108     fp = stdout;
1109
1110   if (write_th (fp))
1111     goto leave;
1112
1113   for (idx=0; (s=standard_sections[idx]); idx++)
1114     {
1115       for (i=0; i < thepage.n_sections; i++)
1116         {
1117           sect = thepage.sections + i;
1118           if (sect->name && !strcmp (s, sect->name))
1119             break;
1120         }
1121       if (i == thepage.n_sections)
1122         sect = NULL;
1123
1124       if (sect)
1125         {
1126           fprintf (fp, ".SH %s\n", sect->name);
1127           write_content (fp, sect->lines);
1128           /* Now continue with all non standard sections directly
1129              following this one. */
1130           for (i++; i < thepage.n_sections; i++)
1131             {
1132               sect = thepage.sections + i;
1133               if (sect->name && is_standard_section (sect->name))
1134                 break;
1135               if (sect->name)
1136                 {
1137                   fprintf (fp, ".SH %s\n", sect->name);
1138                   write_content (fp, sect->lines);
1139                 }
1140             }
1141
1142         }
1143     }
1144
1145
1146  leave:
1147   if (fp != stdout)
1148     fclose (fp);
1149   free (thepage.name);
1150   thepage.name = NULL;
1151   /* FIXME: Cleanup the content.  */
1152 }
1153
1154
1155
1156
1157 /* Parse one Texinfo file and create manpages according to the
1158    embedded instructions.  */
1159 static void
1160 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
1161 {
1162   char *line;
1163   int lnr = 0;
1164   /* Fixme: The following state variables don't carry over to include
1165      files. */
1166   int skip_to_end = 0;        /* Used to skip over menu entries. */
1167   int skip_sect_line = 0;     /* Skip after @mansect.  */
1168   int item_indent = 0;        /* How far is the current @item indented.  */
1169
1170   /* Helper to define a macro. */
1171   char *macroname = NULL;
1172   char *macrovalue = NULL;
1173   size_t macrovaluesize = 0;
1174   size_t macrovalueused = 0;
1175
1176   line = xmalloc (LINESIZE);
1177   while (fgets (line, LINESIZE, fp))
1178     {
1179       size_t n = strlen (line);
1180       int got_line = 0;
1181       char *p, *pend;
1182
1183       lnr++;
1184       if (!n || line[n-1] != '\n')
1185         {
1186           err ("%s:%d: trailing linefeed missing, line too long or "
1187                "embedded Nul character", fname, lnr);
1188           break;
1189         }
1190       line[--n] = 0;
1191
1192       /* Kludge to allow indentation of tables.  */
1193       for (p=line; *p == ' ' || *p == '\t'; p++)
1194         ;
1195       if (*p)
1196         {
1197           if (*p == '@' && !strncmp (p+1, "item", 4))
1198             item_indent = p - line;  /* Set a new indent level.  */
1199           else if (p - line < item_indent)
1200             item_indent = 0;         /* Switch off indention.  */
1201
1202           if (item_indent)
1203             {
1204               memmove (line, line+item_indent, n - item_indent + 1);
1205               n -= item_indent;
1206             }
1207         }
1208
1209
1210       if (*line == '@')
1211         {
1212           for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
1213             n++;
1214           while (*p == ' ' || *p == '\t')
1215             p++;
1216         }
1217       else
1218         p = line;
1219
1220       /* Take action on macro.  */
1221       if (macroname)
1222         {
1223           if (n == 4 && !memcmp (line, "@end", 4)
1224               && (line[4]==' '||line[4]=='\t'||!line[4])
1225               && !strncmp (p, "macro", 5)
1226               && (p[5]==' '||p[5]=='\t'||!p[5]))
1227             {
1228               if (macrovalueused)
1229                 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
1230               macrovalue[macrovalueused] = 0;     /* Terminate macro. */
1231               macrovalue = xrealloc (macrovalue, macrovalueused+1);
1232
1233               set_macro (macroname, macrovalue);
1234               macrovalue = NULL;
1235               free (macroname);
1236               macroname = NULL;
1237             }
1238           else
1239             {
1240               if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
1241                 {
1242                   macrovaluesize += strlen (line) + 256;
1243                   macrovalue = xrealloc (macrovalue,  macrovaluesize);
1244                 }
1245               strcpy (macrovalue+macrovalueused, line);
1246               macrovalueused += strlen (line);
1247               macrovalue[macrovalueused++] = '\n';
1248             }
1249           continue;
1250         }
1251
1252
1253       if (n >= 5 && !memcmp (line, "@node", 5)
1254           && (line[5]==' '||line[5]=='\t'||!line[5]))
1255         {
1256           /* Completey ignore @node lines.  */
1257           continue;
1258         }
1259
1260
1261       if (skip_sect_line)
1262         {
1263           skip_sect_line = 0;
1264           if (!strncmp (line, "@section", 8)
1265               || !strncmp (line, "@subsection", 11)
1266               || !strncmp (line, "@chapheading", 12))
1267             continue;
1268         }
1269
1270       /* We only parse lines we need and ignore the rest.  There are a
1271          few macros used to control this as well as one @ifset
1272          command.  Parts we know about are saved away into containers
1273          separate for each section. */
1274
1275       /* First process ifset/ifclear commands. */
1276       if (*line == '@')
1277         {
1278           if (n == 6 && !memcmp (line, "@ifset", 6)
1279                    && (line[6]==' '||line[6]=='\t'))
1280             {
1281               for (p=line+7; *p == ' ' || *p == '\t'; p++)
1282                 ;
1283               if (!*p)
1284                 {
1285                   err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
1286                   continue;
1287                 }
1288               for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1289                 ;
1290               *pend = 0;  /* Ignore rest of the line.  */
1291               push_condition (p, 1, fname, lnr);
1292               continue;
1293             }
1294           else if (n == 8 && !memcmp (line, "@ifclear", 8)
1295                    && (line[8]==' '||line[8]=='\t'))
1296             {
1297               for (p=line+9; *p == ' ' || *p == '\t'; p++)
1298                 ;
1299               if (!*p)
1300                 {
1301                   err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
1302                   continue;
1303                 }
1304               for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1305                 ;
1306               *pend = 0;  /* Ignore rest of the line.  */
1307               push_condition (p, 0, fname, lnr);
1308               continue;
1309             }
1310           else if (n == 4 && !memcmp (line, "@end", 4)
1311                    && (line[4]==' '||line[4]=='\t')
1312                    && !strncmp (p, "ifset", 5)
1313                    && (p[5]==' '||p[5]=='\t'||!p[5]))
1314             {
1315               pop_condition (1, fname, lnr);
1316               continue;
1317             }
1318           else if (n == 4 && !memcmp (line, "@end", 4)
1319                    && (line[4]==' '||line[4]=='\t')
1320                    && !strncmp (p, "ifclear", 7)
1321                    && (p[7]==' '||p[7]=='\t'||!p[7]))
1322             {
1323               pop_condition (0, fname, lnr);
1324               continue;
1325             }
1326         }
1327
1328       /* Take action on ifset/ifclear.  */
1329       if (!cond_is_active)
1330         continue;
1331
1332       /* Process commands. */
1333       if (*line == '@')
1334         {
1335           if (skip_to_end
1336               && n == 4 && !memcmp (line, "@end", 4)
1337               && (line[4]==' '||line[4]=='\t'||!line[4]))
1338             {
1339               skip_to_end = 0;
1340             }
1341           else if (cond_in_verbatim)
1342             {
1343                 got_line = 1;
1344             }
1345           else if (n == 6 && !memcmp (line, "@macro", 6))
1346             {
1347               macroname = xstrdup (p);
1348               macrovalue = xmalloc ((macrovaluesize = 1024));
1349               macrovalueused = 0;
1350             }
1351           else if (n == 4 && !memcmp (line, "@set", 4))
1352             {
1353               set_variable (p);
1354             }
1355           else if (n == 8 && !memcmp (line, "@manpage", 8))
1356             {
1357               free (*section_name);
1358               *section_name = NULL;
1359               finish_page ();
1360               start_page (p);
1361               in_pause = 0;
1362             }
1363           else if (n == 8 && !memcmp (line, "@mansect", 8))
1364             {
1365               if (!thepage.name)
1366                 err ("%s:%d: section outside of a man page", fname, lnr);
1367               else
1368                 {
1369                   free (*section_name);
1370                   *section_name = ascii_strupr (xstrdup (p));
1371                   in_pause = 0;
1372                   skip_sect_line = 1;
1373                 }
1374             }
1375           else if (n == 9 && !memcmp (line, "@manpause", 9))
1376             {
1377               if (!*section_name)
1378                 err ("%s:%d: pausing outside of a man section", fname, lnr);
1379               else if (in_pause)
1380                 err ("%s:%d: already pausing", fname, lnr);
1381               else
1382                 in_pause = 1;
1383             }
1384           else if (n == 8 && !memcmp (line, "@mancont", 8))
1385             {
1386               if (!*section_name)
1387                 err ("%s:%d: continue outside of a man section", fname, lnr);
1388               else if (!in_pause)
1389                 err ("%s:%d: continue while not pausing", fname, lnr);
1390               else
1391                 in_pause = 0;
1392             }
1393           else if (n == 5 && !memcmp (line, "@menu", 5)
1394                    && (line[5]==' '||line[5]=='\t'||!line[5]))
1395             {
1396               skip_to_end = 1;
1397             }
1398           else if (n == 8 && !memcmp (line, "@include", 8)
1399                    && (line[8]==' '||line[8]=='\t'||!line[8]))
1400             {
1401               char *incname = xstrdup (p);
1402               FILE *incfp = fopen (incname, "r");
1403
1404               if (!incfp && opt_include && *opt_include && *p != '/')
1405                 {
1406                   free (incname);
1407                   incname = xmalloc (strlen (opt_include) + 1
1408                                      + strlen (p) + 1);
1409                   strcpy (incname, opt_include);
1410                   if ( incname[strlen (incname)-1] != '/' )
1411                     strcat (incname, "/");
1412                   strcat (incname, p);
1413                   incfp = fopen (incname, "r");
1414                 }
1415
1416               if (!incfp)
1417                 err ("can't open include file '%s': %s",
1418                      incname, strerror (errno));
1419               else
1420                 {
1421                   parse_file (incname, incfp, section_name, in_pause);
1422                   fclose (incfp);
1423                 }
1424               free (incname);
1425             }
1426           else if (n == 4 && !memcmp (line, "@bye", 4)
1427                    && (line[4]==' '||line[4]=='\t'||!line[4]))
1428             {
1429               break;
1430             }
1431           else if (!skip_to_end)
1432             got_line = 1;
1433         }
1434       else if (!skip_to_end)
1435         got_line = 1;
1436
1437       if (got_line && cond_in_verbatim)
1438         add_content (*section_name, line, 1);
1439       else if (got_line && thepage.name && *section_name && !in_pause)
1440         add_content (*section_name, line, 0);
1441
1442     }
1443   if (ferror (fp))
1444     err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1445   free (macroname);
1446   free (macrovalue);
1447   free (line);
1448 }
1449
1450
1451 static void
1452 top_parse_file (const char *fname, FILE *fp)
1453 {
1454   char *section_name = NULL;  /* Name of the current section or NULL
1455                                  if not in a section.  */
1456   macro_t m;
1457
1458   while (macrolist)
1459     {
1460       macro_t next = macrolist->next;
1461       free (macrolist->value);
1462       free (macrolist);
1463       macrolist = next;
1464     }
1465   while (variablelist)
1466     {
1467       macro_t next = variablelist->next;
1468       free (variablelist->value);
1469       free (variablelist);
1470       variablelist = next;
1471     }
1472   for (m=predefinedmacrolist; m; m = m->next)
1473     set_macro (m->name, xstrdup ("1"));
1474   cond_is_active = 1;
1475   cond_in_verbatim = 0;
1476
1477   parse_file (fname, fp, &section_name, 0);
1478   free (section_name);
1479   finish_page ();
1480 }
1481
1482
1483 int
1484 main (int argc, char **argv)
1485 {
1486   int last_argc = -1;
1487   const char *s;
1488
1489   opt_source = "GNU";
1490   opt_release = "";
1491
1492   /* Define default macros.  The trick is that these macros are not
1493      defined when using the actual texinfo renderer. */
1494   add_predefined_macro ("isman");
1495   add_predefined_macro ("manverb");
1496
1497   /* Option parsing.  */
1498   if (argc)
1499     {
1500       argc--; argv++;
1501     }
1502   while (argc && last_argc != argc )
1503     {
1504       last_argc = argc;
1505       if (!strcmp (*argv, "--"))
1506         {
1507           argc--; argv++;
1508           break;
1509         }
1510       else if (!strcmp (*argv, "--help"))
1511         {
1512           puts (
1513                 "Usage: " PGM " [OPTION] [FILE]\n"
1514                 "Extract man pages from a Texinfo source.\n\n"
1515                 "  --source NAME    use NAME as source field\n"
1516                 "  --release STRING use STRING as the release field\n"
1517                 "  --date EPOCH     use EPOCH as publication date\n"
1518                 "  --store          write output using @manpage name\n"
1519                 "  --select NAME    only output pages with @manpage NAME\n"
1520                 "  --verbose        enable extra informational output\n"
1521                 "  --debug          enable additional debug output\n"
1522                 "  --help           display this help and exit\n"
1523                 "  -I DIR           also search in include DIR\n"
1524                 "  -D gpgone        the only usable define\n\n"
1525                 "With no FILE, or when FILE is -, read standard input.\n\n"
1526                 "Report bugs to <bugs@g10code.com>.");
1527           exit (0);
1528         }
1529       else if (!strcmp (*argv, "--version"))
1530         {
1531           puts (PGM " " VERSION "\n"
1532                "Copyright (C) 2005 g10 Code GmbH\n"
1533                "This program comes with ABSOLUTELY NO WARRANTY.\n"
1534                "This is free software, and you are welcome to redistribute it\n"
1535                 "under certain conditions. See the file COPYING for details.");
1536           exit (0);
1537         }
1538       else if (!strcmp (*argv, "--verbose"))
1539         {
1540           verbose = 1;
1541           argc--; argv++;
1542         }
1543       else if (!strcmp (*argv, "--quiet"))
1544         {
1545           quiet = 1;
1546           argc--; argv++;
1547         }
1548       else if (!strcmp (*argv, "--debug"))
1549         {
1550           verbose = debug = 1;
1551           argc--; argv++;
1552         }
1553       else if (!strcmp (*argv, "--source"))
1554         {
1555           argc--; argv++;
1556           if (argc)
1557             {
1558               opt_source = *argv;
1559               argc--; argv++;
1560             }
1561         }
1562       else if (!strcmp (*argv, "--release"))
1563         {
1564           argc--; argv++;
1565           if (argc)
1566             {
1567               opt_release = *argv;
1568               argc--; argv++;
1569             }
1570         }
1571       else if (!strcmp (*argv, "--date"))
1572         {
1573           argc--; argv++;
1574           if (argc)
1575             {
1576               opt_date = *argv;
1577               argc--; argv++;
1578             }
1579         }
1580       else if (!strcmp (*argv, "--store"))
1581         {
1582           opt_store = 1;
1583           argc--; argv++;
1584         }
1585       else if (!strcmp (*argv, "--select"))
1586         {
1587           argc--; argv++;
1588           if (argc)
1589             {
1590               opt_select = strrchr (*argv, '/');
1591               if (opt_select)
1592                 opt_select++;
1593               else
1594                 opt_select = *argv;
1595               argc--; argv++;
1596             }
1597         }
1598       else if (!strcmp (*argv, "-I"))
1599         {
1600           argc--; argv++;
1601           if (argc)
1602             {
1603               opt_include = *argv;
1604               argc--; argv++;
1605             }
1606         }
1607       else if (!strcmp (*argv, "-D"))
1608         {
1609           argc--; argv++;
1610           if (argc)
1611             {
1612               add_predefined_macro (*argv);
1613               argc--; argv++;
1614             }
1615         }
1616     }
1617
1618   if (argc > 1)
1619     die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1620
1621   /* Take care of supplied timestamp for reproducible builds.  See
1622    * https://reproducible-builds.org/specs/source-date-epoch/  */
1623   if (!opt_date && (s = getenv ("SOURCE_DATE_EPOCH")) && *s)
1624     opt_date = s;
1625
1626   /* Start processing. */
1627   if (argc && strcmp (*argv, "-"))
1628     {
1629       FILE *fp = fopen (*argv, "rb");
1630       if (!fp)
1631         die ("%s:0: can't open file: %s", *argv, strerror (errno));
1632       top_parse_file (*argv, fp);
1633       fclose (fp);
1634     }
1635   else
1636     top_parse_file ("-", stdin);
1637
1638   return !!any_error;
1639 }
1640
1641
1642 /*
1643 Local Variables:
1644 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1645 End:
1646 */