]> granicus.if.org Git - neomutt/commitdiff
build: remove forward declarations
authorRichard Russon <rich@flatcap.org>
Sat, 25 Mar 2017 16:20:01 +0000 (16:20 +0000)
committerRichard Russon <rich@flatcap.org>
Thu, 30 Mar 2017 22:19:16 +0000 (23:19 +0100)
doc/makedoc.c

index 05d580266a6ae1495b49747f829c2ad25c90be09..5b7d485f660076e05d91bea7266cfcd385f6676f 100644 (file)
@@ -98,128 +98,6 @@ enum output_formats_t OutputFormat = F_NONE;
 char *Progname;
 short Debug = 0;
 
-static char *get_token (char *, size_t, char *);
-static char *skip_ws (char *);
-static const char *type2human (int);
-static int buff2type (const char *);
-static int flush_doc (int, FILE *);
-static int handle_docline (char *, FILE *, int);
-static int print_it (int, char *, FILE *, int);
-static void print_confline (const char *, int, const char *, FILE *);
-static void handle_confline (char *, FILE *);
-static void makedoc (FILE *, FILE *);
-static void pretty_default (char *, size_t, const char *, int);
-static int sgml_fputc (int, FILE *);
-static int sgml_fputs (const char *, FILE *);
-static int sgml_id_fputs (const char *, FILE *);
-
-int main (int argc, char *argv[])
-{
-  int c;
-  FILE *f = NULL;
-
-  if ((Progname = strrchr (argv[0], '/')))
-    Progname++;
-  else
-    Progname = argv[0];
-
-  while ((c = getopt (argc, argv, "cmsd")) != EOF)
-  {
-    switch (c)
-    {
-      case 'c': OutputFormat = F_CONF; break;
-      case 'm': OutputFormat = F_MAN; break;
-      case 's': OutputFormat = F_SGML; break;
-      case 'd': Debug++; break;
-      default:
-      {
-       fprintf (stderr, "%s: bad command line parameter.\n", Progname);
-       exit (1);
-      }
-    }
-  }
-
-  if (optind != argc)
-  {
-    if ((f = fopen (argv[optind], "r")) == NULL)
-    {
-      fprintf (stderr, "%s: Can't open %s (%s).\n",
-              Progname, argv[optind], strerror (errno));
-      exit (1);
-    }
-  }
-  else
-    f = stdin;
-
-  switch (OutputFormat)
-  {
-    case F_CONF:
-    case F_MAN:
-    case F_SGML: makedoc (f, stdout); break;
-    default:
-    {
-      fprintf (stderr, "%s: No output format specified.\n",
-              Progname);
-      exit (1);
-    }
-  }
-
-  if (f != stdin)
-    fclose (f);
-
-  return 0;
-}
-
-
-static void makedoc (FILE *in, FILE *out)
-{
-  char buffer[BUFFSIZE];
-  char token[BUFFSIZE];
-  char *p = NULL;
-  int active = 0;
-  int line = 0;
-  int docstat = D_INIT;
-
-  while ((fgets (buffer, sizeof (buffer), in)))
-  {
-    line++;
-    if ((p = strchr (buffer, '\n')) == NULL)
-    {
-      fprintf (stderr, "%s: Line %d too long.  Ask a wizard to enlarge\n"
-                      "%s: my buffer size.\n", Progname, line, Progname);
-      exit (1);
-    }
-    else
-      *p = '\0';
-
-    if (!(p = get_token (token, sizeof (token), buffer)))
-      continue;
-
-    if (Debug)
-    {
-      fprintf (stderr, "%s: line %d.  first token: \"%s\".\n",
-              Progname, line, token);
-    }
-
-    if (strcmp (token, "/*++*/") == 0)
-      active = 1;
-    else if (strcmp (token, "/*--*/") == 0)
-    {
-      docstat = flush_doc (docstat, out);
-      active = 0;
-    }
-    else if (active && ((strcmp (token, "/**") == 0) || (strcmp (token, "**") == 0)))
-      docstat = handle_docline (p, out, docstat);
-    else if (active && (strcmp (token, "{") == 0))
-    {
-      docstat = flush_doc (docstat, out);
-      handle_confline (p, out);
-    }
-  }
-  flush_doc (docstat, out);
-  fputs ("\n", out);
-}
-
 /* skip whitespace */
 
 static char *skip_ws (char *s)
@@ -325,417 +203,519 @@ static char *get_token (char *d, size_t l, char *s)
   return t;
 }
 
-
-/**
- ** Configuration line parser
- **
- ** The following code parses a line from init.h which declares
- ** a configuration variable.
- **
- **/
-
-/* note: the following enum must be in the same order as the
- * following string definitions!
- */
-
-enum
-{
-  DT_NONE = 0,
-  DT_BOOL,
-  DT_NUM,
-  DT_STR,
-  DT_PATH,
-  DT_QUAD,
-  DT_SORT,
-  DT_RX,
-  DT_MAGIC,
-  DT_SYN,
-  DT_ADDR,
-  DT_MBCHARTBL
-};
-
-struct
+static int sgml_fputc (int c, FILE *out)
 {
-  char *machine;
-  char *human;
+  switch (c)
+  {
+    /* the bare minimum for escaping */
+    case '<': return fputs ("&lt;", out);
+    case '>': return fputs ("&gt;", out);
+    case '&': return fputs ("&amp;", out);
+    default:  return fputc (c, out);
+  }
 }
-types[] =
-{
-  { "DT_NONE", "-none-"        },
-  { "DT_BOOL",  "boolean"      },
-  { "DT_NUM",   "number"       },
-  { "DT_STR",  "string"        },
-  { "DT_PATH", "path"          },
-  { "DT_QUAD", "quadoption"    },
-  { "DT_SORT", "sort order"    },
-  { "DT_RX",   "regular expression" },
-  { "DT_MAGIC",        "folder magic" },
-  { "DT_SYN",  NULL },
-  { "DT_ADDR", "e-mail address" },
-  { "DT_MBCHARTBL", "string"   },
-  { NULL, NULL }
-};
-
 
-static int buff2type (const char *s)
+static int sgml_fputs (const char *s, FILE *out)
 {
-  int type;
-
-  for (type = DT_NONE; types[type].machine; type++)
-    if (strcmp (types[type].machine, s) == 0)
-       return type;
-
-  return DT_NONE;
-}
+  for (; *s; s++)
+    if (sgml_fputc ((unsigned int) *s, out) == EOF)
+      return EOF;
 
-static const char *type2human (int type)
-{
-  return types[type].human;
+  return 0;
 }
