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