Remove build hacks for FreeBSD.
[gnupg.git] / doc / yat2m.c
index 39feea9..5dc81bf 100644 (file)
@@ -1,10 +1,10 @@
 /* yat2m.c - Yet Another Texi 2 Man converter
  *     Copyright (C) 2005 g10 Code GmbH
- *      Copyright (C) 2006 2006 Free Software Foundation, Inc.
+ *      Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -13,9 +13,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
       @end macro
       @macro mansect {a}
       @end macro
-      @macro manpause 
+      @macro manpause
       @end macro
       @macro mancont
       @end macro
-      
+
     They are used by yat2m to select parts of the Texinfo which should
     go into the man page. These macros need to be used without leading
     left space. Processing starts after a "manpage" macro has been
     seen.  "mansect" identifies the section and yat2m make sure to
-    emit the sections in the proper order.  To insert verbatim troff
-    markup, the follwing texinfo code may be used:
+    emit the sections in the proper order.  Note that @mansect skips
+    the next input line if that line begins with @section, @subsection or
+    @chapheading.
+
+    To insert verbatim troff markup, the following texinfo code may be
+    used:
 
       @ifset manverb
       .B whateever you want
 
       @c man:.B whatever you want
 
-    This is useful in case you need just one line.  @section is
-    ignored, however @subsection gets rendered as ".SS".  @menu is
-    completely skipped. Several man pages may be extracted from one
-    file, either using the --store or the --select option.
-    Makefile snippet from GnuPG:
+    This is useful in case you need just one line. If you want to
+    include parts only in the man page but keep the texinfo
+    translation you may use:
+
+      @ifset isman
+      stuff to be rendered only on man pages
+      @end ifset
+
+    or to exclude stuff from man pages:
 
+      @ifclear isman
+      stuff not to be rendered on man pages
+      @end ifclear
 
+    the keyword @section is ignored, however @subsection gets rendered
+    as ".SS".  @menu is completely skipped. Several man pages may be
+    extracted from one file, either using the --store or the --select
+    option.
+
+    If you want to indent tables in the source use this style:
+
+      @table foo
+        @item
+        @item
+        @table
+          @item
+        @end
+      @end
+
+    Don't change the indentation within a table and keep the same
+    number of white space at the start of the line.  yat2m simply
+    detects the number of white spaces in front of an @item and remove
+    this number of spaces from all following lines until a new @item
+    is found or there are less spaces than for the last @item.
 */
 
 #include <stdio.h>
 
 
 #define PGM "yat2m"
-#define VERSION "0.5"
+#define VERSION "1.0"
 
 /* The maximum length of a line including the linefeed and one extra
    character. */
 static int verbose;
 static int quiet;
 static int debug;
-static const char *opt_source; 
-static const char *opt_release; 
+static const char *opt_source;
+static const char *opt_release;
 static const char *opt_select;
 static const char *opt_include;
 static int opt_store;
 
+/* The only define we understand is -D gpgone.  Thus we need a simple
+   boolean tro track it. */
+static int gpgone_defined;
 
 /* Flag to keep track whether any error occurred.  */
 static int any_error;
 
 