-static void handle_confline (char *s, FILE *out)
-{
-  char varname[BUFFSIZE];
-  char buff[BUFFSIZE];
-  char tmp[BUFFSIZE];
-  int type;
-
-  char val[BUFFSIZE];
-
-  /* xxx - put this into an actual state machine? */
-
-  /* variable name */
-  if (!(s = get_token (varname, sizeof (varname), s))) return;
 
-  /* comma */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
-
-  /* type */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
+/* print something. */
 
-  type = buff2type (buff);
+static int print_it (int special, char *str, FILE *out, int docstat)
+{
+  int onl = docstat & (D_NL|D_NP);
 
-  /* possibly a "|" or comma */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
+  docstat &= ~(D_NL|D_NP|D_INIT);
 
-  if (strcmp (buff, "|") == 0)
+  switch (OutputFormat)
   {
-    if (Debug) fprintf (stderr, "%s: Expecting <subtype> <comma>.\n", Progname);
-    /* ignore subtype and comma */
-    if (!(s = get_token (buff, sizeof (buff), s))) return;
-    if (!(s = get_token (buff, sizeof (buff), s))) return;
-  }
-
-  /* redraw, comma */
+    /* configuration file */
+    case F_CONF:
+    {
+      switch (special)
+      {
+       static int Continuation = 0;
 
-  while (1)
-  {
-    if (!(s = get_token (buff, sizeof (buff), s))) return;
-    if (strcmp (buff, ",") == 0)
-      break;
-  }
+       case SP_END_FT: docstat &= ~(D_EM|D_BF|D_TT); break;
+       case SP_START_BF: docstat |= D_BF; break;
+       case SP_START_EM: docstat |= D_EM; break;
+        case SP_START_TT: docstat |= D_TT; break;
+       case SP_NEWLINE:
+       {
+         if (onl)
+           docstat |= onl;
+         else
+         {
+           fputs ("\n# ", out);
+           docstat |= D_NL;
+         }
+         if (docstat & D_DL)
+           ++ Continuation;
+         break;
+       }
+       case SP_NEWPAR:
+       {
+         if (onl & D_NP)
+         {
+           docstat |= onl;
+           break;
+         }
 
-  /* option name or UL &address */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
-  if (strcmp (buff, "UL") == 0)
-    if (!(s = get_token (buff, sizeof (buff), s))) return;
-
-  /* comma */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
-
-  if (Debug) fprintf (stderr, "%s: Expecting default value.\n", Progname);
-
-  /* <default value> or UL <default value> */
-  if (!(s = get_token (buff, sizeof (buff), s))) return;
-  if (strcmp (buff, "UL") == 0)
-  {
-    if (Debug) fprintf (stderr, "%s: Skipping UL.\n", Progname);
-    if (!(s = get_token (buff, sizeof (buff), s))) return;
-  }
-
-  memset (tmp, 0, sizeof (tmp));
+         if (!(onl & D_NL))
+           fputs ("\n# ", out);
+         fputs ("\n# ", out);
+         docstat |= D_NP;
+         break;
+       }
+       case SP_START_TAB:
+       {
+         if (!onl)
+           fputs ("\n# ", out);
+         docstat |= D_TAB;
+         break;
+       }
+       case SP_END_TAB:
+       {
+         docstat &= ~D_TAB;
+         docstat |= D_NL;
+         break;
+       }
+       case SP_START_DL:
+       {
+         docstat |= D_DL;
+         break;
+       }
+       case SP_DT:
+       {
+         Continuation = 0;
+         docstat |= D_DT;
+         break;
+       }
+       case SP_DD:
+       {
+         if (docstat & D_IL)
+           fputs ("- ", out);
+         Continuation = 0;
+         break;
+       }
+       case SP_END_DL:
+       {
+         Continuation = 0;
+         docstat &= ~D_DL;
+         break;
+       }
+       case SP_START_IL:
+       {
+         docstat |= D_IL;
+         break;
+       }
+       case SP_END_IL:
+       {
+         Continuation = 0;
+         docstat &= ~D_IL;
+         break;
+       }
+       case SP_STR:
+       {
+         if (Continuation)
+         {
+           Continuation = 0;
+           fputs ("        ", out);
+         }
+         fputs (str, out);
+         if (docstat & D_DT)
+         {
+           int i;
 
-  do
-  {
-    if (strcmp (buff, "}") == 0)
+           for (i = strlen (str) ; i < 8 ; i++)
+             putc (' ', out);
+           docstat &= ~D_DT;
+           docstat |= D_NL;
+         }
+         break;
+       }
+      }
       break;
+    }
 
-    strncpy (tmp + strlen (tmp), buff, sizeof (tmp) - strlen (tmp));
-  }
-  while ((s = get_token (buff, sizeof (buff), s)));
-
-  pretty_default (val, sizeof (val), tmp, type);
-  print_confline (varname, type, val, out);
-}
+    /* manual page */
+    case F_MAN:
+    {
+      switch (special)
+      {
+       case SP_END_FT:
+       {
+         fputs ("\\fP", out);
+         docstat &= ~(D_EM|D_BF|D_TT);
+         break;
+       }
+       case SP_START_BF:
+       {
+         fputs ("\\fB", out);
+         docstat |= D_BF;
+         docstat &= ~(D_EM|D_TT);
+         break;
+       }
+       case SP_START_EM:
+       {
+         fputs ("\\fI", out);
+         docstat |= D_EM;
+         docstat &= ~(D_BF|D_TT);
+         break;
+       }
+        case SP_START_TT:
+       {
+         fputs ("\\fC", out);
+         docstat |= D_TT;
+         docstat &= ~(D_BF|D_EM);
+         break;
+        }
+       case SP_NEWLINE:
+       {
+         if (onl)
+           docstat |= onl;
+         else
+         {
+           fputc ('\n', out);
+           docstat |= D_NL;
+         }
+         break;
+       }
+       case SP_NEWPAR:
+       {
+         if (onl & D_NP)
+         {
+           docstat |= onl;
+           break;
+         }
 
-static void pretty_default (char *t, size_t l, const char *s, int type)
-{
-  memset (t, 0, l);
-  l--;
+         if (!(onl & D_NL))
+           fputc ('\n', out);
+         fputs (".IP\n", out);
 
-  switch (type)
-  {
-    case DT_QUAD:
-    {
-      if (strcasecmp (s, "MUTT_YES") == 0) strncpy (t, "yes", l);
-      else if (strcasecmp (s, "MUTT_NO") == 0) strncpy (t, "no", l);
-      else if (strcasecmp (s, "MUTT_ASKYES") == 0) strncpy (t, "ask-yes", l);
-      else if (strcasecmp (s, "MUTT_ASKNO") == 0) strncpy (t, "ask-no", l);
+         docstat |= D_NP;
+         break;
+       }
+       case SP_START_TAB:
+       {
+         fputs ("\n.IP\n.EX\n", out);
+         docstat |= D_TAB | D_NL;
+         break;
+       }
+       case SP_END_TAB:
+       {
+         fputs ("\n.EE\n", out);
+         docstat &= ~D_TAB;
+         docstat |= D_NL;
+         break;
+       }
+       case SP_START_DL:
+       {
+         fputs (".RS\n.PD 0\n", out);
+         docstat |= D_DL;
+         break;
+       }
+       case SP_DT:
+       {
+         fputs (".TP\n", out);
+         break;
+       }
+       case SP_DD:
+       {
+         if (docstat & D_IL)
+           fputs (".TP\n\\(hy ", out);
+         else
+           fputs ("\n", out);
+         break;
+       }
+       case SP_END_DL:
+       {
+         fputs (".RE\n.PD 1", out);
+         docstat &= ~D_DL;
+         break;
+       }
+       case SP_START_IL:
+       {
+         fputs (".RS\n.PD 0\n", out);
+         docstat |= D_IL;
+         break;
+       }
+       case SP_END_IL:
+       {
+         fputs (".RE\n.PD 1", out);
+         docstat &= ~D_DL;
+         break;
+       }
+       case SP_STR:
+       {
+         while (*str)
+         {
+           for (; *str; str++)
+           {
+             if (*str == '"')
+               fputs ("\"", out);
+             else if (*str == '\\')
+               fputs ("\\\\", out);
+              else if (*str == '-')
+                fputs ("\\-", out);
+             else if (strncmp (str, "``", 2) == 0)
+             {
+               fputs ("\\(lq", out);
+               str++;
+             }
+             else if (strncmp (str, "''", 2) == 0)
+             {
+               fputs ("\\(rq", out);
+               str++;
+             }
+             else
+               fputc (*str, out);
+           }
+         }
+         break;
+       }
+      }
       break;
     }
-    case DT_BOOL:
+
+    /* SGML based manual */
+    case F_SGML:
     {
-      if (atoi (s))
-       strncpy (t, "yes", l);
-      else
-       strncpy (t, "no", l);
-      break;
-    }
-    case DT_SORT:
-    {
-      /* heuristic! */
-      if (strncmp (s, "SORT_", 5) != 0)
-        fprintf (stderr,
-                 "WARNING: expected prefix of SORT_ for type DT_SORT instead of %s\n", s);
-      strncpy (t, s + 5, l);
-      for (; *t; t++) *t = tolower ((unsigned char) *t);
-      break;
-    }
-    case DT_MAGIC:
-    {
-      /* heuristic! */
-      if (strncmp (s, "MUTT_", 5) != 0)
-        fprintf (stderr,
-                 "WARNING: expected prefix of MUTT_ for type DT_MAGIC instead of %s\n", s);
-      strncpy (t, s + 5, l);
-      for (; *t; t++) *t = tolower ((unsigned char) *t);
+      switch (special)
+      {
+       case SP_END_FT:
+       {
+         if (docstat & D_EM) fputs ("</emphasis>", out);
+         if (docstat & D_BF) fputs ("</emphasis>", out);
+          if (docstat & D_TT) fputs ("</literal>", out);
+         docstat &= ~(D_EM|D_BF|D_TT);
+         break;
+       }
+       case SP_START_BF:
+       {
+         fputs ("<emphasis role=\"bold\">", out);
+         docstat |= D_BF;
+         docstat &= ~(D_EM|D_TT);
+         break;
+       }
+       case SP_START_EM:
+       {
+         fputs ("<emphasis>", out);
+         docstat |= D_EM;
+         docstat &= ~(D_BF|D_TT);
+         break;
+       }
+        case SP_START_TT:
+       {
+         fputs ("<literal>", out);
+         docstat |= D_TT;
+         docstat &= ~(D_BF|D_EM);
+         break;
+        }
+       case SP_NEWLINE:
+       {
+         if (onl)
+           docstat |= onl;
+         else
+         {
+           fputc ('\n', out);
+           docstat |= D_NL;
+         }
+         break;
+       }
+       case SP_NEWPAR:
+       {
+         if (onl & D_NP)
+         {
+           docstat |= onl;
+           break;
+         }
+
+         if (!(onl & D_NL))
+           fputc ('\n', out);
+         if (docstat & D_PA)
+           fputs("</para>\n", out);
+         fputs ("<para>\n", out);
+
+         docstat |= D_NP;
+         docstat |= D_PA;
+
+         break;
+       }
+        case SP_END_PAR:
+        {
+         fputs ("</para>\n", out);
+         docstat &= ~D_PA;
+         break;
+        }
+       case SP_START_TAB:
+       {
+         if (docstat & D_PA)
+         {
+           fputs ("\n</para>\n", out);
+           docstat &= ~D_PA;
+         }
+         fputs ("\n<screen>\n", out);
+         docstat |= D_TAB | D_NL;
+         break;
+       }
+       case SP_END_TAB:
+       {
+         fputs ("</screen>", out);
+         docstat &= ~D_TAB;
+         docstat |= D_NL;
+         break;
+       }
+       case SP_START_DL:
+       {
+         if (docstat & D_PA)
+         {
+           fputs ("\n</para>\n", out);
+           docstat &= ~D_PA;
+         }
+         fputs ("\n<informaltable>\n<tgroup cols=\"2\">\n<tbody>\n", out);
+         docstat |= D_DL;
+         break;
+       }
+       case SP_DT:
+       {
+         fputs ("<row><entry>", out);
+         break;
+       }
+       case SP_DD:
+       {
+         docstat |= D_DD;
+         if (docstat & D_DL)
+           fputs("</entry><entry>", out);
+         else
+           fputs ("<listitem><para>", out);
+         break;
+       }
+        case SP_END_DD:
+        {
+         if (docstat & D_DL)
+           fputs ("</entry></row>\n", out);
+         else
+           fputs ("</para></listitem>", out);
+         docstat &= ~D_DD;
+         break;
+        }
+       case SP_END_DL:
+       {
+         fputs ("</entry></row></tbody></tgroup></informaltable>\n", out);
+         docstat &= ~(D_DD|D_DL);
+         break;
+       }
+       case SP_START_IL:
+       {
+         if (docstat & D_PA)
+         {
+           fputs ("\n</para>\n", out);
+           docstat &= ~D_PA;
+         }
+         fputs ("\n<itemizedlist>\n", out);
+         docstat |= D_IL;
+         break;
+       }
+       case SP_END_IL:
+       {
+         fputs ("</para></listitem></itemizedlist>\n", out);
+         docstat &= ~(D_DD|D_DL);
+         break;
+       }
+        case SP_END_SECT:
+        {
+         fputs ("</sect2>", out);
+         break;
+        }
+       case SP_STR:
+       {
+         if (docstat & D_TAB)
+           sgml_fputs (str, out);
+         else
+         {
+           while (*str)
+           {
+             for (; *str; str++)
+             {
+               if (strncmp (str, "``", 2) == 0)
+               {
+                 fputs ("<quote>", out);
+                 str++;
+               }
+               else if (strncmp (str, "''", 2) == 0)
+               {
+                 fputs ("</quote>", out);
+                 str++;
+               }
+               else
+                 sgml_fputc (*str, out);
+             }
+           }
+         }
+         break;
+       }
+      }
       break;
     }
-    case DT_STR:
-    case DT_RX:
-    case DT_ADDR:
-    case DT_PATH:
-    case DT_MBCHARTBL:
-    {
-      if (strcmp (s, "0") == 0)
-       break;
-      /* fallthrough */
-    }
+    /* make gcc happy (unreached) */
     default:
-    {
-      strncpy (t, s, l);
       break;
-    }
   }
+
+  return docstat;
 }
 
-static void char_to_escape (char *dest, unsigned int c)
+/* close eventually-open environments. */
+
+static int fd_recurse = 0;
+
+static int flush_doc (int docstat, FILE *out)
 {
-  switch (c)
+  if (docstat & D_INIT)
+    return D_INIT;
+
+  if (fd_recurse++)
   {
-    case '\r': strcpy (dest, "\\r"); break;    /* __STRCPY_CHECKED__ */
-    case '\n': strcpy (dest, "\\n"); break;    /* __STRCPY_CHECKED__ */
-    case '\t': strcpy (dest, "\\t"); break;    /* __STRCPY_CHECKED__ */
-    case '\f': strcpy (dest, "\\f"); break;    /* __STRCPY_CHECKED__ */
-    default: sprintf (dest, "\\%03o", c); break;
+    fprintf (stderr, "%s: Internal error, recursion in flush_doc()!\n", Progname);
+    exit (1);
   }
-}
-static void conf_char_to_escape (unsigned int c , FILE *out)
-{
-  char buff[16];
-  char_to_escape (buff, c);
-  fputs (buff, out);
-}
 
-static void conf_print_strval (const char *v, FILE *out)
-{
-  for (; *v; v++)
-  {
-    if (*v < ' ' || *v & 0x80)
-    {
-      conf_char_to_escape ((unsigned int) *v, out);
-      continue;
-    }
+  if (docstat & (D_PA))
+    docstat = print_it (SP_END_PAR, NULL, out, docstat);
 
-    if (*v == '"'  || *v == '\\')
-      fputc ('\\', out);
-    fputc (*v, out);
-  }
-}
+  if (docstat & (D_TAB))
+    docstat = print_it (SP_END_TAB, NULL, out, docstat);
 
-static void man_print_strval (const char *v, FILE *out)
-{
-  for (; *v; v++)
-  {
-    if (*v < ' ' || *v & 0x80)
-    {
-      fputc ('\\', out);
-      conf_char_to_escape ((unsigned int) *v, out);
-      continue;
-    }
-
-    if (*v == '"')
-      fputs ("\"", out);
-    else if (*v == '\\')
-      fputs ("\\\\", out);
-    else if (*v == '-')
-      fputs ("\\-", out);
-    else
-      fputc (*v, out);
-  }
-}
+  if (docstat & (D_DL))
+    docstat = print_it (SP_END_DL, NULL, out, docstat);
 
-static void sgml_print_strval (const char *v, FILE *out)
-{
-  char buff[16];
-  for (; *v; v++)
-  {
-    if (*v <  ' ' || *v & 0x80)
-    {
-      char_to_escape (buff, (unsigned int) *v);
-      sgml_fputs (buff, out);
-      continue;
-    }
-    sgml_fputc ((unsigned int) *v, out);
-  }
-}
+  if (docstat & (D_EM | D_BF | D_TT))
+    docstat = print_it (SP_END_FT, NULL, out, docstat);
 
-static int sgml_fputc (int c, FILE *out)
-{
-  switch (c)
-  {
-    /* the bare minimum for escaping */
-    case '<': return fputs ("&lt;", out);
-    case '>': return fputs ("&gt;", out);
-    case '&': return fputs ("&amp;", out);
-    default:  return fputc (c, out);
-  }
-}
+  docstat = print_it (SP_END_SECT, NULL, out, docstat);
 
-static int sgml_fputs (const char *s, FILE *out)
-{
-  for (; *s; s++)
-    if (sgml_fputc ((unsigned int) *s, out) == EOF)
-      return EOF;
+  docstat = print_it (SP_NEWLINE, NULL, out, 0);
 
-  return 0;
+  fd_recurse--;
+  return D_INIT;
 }
 
-/* reduce CDATA to ID */
-static int sgml_id_fputs (const char *s, FILE* out)
+static int commit_buff (char *buff, char **d, FILE *out, int docstat)
 {
-  char id;
-
-  if (*s == '<')
-    s++;
-
-  for (; *s; s++)
+  if (*d > buff)
   {
-    if (*s == '_')
-      id = '-';
-    else
-      id = *s;
-    if (*s == '>' && !*(s+1))
-      break;
-
-    if (fputc ((unsigned int) id, out) == EOF)
-      return EOF;
+    **d = '\0';
+    docstat = print_it (SP_STR, buff, out, docstat);
+    *d = buff;
   }
 
-  return 0;
-}
-
-static void print_confline (const char *varname, int type, const char *val, FILE *out)
-{
-  if (type == DT_SYN) return;
-
-  switch (OutputFormat)
-  {
-    /* configuration file */
-    case F_CONF:
-    {
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
-          type == DT_MBCHARTBL)
-      {
-       fprintf (out, "\n# set %s=\"", varname);
-       conf_print_strval (val, out);
-       fputs ("\"", out);
-      }
-      else if (type != DT_SYN)
-       fprintf (out, "\n# set %s=%s", varname, val);
-
-      fprintf (out, "\n#\n# Name: %s", varname);
-      fprintf (out, "\n# Type: %s", type2human (type));
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
-          type == DT_MBCHARTBL)
-      {
-       fputs ("\n# Default: \"", out);
-       conf_print_strval (val, out);
-       fputs ("\"", out);
-      }
-      else
-       fprintf (out, "\n# Default: %s", val);
-
-      fputs ("\n# ", out);
-      break;
-    }
-
-    /* manual page */
-    case F_MAN:
-    {
-      fprintf (out, "\n.TP\n.B %s\n", varname);
-      fputs (".nf\n", out);
-      fprintf (out, "Type: %s\n", type2human (type));
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
-          type == DT_MBCHARTBL)
-      {
-       fputs ("Default: \"", out);
-       man_print_strval (val, out);
-       fputs ("\"\n", out);
-      }
-      else {
-       fputs ("Default: ", out);
-       man_print_strval (val, out);
-       fputs ("\n", out);
-      }
-
-      fputs (".fi", out);
-
-      break;
-    }
-
-    /* SGML based manual */
-    case F_SGML:
-    {
-      fputs ("\n<sect2 id=\"", out);
-      sgml_id_fputs(varname, out);
-      fputs ("\">\n<title>", out);
-      sgml_fputs (varname, out);
-      fprintf (out, "</title>\n<literallayout>Type: %s", type2human (type));
-
-
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
-          type == DT_MBCHARTBL)
-      {
-       if (val && *val)
-       {
-         fputs ("\nDefault: <quote><literal>", out);
-         sgml_print_strval (val, out);
-         fputs ("</literal></quote>", out);
-       }
-       else
-       {
-         fputs ("\nDefault: (empty)", out);
-       }
-       fputs ("</literallayout>\n", out);
-      }
-      else
-       fprintf (out, "\nDefault: %s</literallayout>\n", val);
-      break;
-    }
-    /* make gcc happy */
-    default:
-      break;
-  }
+  return docstat;
 }
 
 /**
@@ -767,644 +747,648 @@ static void print_confline (const char *varname, int type, const char *val, FILE
  **   This is used to protect indentations in tables.
  **/
 
