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