+/* Object to keep macro definitions.  */
+struct macro_s
+{
+  struct macro_s *next;
+  char *value;  /* Malloced value. */
+  char name[1];
+};
+typedef struct macro_s *macro_t;
+
+/* List of all defined macros. */
+static macro_t macrolist;
+
+
 /* Object to store one line of content.  */
 struct line_buffer_s
 {
@@ -117,26 +162,27 @@ struct section_buffer_s
 typedef struct section_buffer_s *section_buffer_t;
 
 /* Variable to keep info about the current page together.  */
-static struct 
+static struct
 {
   /* Filename of the current page or NULL if no page is active.  Malloced. */
   char *name;
 
   /* Number of allocated elements in SECTIONS below.  */
-  size_t n_sections;       
+  size_t n_sections;
   /* Array with the data of the sections.  */
-  section_buffer_t sections; 
+  section_buffer_t sections;
 
 } thepage;
 
 
-/* The list of standard section names.  */
-static const char * const standard_sections[] = 
+/* The list of standard section names.  COMMANDS and ASSUAN are GnuPG
+   specific. */
+static const char * const standard_sections[] =
   { "NAME",  "SYNOPSIS",  "DESCRIPTION",
     "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
-    "OPTIONS", "USAGE", "EXAMPLES", "FILES",
+    "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
     "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
-    "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
+    "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
 
 
 /*-- Local prototypes.  --*/
@@ -254,7 +300,7 @@ isodatestring (void)
   static char buffer[11+5];
   struct tm *tp;
   time_t atime = time (NULL);
-  
+
   if (atime < 0)
     strcpy (buffer, "????" "-??" "-??");
   else
@@ -275,7 +321,7 @@ static section_buffer_t
 get_section_buffer (const char *name)
 {
   int i;
-  section_buffer_t sect; 
+  section_buffer_t sect;
 
   /* If there is no section we put everything into the required NAME
      section.  Given that this is the first one listed it is likely
@@ -368,7 +414,7 @@ static void
 start_page (char *name)
 {
   if (verbose)
-    inf ("starting page `%s'", name);
+    inf ("starting page '%s'", name);
   assert (!thepage.name);
   thepage.name = xstrdup (name);
   thepage.n_sections = 0;
@@ -382,11 +428,13 @@ write_th (FILE *fp)
 {
   char *name, *p;
 
+  fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
+
   name = ascii_strupr (xstrdup (thepage.name));
   p = strrchr (name, '.');
   if (!p || !p[1])
     {
-      err ("no section name in man page `%s'", thepage.name);
+      err ("no section name in man page '%s'", thepage.name);
       free (name);
       return -1;
     }
@@ -415,11 +463,13 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
   } cmdtbl[] = {
     { "command", 0, "\\fB", "\\fR" },
     { "code",    0, "\\fB", "\\fR" },
+    { "sc",      0, "\\fB", "\\fR" },
     { "var",     0, "\\fI", "\\fR" },
-    { "samp",    0, "\n'",  "'\n"  },
-    { "file",    0, "`\\fI","\\fR'" }, 
-    { "env",     0, "`\\fI","\\fR'" }, 
+    { "samp",    0, "\\(aq", "\\(aq"  },
+    { "file",    0, "\\(oq\\fI","\\fR\\(cq" },
+    { "env",     0, "\\(oq\\fI","\\fR\\(cq" },
     { "acronym", 0 },
+    { "dfn",     0 },
     { "option",  0, "\\fB", "\\fR"   },
     { "example", 1, ".RS 2\n.nf\n" },
     { "smallexample", 1, ".RS 2\n.nf\n" },
@@ -431,23 +481,23 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
     { "uref",    0, "(\\fB", "\\fR)" },
     { "footnote",0, " ([", "])" },
     { "emph",    0, "\\fI", "\\fR" },
-    { "w",       1 },                                 
+    { "w",       1 },
     { "c",       5 },
     { "opindex", 1 },
     { "cpindex", 1 },
     { "cindex",  1 },
-    { "node",    1 },
     { "noindent", 0 },
     { "section", 1 },
+    { "chapter", 1 },
     { "subsection", 6, "\n.SS " },
     { "chapheading", 0},
     { "item",    2, ".TP\n.B " },
     { "itemx",   2, ".TP\n.B " },
-    { "table",   3 }, 
+    { "table",   3 },
+    { "itemize",   3 },
+    { "bullet",  0, "* " },
     { "end",     4 },
     { "quotation",1, ".RS\n\\fB" },
-    { "ifset",   1 },
-    { "ifclear",   1 },
     { NULL }
   };
   size_t n;
@@ -468,7 +518,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
         {
         case 1: /* Throw away the entire line.  */
           s = memchr (rest, '\n', len);
-          return s? (s-rest)+1 : len;  
+          return s? (s-rest)+1 : len;
         case 2: /* Handle @item.  */
           break;
         case 3: /* Handle table.  */
@@ -476,7 +526,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
             fputs (".RS\n", fp);
           /* Now throw away the entire line. */
           s = memchr (rest, '\n', len);
-          return s? (s-rest)+1 : len;  
+          return s? (s-rest)+1 : len;
           break;
         case 4: /* Handle end.  */
           for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
@@ -502,14 +552,9 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
             {
               fputs ("\\fR\n.RE\n", fp);
             }
-          else if (n >= 5 && !memcmp (s, "ifset", 5)
-              && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
-            {
-              fputs ("\\fR\n.RE\n", fp);
-            }
           /* Now throw away the entire line. */
           s = memchr (rest, '\n', len);
-          return s? (s-rest)+1 : len;  
+          return s? (s-rest)+1 : len;
         case 5: /* Handle special comments. */
           for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
             ;
@@ -521,7 +566,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
             }
           /* Now throw away the entire line. */
           s = memchr (rest, '\n', len);
-          return s? (s-rest)+1 : len;  
+          return s? (s-rest)+1 : len;
         case 6:
           *eol_action = 1;
           break;
@@ -534,8 +579,20 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
     }
   else
     {
-      inf ("texinfo command `%s' not supported (%.*s)", command,
-           ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
+      macro_t m;
+
+      for (m = macrolist; m ; m = m->next)
+        if (!strcmp (m->name, command))
+            break;
+      if (m)
+        {
+          proc_texi_buffer (fp, m->value, strlen (m->value),
+                            table_level, eol_action);
+          ignore_args = 1; /* Parameterized macros are not yet supported. */
+        }
+      else
+        inf ("texinfo command '%s' not supported (%.*s)", command,
+             ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
     }
 
   if (*rest == '{')
@@ -548,7 +605,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
           i--;
       if (i)
         {
-          err ("closing brace for command `%s' not found", command);
+          err ("closing brace for command '%s' not found", command);
           return len;
         }
       if (n > 2 && !ignore_args)
@@ -584,17 +641,17 @@ proc_texi_buffer (FILE *fp, const char *line, size_t len,
             {
               switch (*s)
                 {
-                case '@': case '{': case '}': 
-                  putc (*s, fp); in_cmd = 0; 
+                case '@': case '{': case '}':
+                  putc (*s, fp); in_cmd = 0;
                   break;
                 case ':': /* Not ending a sentence flag.  */
                   in_cmd = 0;
                   break;
                 case '.': case '!': case '?': /* Ending a sentence. */
-                  putc (*s, fp); in_cmd = 0; 
+                  putc (*s, fp); in_cmd = 0;
                   break;
                 case ' ': case '\t': case '\n': /* Non collapsing spaces.  */
-                  putc (*s, fp); in_cmd = 0; 
+                  putc (*s, fp); in_cmd = 0;
                   break;
                 default:
                   cmdidx = 0;
@@ -612,7 +669,7 @@ proc_texi_buffer (FILE *fp, const char *line, size_t len,
               s--; len++;
               in_cmd = 0;
             }
-          else if (cmdidx < sizeof cmdbuf -1)  
+          else if (cmdidx < sizeof cmdbuf -1)
             cmdbuf[cmdidx++] = *s;
           else
             {
@@ -634,9 +691,21 @@ proc_texi_buffer (FILE *fp, const char *line, size_t len,
             }
           *eol_action = 0;
         }
+      else if (*s == '\\')
+        fputs ("\\\\", fp);
       else
         putc (*s, fp);
     }
+
+  if (in_cmd > 1)
+    {
+      cmdbuf[cmdidx] = 0;
+      n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
+      assert (n <= len);
+      s += n; len -= n;
+      s--; len++;
+      in_cmd = 0;
+    }
 }
 
 
@@ -679,7 +748,7 @@ write_content (FILE *fp, line_buffer_t lines)
 /*           fputs ("---\n", fp); */
           parse_texi_line (fp, line->line, &table_level);
         }
-    }  
+    }
 }
 
 
@@ -702,7 +771,7 @@ static void
 finish_page (void)
 {
   FILE *fp;
-  section_buffer_t sect;
+  section_buffer_t sect = NULL;
   int idx;
   const char *s;
   int i;
@@ -711,13 +780,13 @@ finish_page (void)
     return; /* No page active.  */
 
   if (verbose)
-    inf ("finishing page `%s'", thepage.name);
+    inf ("finishing page '%s'", thepage.name);
 
   if (opt_select)
     {
       if (!strcmp (opt_select, thepage.name))
         {
-          inf ("selected `%s'", thepage.name );
+          inf ("selected '%s'", thepage.name );
           fp = stdout;
         }
       else
@@ -729,10 +798,10 @@ finish_page (void)
     }
   else if (opt_store)
     {
-      inf ("writing `%s'", thepage.name );
+      inf ("writing '%s'", thepage.name );
       fp = fopen ( thepage.name, "w" );
       if (!fp)
-        die ("failed to create `%s': %s\n", thepage.name, strerror (errno));
+        die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
     }
   else
     fp = stdout;
@@ -768,7 +837,7 @@ finish_page (void)
                   write_content (fp, sect->lines);
                 }
             }