-/* close eventually-open environments. */
-
-static int fd_recurse = 0;
-
-static int flush_doc (int docstat, FILE *out)
+/* reduce CDATA to ID */
+static int sgml_id_fputs (const char *s, FILE* out)
 {
-  if (docstat & D_INIT)
-    return D_INIT;
-
-  if (fd_recurse++)
-  {
-    fprintf (stderr, "%s: Internal error, recursion in flush_doc()!\n", Progname);
-    exit (1);
-  }
+  char id;
 
-  if (docstat & (D_PA))
-    docstat = print_it (SP_END_PAR, NULL, out, docstat);
+  if (*s == '<')
+    s++;
 
-  if (docstat & (D_TAB))
-    docstat = print_it (SP_END_TAB, NULL, out, docstat);
+  for (; *s; s++)
+  {
+    if (*s == '_')
+      id = '-';
+    else
+      id = *s;
+    if (*s == '>' && !*(s+1))
+      break;
 
-  if (docstat & (D_DL))
-    docstat = print_it (SP_END_DL, NULL, out, docstat);
+    if (fputc ((unsigned int) id, out) == EOF)
+      return EOF;
+  }
 
-  if (docstat & (D_EM | D_BF | D_TT))
-    docstat = print_it (SP_END_FT, NULL, out, docstat);
+  return 0;
+}
 
