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