~ubuntu-branches/ubuntu/precise/gnupg/precise

« back to all changes in this revision

Viewing changes to doc/yat2m.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2006-12-12 15:56:56 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20061212155656-rlb7g2bxqtu2q2ys
Tags: 1.4.6-1ubuntu1
* Merge from debian unstable, remaining changes:
  - config.h.in: Disable mlock() test since it fails with ulimit 0 (on
    buildds).
  - debian/rules:
    + Do not install gpg as suid root, since that is not necessary with
      kernels 2.6.8+.
    + Make the build fail if the test suite fails.

Show diffs side-by-side

added added

removed removed

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