-  docstat = print_it (SP_END_SECT, NULL, out, docstat);
+void print_ref (FILE *out, int output_dollar, const char *ref)
+{
+  switch (OutputFormat)
+  {
+  case F_CONF:
+  case F_MAN:
+    if (output_dollar)
+      putc ('$', out);
+    fputs (ref, out);
+    break;
 
-  docstat = print_it (SP_NEWLINE, NULL, out, 0);
+  case F_SGML:
+    fputs ("<link linkend=\"", out);
+    sgml_id_fputs (ref, out);
+    fputs ("\">", out);
+    if (output_dollar)
+      fputc ('$', out);
+    sgml_fputs (ref, out);
+    fputs ("</link>", out);
+    break;
 
-  fd_recurse--;
-  return D_INIT;
+  default:
+    break;
+  }
 }
 
-/* print something. */
-
-static int print_it (int special, char *str, FILE *out, int docstat)
+static int handle_docline (char *l, FILE *out, int docstat)
 {
-  int onl = docstat & (D_NL|D_NP);
+  char buff[BUFFSIZE];
+  char *s = NULL, *d = NULL;
+  l = skip_ws (l);
 
-  docstat &= ~(D_NL|D_NP|D_INIT);
+  if (Debug)
+    fprintf (stderr, "%s: handle_docline `%s'\n", Progname, l);
 
-  switch (OutputFormat)
-  {
-    /* configuration file */
-    case F_CONF:
+  if (strncmp (l, ".pp", 3) == 0)
+    return print_it (SP_NEWPAR, NULL, out, docstat);
+  else if (strncmp (l, ".ts", 3) == 0)
+    return print_it (SP_START_TAB, NULL, out, docstat);
+  else if (strncmp (l, ".te", 3) == 0)
+    return print_it (SP_END_TAB, NULL, out, docstat);
+  else if (strncmp (l, ".dl", 3) == 0)
+    return print_it (SP_START_DL, NULL, out, docstat);
+  else if (strncmp (l, ".de", 3) == 0)
+    return print_it (SP_END_DL, NULL, out, docstat);
+  else if (strncmp (l, ".il", 3) == 0)
+    return print_it (SP_START_IL, NULL, out, docstat);
+  else if (strncmp (l, ".ie", 3) == 0)
+    return print_it (SP_END_IL, NULL, out, docstat);
+  else if (strncmp (l, ". ", 2) == 0)
+    *l = ' ';
+
+  for (s = l, d = buff; *s; s++)
+  {
+    if (strncmp (s, "\\(as", 4) == 0)
     {
-      switch (special)
+      *d++ = '*';
+      s += 3;
+    }
+    else if (strncmp (s, "\\(rs", 4) == 0)
+    {
+      *d++ = '\\';
+      s += 3;
+    }
+    else if (strncmp (s, "\\fI", 3) == 0)
+    {
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_START_EM, NULL, out, docstat);
+      s += 2;
+    }
+    else if (strncmp (s, "\\fB", 3) == 0)
+    {
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_START_BF, NULL, out, docstat);
+      s += 2;
+    }
+    else if (strncmp (s, "\\fC", 3) == 0)
+    {
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_START_TT, NULL, out, docstat);
+      s += 2;
+    }
+    else if (strncmp (s, "\\fP", 3) == 0)
+    {
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_END_FT, NULL, out, docstat);
+      s += 2;
+    }
+    else if (strncmp (s, ".dt", 3) == 0)
+    {
+      if (docstat & D_DD)
       {
-       static int Continuation = 0;
-
-       case SP_END_FT: docstat &= ~(D_EM|D_BF|D_TT); break;
-       case SP_START_BF: docstat |= D_BF; break;
-       case SP_START_EM: docstat |= D_EM; break;
-        case SP_START_TT: docstat |= D_TT; break;
-       case SP_NEWLINE:
-       {
-         if (onl)
-           docstat |= onl;
-         else
-         {
-           fputs ("\n# ", out);
-           docstat |= D_NL;
-         }
-         if (docstat & D_DL)
-           ++ Continuation;
-         break;
-       }
-       case SP_NEWPAR:
-       {
-         if (onl & D_NP)
-         {
-           docstat |= onl;
-           break;
-         }
-
-         if (!(onl & D_NL))
-           fputs ("\n# ", out);
-         fputs ("\n# ", out);
-         docstat |= D_NP;
-         break;
-       }
-       case SP_START_TAB:
-       {
-         if (!onl)
-           fputs ("\n# ", out);
-         docstat |= D_TAB;
-         break;
-       }
-       case SP_END_TAB:
-       {
-         docstat &= ~D_TAB;
-         docstat |= D_NL;
-         break;
-       }
-       case SP_START_DL:
-       {
-         docstat |= D_DL;
-         break;
-       }
-       case SP_DT:
-       {
-         Continuation = 0;
-         docstat |= D_DT;
-         break;
-       }
-       case SP_DD:
-       {
-         if (docstat & D_IL)
-           fputs ("- ", out);
-         Continuation = 0;
-         break;
-       }
-       case SP_END_DL:
-       {
-         Continuation = 0;
-         docstat &= ~D_DL;
-         break;
-       }
-       case SP_START_IL:
-       {
-         docstat |= D_IL;
-         break;
-       }
-       case SP_END_IL:
-       {
-         Continuation = 0;
-         docstat &= ~D_IL;
-         break;
-       }
-       case SP_STR:
-       {
-         if (Continuation)
-         {
-           Continuation = 0;
-           fputs ("        ", out);
-         }
-         fputs (str, out);
-         if (docstat & D_DT)
-         {
-           int i;
-
-           for (i = strlen (str) ; i < 8 ; i++)
-             putc (' ', out);
-           docstat &= ~D_DT;
-           docstat |= D_NL;
-         }
-         break;
-       }
+       docstat = commit_buff (buff, &d, out, docstat);
+       docstat = print_it (SP_END_DD, NULL, out, docstat);
       }
-      break;
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_DT, NULL, out, docstat);
+      s += 3;
     }