-          
+
         }
     }
 
@@ -787,13 +856,27 @@ finish_page (void)
 /* Parse one Texinfo file and create manpages according to the
    embedded instructions.  */
 static void
-parse_file (const char *fname, FILE *fp, char **section_name)
+parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
 {
   char *line;
   int lnr = 0;
+  /* Fixme: The following state variables don't carry over to include
+     files. */
   int in_verbatim = 0;
-  int in_pause = 0;
   int skip_to_end = 0;        /* Used to skip over menu entries. */
+  int skip_sect_line = 0;     /* Skip after @mansect.  */
+  int ifset_nesting = 0;      /* How often a ifset has been seen. */
+  int ifclear_nesting = 0;    /* How often a ifclear has been seen. */
+  int in_gpgone = 0;          /* Keep track of "@ifset gpgone" parts.  */
+  int not_in_gpgone = 0;      /* Keep track of "@ifclear gpgone" parts.  */
+  int not_in_man = 0;         /* Keep track of "@ifclear isman" parts.  */
+  int item_indent = 0;        /* How far is the current @item indented.  */
+
+  /* Helper to define a macro. */
+  char *macroname = NULL;
+  char *macrovalue = NULL;
+  size_t macrovaluesize = 0;
+  size_t macrovalueused = 0;
 
   line = xmalloc (LINESIZE);
   while (fgets (line, LINESIZE, fp))
@@ -805,45 +888,217 @@ parse_file (const char *fname, FILE *fp, char **section_name)
       lnr++;
       if (!n || line[n-1] != '\n')
         {
-          err ("%s:$d: trailing linefeed missing, line too long or "
+          err ("%s:%d: trailing linefeed missing, line too long or "
                "embedded Nul character", fname, lnr);
           break;
         }
       line[--n] = 0;
-      /* We only parse lines we need and ignore the rest.  There are a
-         few macros used to control this as well as one @ifset
-         command.  Parts we know about are saved away into containers
-         separate for each section. */
+
+      /* Kludge to allow indentation of tables.  */
+      for (p=line; *p == ' ' || *p == '\t'; p++)
+        ;
+      if (*p)
+        {
+          if (*p == '@' && !strncmp (p+1, "item", 4))
+            item_indent = p - line;  /* Set a new indent level.  */
+          else if (p - line < item_indent)
+            item_indent = 0;         /* Switch off indention.  */
+
+          if (item_indent)
+            {
+              memmove (line, line+item_indent, n - item_indent + 1);
+              n -= item_indent;
+            }
+        }
+
+
       if (*line == '@')
         {
           for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
             n++;
           while (*p == ' ' || *p == '\t')
             p++;
+        }
+      else
+        p = line;
 
-          if (skip_to_end
-              && n == 4 && !memcmp (line, "@end", 4)
-              && (line[4]==' '||line[4]=='\t'||!line[4]))
+      /* Take action on macro.  */
+      if (macroname)
+        {
+          if (n == 4 && !memcmp (line, "@end", 4)
+              && (line[4]==' '||line[4]=='\t'||!line[4])
+              && !strncmp (p, "macro", 5)
+              && (p[5]==' '||p[5]=='\t'||!p[5]))
             {
-              skip_to_end = 0;
+              macro_t m;
+
+              if (macrovalueused)
+                macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
+              macrovalue[macrovalueused] = 0;     /* Terminate macro. */
+              macrovalue = xrealloc (macrovalue, macrovalueused+1);
+
+              for (m= macrolist; m; m = m->next)
+                if (!strcmp (m->name, macroname))
+                  break;
+              if (m)
+                free (m->value);
+              else
+                {
+                  m = xcalloc (1, sizeof *m + strlen (macroname));
+                  strcpy (m->name, macroname);
+                  m->next = macrolist;
+                  macrolist = m;
+                }
+              m->value = macrovalue;
+              macrovalue = NULL;
+              free (macroname);
+              macroname = NULL;
             }
-          else if (n == 6 && !memcmp (line, "@ifset", 6)
-              && !strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
+          else
             {
-              if (in_verbatim)
-                err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
-              else
-                in_verbatim = 1;
+              if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
+                {
+                  macrovaluesize += strlen (line) + 256;
+                  macrovalue = xrealloc (macrovalue,  macrovaluesize);
+                }
+              strcpy (macrovalue+macrovalueused, line);
+              macrovalueused += strlen (line);
+              macrovalue[macrovalueused++] = '\n';
             }
-          else if (in_verbatim && n == 4 && !memcmp (line, "@end", 4)
+          continue;
+        }
+
+
+      if (n >= 5 && !memcmp (line, "@node", 5)
+          && (line[5]==' '||line[5]=='\t'||!line[5]))
+        {
+          /* Completey ignore @node lines.  */
+          continue;
+        }
+
+
+      if (skip_sect_line)
+        {
+          skip_sect_line = 0;
+          if (!strncmp (line, "@section", 8)
+              || !strncmp (line, "@subsection", 11)
+              || !strncmp (line, "@chapheading", 12))
+            continue;
+        }
+
+      /* We only parse lines we need and ignore the rest.  There are a
+         few macros used to control this as well as one @ifset
+         command.  Parts we know about are saved away into containers
+         separate for each section. */
+
+      /* First process ifset/ifclear commands. */
+      if (*line == '@')
+        {
+          if (n == 6 && !memcmp (line, "@ifset", 6)
+                   && (line[6]==' '||line[6]=='\t'))
+            {
+              ifset_nesting++;
+
+              if (!strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
+                {
+                  if (in_verbatim)
+                    err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
+                  else
+                    in_verbatim = ifset_nesting;
+                }
+              else if (!strncmp (p, "gpgone", 6)
+                       && (p[6]==' '||p[6]=='\t'||!p[6]))
+                {
+                  if (in_gpgone)
+                    err ("%s:%d: nested \"@ifset gpgone\"", fname, lnr);
+                  else
+                    in_gpgone = ifset_nesting;
+                }
+              continue;
+            }
+          else if (n == 4 && !memcmp (line, "@end", 4)
+                   && (line[4]==' '||line[4]=='\t')
                    && !strncmp (p, "ifset", 5)
                    && (p[5]==' '||p[5]=='\t'||!p[5]))
             {
-              in_verbatim = 0;
+              if (in_verbatim && ifset_nesting == in_verbatim)
+                in_verbatim = 0;
+              if (in_gpgone && ifset_nesting == in_gpgone)
+                in_gpgone = 0;
+
+              if (ifset_nesting)
+                ifset_nesting--;
+              else
+                err ("%s:%d: unbalanced \"@end ifset\"", fname, lnr);
+              continue;
+            }
+          else if (n == 8 && !memcmp (line, "@ifclear", 8)
+                   && (line[8]==' '||line[8]=='\t'))
+            {
+              ifclear_nesting++;
+
+              if (!strncmp (p, "gpgone", 6)
+                  && (p[6]==' '||p[6]=='\t'||!p[6]))
+                {
+                  if (not_in_gpgone)
+                    err ("%s:%d: nested \"@ifclear gpgone\"", fname, lnr);
+                  else
+                    not_in_gpgone = ifclear_nesting;
+                }
+
+              else if (!strncmp (p, "isman", 5)
+                       && (p[5]==' '||p[5]=='\t'||!p[5]))
+                {
+                  if (not_in_man)
+                    err ("%s:%d: nested \"@ifclear isman\"", fname, lnr);
+                  else
+                    not_in_man = ifclear_nesting;
+                }
+
+              continue;
+            }
+          else if (n == 4 && !memcmp (line, "@end", 4)
+                   && (line[4]==' '||line[4]=='\t')
+                   && !strncmp (p, "ifclear", 7)
+                   && (p[7]==' '||p[7]=='\t'||!p[7]))
+            {
+              if (not_in_gpgone && ifclear_nesting == not_in_gpgone)
+                not_in_gpgone = 0;
+              if (not_in_man && ifclear_nesting == not_in_man)
+                not_in_man = 0;
+
+              if (ifclear_nesting)
+                ifclear_nesting--;
+              else
+                err ("%s:%d: unbalanced \"@end ifclear\"", fname, lnr);
+              continue;
+            }
+        }
+
+      /* Take action on ifset/ifclear.  */
+      if ( (in_gpgone && !gpgone_defined)
+           || (not_in_gpgone && gpgone_defined)
+           || not_in_man)
+        continue;
+
+      /* Process commands. */
+      if (*line == '@')
+        {
+          if (skip_to_end
+              && n == 4 && !memcmp (line, "@end", 4)
+              && (line[4]==' '||line[4]=='\t'||!line[4]))
+            {
+              skip_to_end = 0;
             }
           else if (in_verbatim)
             {
-              got_line = 1;
+                got_line = 1;
+            }
+          else if (n == 6 && !memcmp (line, "@macro", 6))
+            {
+              macroname = xstrdup (p);
+              macrovalue = xmalloc ((macrovaluesize = 1024));
+              macrovalueused = 0;
             }
           else if (n == 8 && !memcmp (line, "@manpage", 8))
             {
@@ -862,6 +1117,7 @@ parse_file (const char *fname, FILE *fp, char **section_name)
                   free (*section_name);
                   *section_name = ascii_strupr (xstrdup (p));
                   in_pause = 0;
+                  skip_sect_line = 1;
                 }
             }
           else if (n == 9 && !memcmp (line, "@manpause", 9))
@@ -887,11 +1143,6 @@ parse_file (const char *fname, FILE *fp, char **section_name)
             {
               skip_to_end = 1;
             }
-          else if (n == 8 && !memcmp (line, "@ifclear", 8)
-              && !strncmp (p, "isman", 5) && (p[5]==' '||p[5]=='\t'||!p[5]))
-            {
-              skip_to_end = 1;
-            }
           else if (n == 8 && !memcmp (line, "@include", 8)
                    && (line[8]==' '||line[8]=='\t'||!line[8]))
             {
@@ -911,15 +1162,20 @@ parse_file (const char *fname, FILE *fp, char **section_name)
                 }
 
               if (!incfp)
-                err ("can't open include file `%s':%s",
+                err ("can't open include file '%s':%s",
                      incname, strerror (errno));
               else
                 {
-                  parse_file (incname, incfp, section_name);
+                  parse_file (incname, incfp, section_name, in_pause);
                   fclose (incfp);
                 }
               free (incname);
             }
+          else if (n == 4 && !memcmp (line, "@bye", 4)
+                   && (line[4]==' '||line[4]=='\t'||!line[4]))
+            {
+              break;
+            }
           else if (!skip_to_end)
             got_line = 1;
         }
@@ -934,6 +1190,8 @@ parse_file (const char *fname, FILE *fp, char **section_name)
     }
   if (ferror (fp))
     err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
+  free (macroname);
+  free (macrovalue);
   free (line);
 }
 
@@ -943,13 +1201,21 @@ top_parse_file (const char *fname, FILE *fp)
 {
   char *section_name = NULL;  /* Name of the current section or NULL
                                  if not in a section.  */
-  parse_file (fname, fp, &section_name);
+  while (macrolist)
+    {
+      macro_t next = macrolist->next;
+      free (macrolist->value);
+      free (macrolist);
+      macrolist = next;
+    }
+
+  parse_file (fname, fp, &section_name, 0);
   free (section_name);
   finish_page ();
 }
 
 
-int 
+int
 main (int argc, char **argv)
 {
   int last_argc = -1;
@@ -981,7 +1247,8 @@ main (int argc, char **argv)
                 "  --verbose        enable extra informational output\n"
                 "  --debug          enable additional debug output\n"
                 "  --help           display this help and exit\n"
-                "  -I DIR           also search in include DIR\n\n"
+                "  -I DIR           also search in include DIR\n"
+                "  -D gpgone        the only useable define\n\n"
                 "With no FILE, or when FILE is -, read standard input.\n\n"
                 "Report bugs to <bugs@g10code.com>.");
           exit (0);
@@ -1041,7 +1308,7 @@ main (int argc, char **argv)
               opt_select = strrchr (*argv, '/');
               if (opt_select)
                 opt_select++;
-              else 
+              else
                 opt_select = *argv;
               argc--; argv++;
             }
@@ -1055,8 +1322,18 @@ main (int argc, char **argv)
               argc--; argv++;
             }
         }
-    }          
+      else if (!strcmp (*argv, "-D"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              if (!strcmp (*argv, "gpgone"))
+                gpgone_defined = 1;
+              argc--; argv++;
+            }
+        }
+    }
+
   if (argc > 1)
     die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");