-
-    /* manual page */
-    case F_MAN:
+    else if (strncmp (s, ".dd", 3) == 0)
     {
-      switch (special)
+      if ((docstat & D_IL) && (docstat & D_DD))
       {
-       case SP_END_FT:
-       {
-         fputs ("\\fP", out);
-         docstat &= ~(D_EM|D_BF|D_TT);
-         break;
-       }
-       case SP_START_BF:
-       {
-         fputs ("\\fB", out);
-         docstat |= D_BF;
-         docstat &= ~(D_EM|D_TT);
-         break;
-       }
-       case SP_START_EM:
-       {
-         fputs ("\\fI", out);
-         docstat |= D_EM;
-         docstat &= ~(D_BF|D_TT);
-         break;
-       }
-        case SP_START_TT:
-       {
-         fputs ("\\fC", out);
-         docstat |= D_TT;
-         docstat &= ~(D_BF|D_EM);
-         break;
-        }
-       case SP_NEWLINE:
-       {
-         if (onl)
-           docstat |= onl;
-         else
-         {
-           fputc ('\n', out);
-           docstat |= D_NL;
-         }
-         break;
-       }
-       case SP_NEWPAR:
-       {
-         if (onl & D_NP)
-         {
-           docstat |= onl;
-           break;
-         }
+       docstat = commit_buff (buff, &d, out, docstat);
+       docstat = print_it (SP_END_DD, NULL, out, docstat);
+      }
+      docstat = commit_buff (buff, &d, out, docstat);
+      docstat = print_it (SP_DD, NULL, out, docstat);
+      s += 3;
+    }
+    else if (*s == '$')
+    {
+      int output_dollar = 0;
+      char *ref = NULL;
+      char save;
 
-         if (!(onl & D_NL))
-           fputc ('\n', out);
-         fputs (".IP\n", out);
+      ++s;
+      if (*s == '$')
+      {
+       output_dollar = 1;
+       ++s;
+      }
+      if (*s == '$')
+      {
+       *d++ = '$';
+      }
+      else
+      {
+       ref = s;
+       while (isalnum ((unsigned char) *s) || (*s && strchr("-_<>", *s)))
+         ++s;
 
-         docstat |= D_NP;
-         break;
-       }
-       case SP_START_TAB:
-       {
-         fputs ("\n.IP\n.EX\n", out);
-         docstat |= D_TAB | D_NL;
-         break;
-       }
-       case SP_END_TAB:
-       {
-         fputs ("\n.EE\n", out);
-         docstat &= ~D_TAB;
-         docstat |= D_NL;
-         break;
-       }
-       case SP_START_DL:
-       {
-         fputs (".RS\n.PD 0\n", out);
-         docstat |= D_DL;
-         break;
-       }
-       case SP_DT:
-       {
-         fputs (".TP\n", out);
-         break;
-       }
-       case SP_DD:
-       {
-         if (docstat & D_IL)
-           fputs (".TP\n\\(hy ", out);
-         else
-           fputs ("\n", out);
-         break;
-       }
-       case SP_END_DL:
-       {
-         fputs (".RE\n.PD 1", out);
-         docstat &= ~D_DL;
-         break;
-       }
-       case SP_START_IL:
-       {
-         fputs (".RS\n.PD 0\n", out);
-         docstat |= D_IL;
-         break;
-       }
-       case SP_END_IL:
-       {
-         fputs (".RE\n.PD 1", out);
-         docstat &= ~D_DL;
-         break;
-       }
-       case SP_STR:
-       {
-         while (*str)
-         {
-           for (; *str; str++)
-           {
-             if (*str == '"')
-               fputs ("\"", out);
-             else if (*str == '\\')
-               fputs ("\\\\", out);
-              else if (*str == '-')
-                fputs ("\\-", out);
-             else if (strncmp (str, "``", 2) == 0)
-             {
-               fputs ("\\(lq", out);
-               str++;
-             }
-             else if (strncmp (str, "''", 2) == 0)
-             {
-               fputs ("\\(rq", out);
-               str++;
-             }
-             else
-               fputc (*str, out);
-           }
-         }
-         break;
-       }
+       docstat = commit_buff (buff, &d, out, docstat);
+       save = *s;
+       *s = 0;
+       print_ref (out, output_dollar, ref);
+       *s = save;
+       --s;
+      }
+    }
+    else
+      *d++ = *s;
+  }
+
+  docstat = commit_buff (buff, &d, out, docstat);
+  return print_it (SP_NEWLINE, NULL, out, docstat);
+}
+
+/* note: the following enum must be in the same order as the
+ * following string definitions!
+ */
+
+enum
+{
+  DT_NONE = 0,
+  DT_BOOL,
+  DT_NUM,
+  DT_STR,
+  DT_PATH,
+  DT_QUAD,
+  DT_SORT,
+  DT_RX,
+  DT_MAGIC,
+  DT_SYN,
+  DT_ADDR,
+  DT_MBCHARTBL
+};
+
+struct
+{
+  char *machine;
+  char *human;
+}
+types[] =
+{
+  { "DT_NONE", "-none-"        },
+  { "DT_BOOL",  "boolean"      },
+  { "DT_NUM",   "number"       },
+  { "DT_STR",  "string"        },
+  { "DT_PATH", "path"          },
+  { "DT_QUAD", "quadoption"    },
+  { "DT_SORT", "sort order"    },
+  { "DT_RX",   "regular expression" },
+  { "DT_MAGIC",        "folder magic" },
+  { "DT_SYN",  NULL },
+  { "DT_ADDR", "e-mail address" },
+  { "DT_MBCHARTBL", "string"   },
+  { NULL, NULL }
+};
+
+static int buff2type (const char *s)
+{
+  int type;
+
+  for (type = DT_NONE; types[type].machine; type++)
+    if (strcmp (types[type].machine, s) == 0)
+       return type;
+
+  return DT_NONE;
+}
+
+static void pretty_default (char *t, size_t l, const char *s, int type)
+{
+  memset (t, 0, l);
+  l--;
+
+  switch (type)
+  {
+    case DT_QUAD:
+    {
+      if (strcasecmp (s, "MUTT_YES") == 0) strncpy (t, "yes", l);
+      else if (strcasecmp (s, "MUTT_NO") == 0) strncpy (t, "no", l);
+      else if (strcasecmp (s, "MUTT_ASKYES") == 0) strncpy (t, "ask-yes", l);
+      else if (strcasecmp (s, "MUTT_ASKNO") == 0) strncpy (t, "ask-no", l);
+      break;
+    }
+    case DT_BOOL:
+    {
+      if (atoi (s))
+       strncpy (t, "yes", l);
+      else
+       strncpy (t, "no", l);
+      break;
+    }
+    case DT_SORT:
+    {
+      /* heuristic! */
+      if (strncmp (s, "SORT_", 5) != 0)
+        fprintf (stderr,
+                 "WARNING: expected prefix of SORT_ for type DT_SORT instead of %s\n", s);
+      strncpy (t, s + 5, l);
+      for (; *t; t++) *t = tolower ((unsigned char) *t);
+      break;
+    }
+    case DT_MAGIC:
+    {
+      /* heuristic! */
+      if (strncmp (s, "MUTT_", 5) != 0)
+        fprintf (stderr,
+                 "WARNING: expected prefix of MUTT_ for type DT_MAGIC instead of %s\n", s);
+      strncpy (t, s + 5, l);
+      for (; *t; t++) *t = tolower ((unsigned char) *t);
+      break;
+    }
+    case DT_STR:
+    case DT_RX:
+    case DT_ADDR:
+    case DT_PATH:
+    case DT_MBCHARTBL:
+    {
+      if (strcmp (s, "0") == 0)
+       break;
+      /* fallthrough */
+    }
+    default:
+    {
+      strncpy (t, s, l);
+      break;
+    }
+  }
+}
+
+static void char_to_escape (char *dest, unsigned int c)
+{
+  switch (c)
+  {
+    case '\r': strcpy (dest, "\\r"); break;    /* __STRCPY_CHECKED__ */
+    case '\n': strcpy (dest, "\\n"); break;    /* __STRCPY_CHECKED__ */
+    case '\t': strcpy (dest, "\\t"); break;    /* __STRCPY_CHECKED__ */
+    case '\f': strcpy (dest, "\\f"); break;    /* __STRCPY_CHECKED__ */
+    default: sprintf (dest, "\\%03o", c); break;
+  }
+}
+
+static void conf_char_to_escape (unsigned int c , FILE *out)
+{
+  char buff[16];
+  char_to_escape (buff, c);
+  fputs (buff, out);
+}
+
+static void conf_print_strval (const char *v, FILE *out)
+{
+  for (; *v; v++)
+  {
+    if (*v < ' ' || *v & 0x80)
+    {
+      conf_char_to_escape ((unsigned int) *v, out);
+      continue;
+    }
+
+    if (*v == '"'  || *v == '\\')
+      fputc ('\\', out);
+    fputc (*v, out);
+  }
+}
+
+static const char *type2human (int type)
+{
+  return types[type].human;
+}
+
+/**
+ ** Configuration line parser
+ **
+ ** The following code parses a line from init.h which declares
+ ** a configuration variable.
+ **
+ **/
+
+static void man_print_strval (const char *v, FILE *out)
+{
+  for (; *v; v++)
+  {
+    if (*v < ' ' || *v & 0x80)
+    {
+      fputc ('\\', out);
+      conf_char_to_escape ((unsigned int) *v, out);
+      continue;
+    }
+
+    if (*v == '"')
+      fputs ("\"", out);
+    else if (*v == '\\')
+      fputs ("\\\\", out);
+    else if (*v == '-')
+      fputs ("\\-", out);
+    else
+      fputc (*v, out);
+  }
+}
+
+static void sgml_print_strval (const char *v, FILE *out)
+{
+  char buff[16];
+  for (; *v; v++)
+  {
+    if (*v <  ' ' || *v & 0x80)
+    {
+      char_to_escape (buff, (unsigned int) *v);
+      sgml_fputs (buff, out);
+      continue;
+    }
+    sgml_fputc ((unsigned int) *v, out);
+  }
+}
+
+static void print_confline (const char *varname, int type, const char *val, FILE *out)
+{
+  if (type == DT_SYN) return;
+
+  switch (OutputFormat)
+  {
+    /* configuration file */
+    case F_CONF:
+    {
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
+          type == DT_MBCHARTBL)
+      {
+       fprintf (out, "\n# set %s=\"", varname);
+       conf_print_strval (val, out);
+       fputs ("\"", out);
+      }
+      else if (type != DT_SYN)
+       fprintf (out, "\n# set %s=%s", varname, val);
+
+      fprintf (out, "\n#\n# Name: %s", varname);
+      fprintf (out, "\n# Type: %s", type2human (type));
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
+          type == DT_MBCHARTBL)
+      {
+       fputs ("\n# Default: \"", out);
+       conf_print_strval (val, out);
+       fputs ("\"", out);
       }
+      else
+       fprintf (out, "\n# Default: %s", val);
+
+      fputs ("\n# ", out);
       break;
     }
 
-    /* SGML based manual */
-    case F_SGML:
+    /* manual page */
+    case F_MAN:
     {
-      switch (special)
+      fprintf (out, "\n.TP\n.B %s\n", varname);
+      fputs (".nf\n", out);
+      fprintf (out, "Type: %s\n", type2human (type));
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
+          type == DT_MBCHARTBL)
       {
-       case SP_END_FT:
-       {
-         if (docstat & D_EM) fputs ("</emphasis>", out);
-         if (docstat & D_BF) fputs ("</emphasis>", out);
-          if (docstat & D_TT) fputs ("</literal>", out);
-         docstat &= ~(D_EM|D_BF|D_TT);
-         break;
-       }
-       case SP_START_BF:
-       {
-         fputs ("<emphasis role=\"bold\">", out);
-         docstat |= D_BF;
-         docstat &= ~(D_EM|D_TT);
-         break;
-       }
-       case SP_START_EM:
-       {
-         fputs ("<emphasis>", out);
-         docstat |= D_EM;
-         docstat &= ~(D_BF|D_TT);
-         break;
-       }
-        case SP_START_TT:
-       {
-         fputs ("<literal>", out);
-         docstat |= D_TT;
-         docstat &= ~(D_BF|D_EM);
-         break;
-        }
-       case SP_NEWLINE:
-       {
-         if (onl)
-           docstat |= onl;
-         else
-         {
-           fputc ('\n', out);
-           docstat |= D_NL;
-         }
-         break;
-       }
-       case SP_NEWPAR:
-       {
-         if (onl & D_NP)
-         {
-           docstat |= onl;
-           break;
-         }
+       fputs ("Default: \"", out);
+       man_print_strval (val, out);
+       fputs ("\"\n", out);
+      }
+      else {
+       fputs ("Default: ", out);
+       man_print_strval (val, out);
+       fputs ("\n", out);
+      }
 
-         if (!(onl & D_NL))
-           fputc ('\n', out);
-         if (docstat & D_PA)
-           fputs("</para>\n", out);
-         fputs ("<para>\n", out);
+      fputs (".fi", out);
 
-         docstat |= D_NP;
-         docstat |= D_PA;
+      break;
+    }
 
-         break;
-       }
-        case SP_END_PAR:
-        {
-         fputs ("</para>\n", out);
-         docstat &= ~D_PA;
-         break;
-        }
-       case SP_START_TAB:
-       {
-         if (docstat & D_PA)
-         {
-           fputs ("\n</para>\n", out);
-           docstat &= ~D_PA;
-         }
-         fputs ("\n<screen>\n", out);
-         docstat |= D_TAB | D_NL;
-         break;
-       }
-       case SP_END_TAB:
-       {
-         fputs ("</screen>", out);
-         docstat &= ~D_TAB;
-         docstat |= D_NL;
-         break;
-       }
-       case SP_START_DL:
-       {
-         if (docstat & D_PA)
-         {
-           fputs ("\n</para>\n", out);
-           docstat &= ~D_PA;
-         }
-         fputs ("\n<informaltable>\n<tgroup cols=\"2\">\n<tbody>\n", out);
-         docstat |= D_DL;
-         break;
-       }
-       case SP_DT:
-       {
-         fputs ("<row><entry>", out);
-         break;
-       }
-       case SP_DD:
-       {
-         docstat |= D_DD;
-         if (docstat & D_DL)
-           fputs("</entry><entry>", out);
-         else
-           fputs ("<listitem><para>", out);
-         break;
-       }
-        case SP_END_DD:
-        {
-         if (docstat & D_DL)
-           fputs ("</entry></row>\n", out);
-         else
-           fputs ("</para></listitem>", out);
-         docstat &= ~D_DD;
-         break;
-        }
-       case SP_END_DL:
-       {
-         fputs ("</entry></row></tbody></tgroup></informaltable>\n", out);
-         docstat &= ~(D_DD|D_DL);
-         break;
-       }
-       case SP_START_IL:
-       {
-         if (docstat & D_PA)
-         {
-           fputs ("\n</para>\n", out);
-           docstat &= ~D_PA;
-         }
-         fputs ("\n<itemizedlist>\n", out);
-         docstat |= D_IL;
-         break;
-       }
-       case SP_END_IL:
+    /* SGML based manual */
+    case F_SGML:
+    {
+      fputs ("\n<sect2 id=\"", out);
+      sgml_id_fputs(varname, out);
+      fputs ("\">\n<title>", out);
+      sgml_fputs (varname, out);
+      fprintf (out, "</title>\n<literallayout>Type: %s", type2human (type));
+
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == DT_PATH ||
+          type == DT_MBCHARTBL)
+      {
+       if (val && *val)
        {
-         fputs ("</para></listitem></itemizedlist>\n", out);
-         docstat &= ~(D_DD|D_DL);
-         break;
+         fputs ("\nDefault: <quote><literal>", out);
+         sgml_print_strval (val, out);
+         fputs ("</literal></quote>", out);
        }
-        case SP_END_SECT:
-        {
-         fputs ("</sect2>", out);
-         break;
-        }
-       case SP_STR:
+       else
        {
-         if (docstat & D_TAB)
-           sgml_fputs (str, out);
-         else
-         {
-           while (*str)
-           {
-             for (; *str; str++)
-             {
-               if (strncmp (str, "``", 2) == 0)
-               {
-                 fputs ("<quote>", out);
-                 str++;
-               }
-               else if (strncmp (str, "''", 2) == 0)
-               {
-                 fputs ("</quote>", out);
-                 str++;
-               }
-               else
-                 sgml_fputc (*str, out);
-             }
-           }
-         }
-         break;
+         fputs ("\nDefault: (empty)", out);
        }
+       fputs ("</literallayout>\n", out);
       }
+      else
+       fprintf (out, "\nDefault: %s</literallayout>\n", val);
       break;
     }
-    /* make gcc happy (unreached) */
+    /* make gcc happy */
     default:
       break;
   }
+}
+
+static void handle_confline (char *s, FILE *out)
+{
+  char varname[BUFFSIZE];
+  char buff[BUFFSIZE];
+  char tmp[BUFFSIZE];
+  int type;
+
+  char val[BUFFSIZE];
+
+  /* xxx - put this into an actual state machine? */
+
+  /* variable name */
+  if (!(s = get_token (varname, sizeof (varname), s))) return;
+
+  /* comma */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+
+  /* type */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+
+  type = buff2type (buff);
+
+  /* possibly a "|" or comma */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+
+  if (strcmp (buff, "|") == 0)
+  {
+    if (Debug) fprintf (stderr, "%s: Expecting <subtype> <comma>.\n", Progname);
+    /* ignore subtype and comma */
+    if (!(s = get_token (buff, sizeof (buff), s))) return;
+    if (!(s = get_token (buff, sizeof (buff), s))) return;
+  }
 
-  return docstat;
-}
+  /* redraw, comma */
 
-void print_ref (FILE *out, int output_dollar, const char *ref)
-{
-  switch (OutputFormat)
+  while (1)
   {
-  case F_CONF:
-  case F_MAN:
-    if (output_dollar)
-      putc ('$', out);
-    fputs (ref, out);
-    break;
+    if (!(s = get_token (buff, sizeof (buff), s))) return;
+    if (strcmp (buff, ",") == 0)
+      break;
+  }
 
-  case F_SGML:
-    fputs ("<link linkend=\"", out);
-    sgml_id_fputs (ref, out);
-    fputs ("\">", out);
-    if (output_dollar)
-      fputc ('$', out);
-    sgml_fputs (ref, out);
-    fputs ("</link>", out);
-    break;
+  /* option name or UL &address */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+  if (strcmp (buff, "UL") == 0)
+    if (!(s = get_token (buff, sizeof (buff), s))) return;
 
-  default:
-    break;
+  /* comma */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+
+  if (Debug) fprintf (stderr, "%s: Expecting default value.\n", Progname);
+
+  /* <default value> or UL <default value> */
+  if (!(s = get_token (buff, sizeof (buff), s))) return;
+  if (strcmp (buff, "UL") == 0)
+  {
+    if (Debug) fprintf (stderr, "%s: Skipping UL.\n", Progname);
+    if (!(s = get_token (buff, sizeof (buff), s))) return;
   }
-}
 
-static int commit_buff (char *buff, char **d, FILE *out, int docstat)
-{
-  if (*d > buff)
+  memset (tmp, 0, sizeof (tmp));
+
+  do
   {
-    **d = '\0';
-    docstat = print_it (SP_STR, buff, out, docstat);
-    *d = buff;
+    if (strcmp (buff, "}") == 0)
+      break;
+
+    strncpy (tmp + strlen (tmp), buff, sizeof (tmp) - strlen (tmp));
   }
+  while ((s = get_token (buff, sizeof (buff), s)));
 
-  return docstat;
+  pretty_default (val, sizeof (val), tmp, type);
+  print_confline (varname, type, val, out);
 }
 
-static int handle_docline (char *l, FILE *out, int docstat)
+static void makedoc (FILE *in, FILE *out)
 {
-  char buff[BUFFSIZE];
-  char *s = NULL, *d = NULL;
-  l = skip_ws (l);
-
-  if (Debug)
-    fprintf (stderr, "%s: handle_docline `%s'\n", Progname, l);
-
-  if (strncmp (l, ".pp", 3) == 0)
-    return print_it (SP_NEWPAR, NULL, out, docstat);
-  else if (strncmp (l, ".ts", 3) == 0)
-    return print_it (SP_START_TAB, NULL, out, docstat);
-  else if (strncmp (l, ".te", 3) == 0)
-    return print_it (SP_END_TAB, NULL, out, docstat);
-  else if (strncmp (l, ".dl", 3) == 0)
-    return print_it (SP_START_DL, NULL, out, docstat);
-  else if (strncmp (l, ".de", 3) == 0)
-    return print_it (SP_END_DL, NULL, out, docstat);
-  else if (strncmp (l, ".il", 3) == 0)
-    return print_it (SP_START_IL, NULL, out, docstat);
-  else if (strncmp (l, ".ie", 3) == 0)
-    return print_it (SP_END_IL, NULL, out, docstat);
-  else if (strncmp (l, ". ", 2) == 0)
-    *l = ' ';
+  char buffer[BUFFSIZE];
+  char token[BUFFSIZE];
+  char *p = NULL;
+  int active = 0;
+  int line = 0;
+  int docstat = D_INIT;
 
-  for (s = l, d = buff; *s; s++)
+  while ((fgets (buffer, sizeof (buffer), in)))
   {
-    if (strncmp (s, "\\(as", 4) == 0)
-    {
-      *d++ = '*';
-      s += 3;
-    }
-    else if (strncmp (s, "\\(rs", 4) == 0)
-    {
-      *d++ = '\\';
-      s += 3;
-    }
-    else if (strncmp (s, "\\fI", 3) == 0)
+    line++;
+    if ((p = strchr (buffer, '\n')) == NULL)
     {
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_START_EM, NULL, out, docstat);
-      s += 2;
+      fprintf (stderr, "%s: Line %d too long.  Ask a wizard to enlarge\n"
+                      "%s: my buffer size.\n", Progname, line, Progname);
+      exit (1);
     }
-    else if (strncmp (s, "\\fB", 3) == 0)
+    else
+      *p = '\0';
+
+    if (!(p = get_token (token, sizeof (token), buffer)))
+      continue;
+
+    if (Debug)
     {
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_START_BF, NULL, out, docstat);
-      s += 2;
+      fprintf (stderr, "%s: line %d.  first token: \"%s\".\n",
+              Progname, line, token);
     }
-    else if (strncmp (s, "\\fC", 3) == 0)
+
+    if (strcmp (token, "/*++*/") == 0)
+      active = 1;
+    else if (strcmp (token, "/*--*/") == 0)
     {
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_START_TT, NULL, out, docstat);
-      s += 2;
+      docstat = flush_doc (docstat, out);
+      active = 0;
     }
-    else if (strncmp (s, "\\fP", 3) == 0)
+    else if (active && ((strcmp (token, "/**") == 0) || (strcmp (token, "**") == 0)))
+      docstat = handle_docline (p, out, docstat);
+    else if (active && (strcmp (token, "{") == 0))
     {
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_END_FT, NULL, out, docstat);
-      s += 2;
+      docstat = flush_doc (docstat, out);
+      handle_confline (p, out);
     }
-    else if (strncmp (s, ".dt", 3) == 0)
+  }
+  flush_doc (docstat, out);
+  fputs ("\n", out);
+}
+
+int main (int argc, char *argv[])
+{
+  int c;
+  FILE *f = NULL;
+
+  if ((Progname = strrchr (argv[0], '/')))
+    Progname++;
+  else
+    Progname = argv[0];
+
+  while ((c = getopt (argc, argv, "cmsd")) != EOF)
+  {
+    switch (c)
     {
-      if (docstat & D_DD)
+      case 'c': OutputFormat = F_CONF; break;
+      case 'm': OutputFormat = F_MAN; break;
+      case 's': OutputFormat = F_SGML; break;
+      case 'd': Debug++; break;
+      default:
       {
-       docstat = commit_buff (buff, &d, out, docstat);
-       docstat = print_it (SP_END_DD, NULL, out, docstat);
+       fprintf (stderr, "%s: bad command line parameter.\n", Progname);
+       exit (1);
       }
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_DT, NULL, out, docstat);
-      s += 3;
     }
-    else if (strncmp (s, ".dd", 3) == 0)
+  }
+
+  if (optind != argc)
+  {
+    if ((f = fopen (argv[optind], "r")) == NULL)
     {
-      if ((docstat & D_IL) && (docstat & D_DD))
-      {
-       docstat = commit_buff (buff, &d, out, docstat);
-       docstat = print_it (SP_END_DD, NULL, out, docstat);
-      }
-      docstat = commit_buff (buff, &d, out, docstat);
-      docstat = print_it (SP_DD, NULL, out, docstat);
-      s += 3;
+      fprintf (stderr, "%s: Can't open %s (%s).\n",
+              Progname, argv[optind], strerror (errno));
+      exit (1);
     }
-    else if (*s == '$')
-    {
-      int output_dollar = 0;
-      char *ref = NULL;
-      char save;
-
-      ++s;
-      if (*s == '$')
-      {
-       output_dollar = 1;
-       ++s;
-      }
-      if (*s == '$')
-      {
-       *d++ = '$';
-      }
-      else
-      {
-       ref = s;
-       while (isalnum ((unsigned char) *s) || (*s && strchr("-_<>", *s)))
-         ++s;
+  }
+  else
+    f = stdin;
 
-       docstat = commit_buff (buff, &d, out, docstat);
-       save = *s;
-       *s = 0;
-       print_ref (out, output_dollar, ref);
-       *s = save;
-       --s;
-      }
+  switch (OutputFormat)
+  {
+    case F_CONF:
+    case F_MAN:
+    case F_SGML: makedoc (f, stdout); break;
+    default:
+    {
+      fprintf (stderr, "%s: No output format specified.\n",
+              Progname);
+      exit (1);
     }
-    else
-      *d++ = *s;
   }
 
-  docstat = commit_buff (buff, &d, out, docstat);
-  return print_it (SP_NEWLINE, NULL, out, docstat);
+  if (f != stdin)
+    fclose (f);
+
+  return 0;
 }
+