]> code.delx.au - gnu-emacs/blobdiff - lib-src/make-docfile.c
merge master
[gnu-emacs] / lib-src / make-docfile.c
index 73d1a0eb31d3b78360d2c93062c83fbfffd9d725..741fa4bfa425561b6d1a92c690f741c5d919576a 100644 (file)
@@ -1,6 +1,6 @@
 /* Generate doc-string file for GNU Emacs from source files.
 
-Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2013 Free Software
+Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2015 Free Software
 Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -36,19 +36,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>   /* config.h unconditionally includes this anyway */
-#ifdef MSDOS
-#include <fcntl.h>
-#endif /* MSDOS */
+
 #ifdef WINDOWSNT
 /* Defined to be sys_fopen in ms-w32.h, but only #ifdef emacs, so this
    is really just insurance.  */
 #undef fopen
-#include <fcntl.h>
 #include <direct.h>
 #endif /* WINDOWSNT */
 
+#include <binary-io.h>
+
 #ifdef DOS_NT
 /* Defined to be sys_chdir in ms-w32.h, but only #ifdef emacs, so this
    is really just insurance.
@@ -56,26 +56,20 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    Similarly, msdos defines this as sys_chdir, but we're not linking with the
    file where that function is defined.  */
 #undef chdir
-#define READ_TEXT "rt"
-#define READ_BINARY "rb"
 #define IS_SLASH(c)  ((c) == '/' || (c) == '\\' || (c) == ':')
 #else  /* not DOS_NT */
-#define READ_TEXT "r"
-#define READ_BINARY "r"
 #define IS_SLASH(c)  ((c) == '/')
 #endif /* not DOS_NT */
 
 static int scan_file (char *filename);
 static int scan_lisp_file (const char *filename, const char *mode);
 static int scan_c_file (char *filename, const char *mode);
+static int scan_c_stream (FILE *infile);
 static void start_globals (void);
 static void write_globals (void);
 
 #include <unistd.h>
 
-/* Stdio stream for output to the DOC file.  */
-FILE *outfile;
-
 /* Name this program was invoked with.  */
 char *progname;
 
@@ -114,6 +108,17 @@ xmalloc (unsigned int size)
   return result;
 }
 
+/* Like strdup, but get fatal error if memory is exhausted.  */
+
+static char *
+xstrdup (char *s)
+{
+  char *result = strdup (s);
+  if (! result)
+    fatal ("virtual memory exhausted", 0);
+  return result;
+}
+
 /* Like realloc but get fatal error if memory is exhausted.  */
 
 static void *
@@ -131,37 +136,27 @@ main (int argc, char **argv)
 {
   int i;
   int err_count = 0;
-  int first_infile;
 
   progname = argv[0];
 
-  outfile = stdout;
-
-  /* Don't put CRs in the DOC file.  */
-#ifdef MSDOS
-  _fmode = O_BINARY;
-#if 0  /* Suspicion is that this causes hanging.
-         So instead we require people to use -o on MSDOS.  */
-  (stdout)->_flag &= ~_IOTEXT;
-  _setmode (fileno (stdout), O_BINARY);
-#endif
-  outfile = 0;
-#endif /* MSDOS */
-#ifdef WINDOWSNT
-  _fmode = O_BINARY;
-  _setmode (fileno (stdout), O_BINARY);
-#endif /* WINDOWSNT */
-
   /* If first two args are -o FILE, output to FILE.  */
   i = 1;
   if (argc > i + 1 && !strcmp (argv[i], "-o"))
     {
-      outfile = fopen (argv[i + 1], "w");
+      if (! freopen (argv[i + 1], "w", stdout))
+       {
+         perror (argv[i + 1]);
+         return EXIT_FAILURE;
+       }
       i += 2;
     }
   if (argc > i + 1 && !strcmp (argv[i], "-a"))
     {
-      outfile = fopen (argv[i + 1], "a");
+      if (! freopen (argv[i + 1], "a", stdout))
+       {
+         perror (argv[i + 1]);
+         return EXIT_FAILURE;
+       }
       i += 2;
     }
   if (argc > i + 1 && !strcmp (argv[i], "-d"))
@@ -179,22 +174,26 @@ main (int argc, char **argv)
       ++i;
     }
 
-  if (outfile == 0)
-    fatal ("No output file specified", "");
+  set_binary_mode (fileno (stdout), O_BINARY);
 
   if (generate_globals)
     start_globals ();
 
-  first_infile = i;
-  for (; i < argc; i++)
+  if (argc <= i)
+    scan_c_stream (stdin);
+  else
     {
-      int j;
-      /* Don't process one file twice.  */
-      for (j = first_infile; j < i; j++)
-       if (! strcmp (argv[i], argv[j]))
-         break;
-      if (j == i)
-       err_count += scan_file (argv[i]);
+      int first_infile = i;
+      for (; i < argc; i++)
+       {
+         int j;
+         /* Don't process one file twice.  */
+         for (j = first_infile; j < i; j++)
+           if (strcmp (argv[i], argv[j]) == 0)
+             break;
+         if (j == i)
+           err_count += scan_file (argv[i]);
+       }
     }
 
   if (err_count == 0 && generate_globals)
@@ -215,13 +214,11 @@ put_filename (char *filename)
        filename = tmp + 1;
     }
 
-  putc (037, outfile);
-  putc ('S', outfile);
-  fprintf (outfile, "%s\n", filename);
+  printf ("\037S%s\n", filename);
 }
 
-/* Read file FILENAME and output its doc strings to outfile.  */
-/* Return 1 if file is not found, 0 if it is found.  */
+/* Read file FILENAME and output its doc strings to stdout.
+   Return 1 if file is not found, 0 if it is found.  */
 
 static int
 scan_file (char *filename)
@@ -232,19 +229,19 @@ scan_file (char *filename)
   if (!generate_globals)
     put_filename (filename);
   if (len > 4 && !strcmp (filename + len - 4, ".elc"))
-    return scan_lisp_file (filename, READ_BINARY);
+    return scan_lisp_file (filename, "rb");
   else if (len > 3 && !strcmp (filename + len - 3, ".el"))
-    return scan_lisp_file (filename, READ_TEXT);
+    return scan_lisp_file (filename, "r");
   else
-    return scan_c_file (filename, READ_TEXT);
+    return scan_c_file (filename, "r");
 }
 
 static void
 start_globals (void)
 {
-  fprintf (outfile, "/* This file was auto-generated by make-docfile.  */\n");
-  fprintf (outfile, "/* DO NOT EDIT.  */\n");
-  fprintf (outfile, "struct emacs_globals {\n");
+  puts ("/* This file was auto-generated by make-docfile.  */");
+  puts ("/* DO NOT EDIT.  */");
+  puts ("struct emacs_globals {");
 }
 \f
 static char input_buffer[128];
@@ -373,7 +370,7 @@ scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
 
 /* Skip a C string or C-style comment from INFILE, and return the
    character that follows.  COMMENT non-zero means skip a comment.  If
-   PRINTFLAG is positive, output string contents to outfile.  If it is
+   PRINTFLAG is positive, output string contents to stdout.  If it is
    negative, store contents in buf.  Convert escape sequences \n and
    \t to newline and tab; discard \ followed by newline.
    If SAW_USAGE is non-zero, then any occurrences of the string `usage:'
@@ -388,7 +385,7 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa
 
   state.in_file = infile;
   state.buf_ptr = (printflag < 0 ? input_buffer : 0);
-  state.out_file = (printflag > 0 ? outfile : 0);
+  state.out_file = (printflag > 0 ? stdout : 0);
   state.pending_spaces = 0;
   state.pending_newlines = 0;
   state.keyword = (saw_usage ? "usage:" : 0);
@@ -465,18 +462,18 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa
 
 
 \f
-/* Write to file OUT the argument names of function FUNC, whose text is in BUF.
+/* Write to stdout the argument names of function FUNC, whose text is in BUF.
    MINARGS and MAXARGS are the minimum and maximum number of arguments.  */
 
 static void
-write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
+write_c_args (char *func, char *buf, int minargs, int maxargs)
 {
   register char *p;
   int in_ident = 0;
   char *ident_start IF_LINT (= NULL);
   size_t ident_length = 0;
 
-  fprintf (out, "(fn");
+  fputs ("(fn", stdout);
 
   if (*buf == '(')
     ++buf;
@@ -517,10 +514,10 @@ write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
          if (strncmp (ident_start, "void", ident_length) == 0)
            continue;
 
-         putc (' ', out);
+         putchar (' ');
 
          if (minargs == 0 && maxargs > 0)
-           fprintf (out, "&optional ");
+           fputs ("&optional ", stdout);
 
          minargs--;
          maxargs--;
@@ -528,7 +525,7 @@ write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
          /* In C code, `default' is a reserved word, so we spell it
             `defalt'; demangle that here.  */
          if (ident_length == 6 && memcmp (ident_start, "defalt", 6) == 0)
-           fprintf (out, "DEFAULT");
+           fputs ("DEFAULT", stdout);
          else
            while (ident_length-- > 0)
              {
@@ -539,22 +536,24 @@ write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
                else if (c == '_')
                  /* Print underscore as hyphen.  */
                  c = '-';
-               putc (c, out);
+               putchar (c);
              }
        }
     }
 
-  putc (')', out);
+  putchar (')');
 }
 \f
 /* The types of globals.  These are sorted roughly in decreasing alignment
-   order to avoid allocation gaps, except that functions are last.  */
+   order to avoid allocation gaps, except that symbols and functions
+   are last.  */
 enum global_type
 {
   INVALID,
   LISP_OBJECT,
   EMACS_INTEGER,
   BOOLEAN,
+  SYMBOL,
   FUNCTION
 };
 
@@ -563,17 +562,25 @@ struct global
 {
   enum global_type type;
   char *name;
-  int value;
+  int flags;
+  union
+  {
+    int value;
+    char const *svalue;
+  } v;
 };
 
+/* Bit values for FLAGS field from the above.  Applied for DEFUNs only.  */
+enum { DEFUN_noreturn = 1, DEFUN_const = 2 };
+
 /* All the variable names we saw while scanning C sources in `-g'
    mode.  */
 int num_globals;
 int num_globals_allocated;
 struct global *globals;
 
-static void
-add_global (enum global_type type, char *name, int value)
+static struct global *
+add_global (enum global_type type, char *name, int value, char const *svalue)
 {
   /* Ignore the one non-symbol that can occur.  */
   if (strcmp (name, "..."))
@@ -594,8 +601,14 @@ add_global (enum global_type type, char *name, int value)
 
       globals[num_globals - 1].type = type;
       globals[num_globals - 1].name = name;
-      globals[num_globals - 1].value = value;
+      if (svalue)
+       globals[num_globals - 1].v.svalue = svalue;
+      else
+       globals[num_globals - 1].v.value = value;
+      globals[num_globals - 1].flags = 0;
+      return globals + num_globals - 1;
     }
+  return NULL;
 }
 
 static int
@@ -607,21 +620,58 @@ compare_globals (const void *a, const void *b)
   if (ga->type != gb->type)
     return ga->type - gb->type;
 
+  /* Consider "nil" to be the least, so that iQnil is zero.  That
+     way, Qnil's internal representation is zero, which is a bit faster.  */
+  if (ga->type == SYMBOL)
+    {
+      bool a_nil = strcmp (ga->name, "Qnil") == 0;
+      bool b_nil = strcmp (gb->name, "Qnil") == 0;
+      if (a_nil | b_nil)
+       return b_nil - a_nil;
+    }
+
   return strcmp (ga->name, gb->name);
 }
 
 static void
-close_emacs_globals (void)
+close_emacs_globals (int num_symbols)
 {
-  fprintf (outfile, "};\n");
-  fprintf (outfile, "extern struct emacs_globals globals;\n");
+  printf (("};\n"
+          "extern struct emacs_globals globals;\n"
+          "\n"
+          "#ifndef DEFINE_SYMBOLS\n"
+          "extern\n"
+          "#endif\n"
+          "struct Lisp_Symbol alignas (GCALIGNMENT) lispsym[%d];\n"),
+         num_symbols);
 }
 
 static void
 write_globals (void)
 {
-  int i, seen_defun = 0;
+  int i, j;
+  bool seen_defun = false;
+  int symnum = 0;
+  int num_symbols = 0;
   qsort (globals, num_globals, sizeof (struct global), compare_globals);
+
+  j = 0;
+  for (i = 0; i < num_globals; i++)
+    {
+      while (i + 1 < num_globals
+            && strcmp (globals[i].name, globals[i + 1].name) == 0)
+       {
+         if (globals[i].type == FUNCTION
+             && globals[i].v.value != globals[i + 1].v.value)
+           error ("function '%s' defined twice with differing signatures",
+                  globals[i].name);
+         i++;
+       }
+      num_symbols += globals[i].type == SYMBOL;
+      globals[j++] = globals[i];
+    }
+  num_globals = j;
+
   for (i = 0; i < num_globals; ++i)
     {
       char const *type = 0;
@@ -637,12 +687,13 @@ write_globals (void)
        case LISP_OBJECT:
          type = "Lisp_Object";
          break;
+       case SYMBOL:
        case FUNCTION:
          if (!seen_defun)
            {
-             close_emacs_globals ();
-             fprintf (outfile, "\n");
-             seen_defun = 1;
+             close_emacs_globals (num_symbols);
+             putchar ('\n');
+             seen_defun = true;
            }
          break;
        default:
@@ -651,43 +702,65 @@ write_globals (void)
 
       if (type)
        {
-         fprintf (outfile, "  %s f_%s;\n", type, globals[i].name);
-         fprintf (outfile, "#define %s globals.f_%s\n",
-                  globals[i].name, globals[i].name);
+         printf ("  %s f_%s;\n", type, globals[i].name);
+         printf ("#define %s globals.f_%s\n",
+                 globals[i].name, globals[i].name);
        }
+      else if (globals[i].type == SYMBOL)
+       printf (("DEFINE_LISP_SYMBOL_BEGIN (%s)\n"
+                "#define i%s %d\n"
+                "#define %s builtin_lisp_symbol (i%s)\n"
+                "DEFINE_LISP_SYMBOL_END (%s)\n\n"),
+               globals[i].name, globals[i].name, symnum++,
+               globals[i].name, globals[i].name, globals[i].name);
       else
        {
-         /* It would be nice to have a cleaner way to deal with these
-            special hacks.  */
-         if (strcmp (globals[i].name, "Fthrow") == 0
-             || strcmp (globals[i].name, "Ftop_level") == 0
-             || strcmp (globals[i].name, "Fkill_emacs") == 0
-             || strcmp (globals[i].name, "Fexit_recursive_edit") == 0
-             || strcmp (globals[i].name, "Fabort_recursive_edit") == 0)
-           fprintf (outfile, "_Noreturn ");
-         fprintf (outfile, "EXFUN (%s, ", globals[i].name);
-         if (globals[i].value == -1)
-           fprintf (outfile, "MANY");
-         else if (globals[i].value == -2)
-           fprintf (outfile, "UNEVALLED");
+         if (globals[i].flags & DEFUN_noreturn)
+           fputs ("_Noreturn ", stdout);
+
+         printf ("EXFUN (%s, ", globals[i].name);
+         if (globals[i].v.value == -1)
+           fputs ("MANY", stdout);
+         else if (globals[i].v.value == -2)
+           fputs ("UNEVALLED", stdout);
          else
-           fprintf (outfile, "%d", globals[i].value);
-         fprintf (outfile, ");\n");
-       }
+           printf ("%d", globals[i].v.value);
+         putchar (')');
 
-      while (i + 1 < num_globals
-            && !strcmp (globals[i].name, globals[i + 1].name))
-       {
-         if (globals[i].type == FUNCTION
-             && globals[i].value != globals[i + 1].value)
-           error ("function '%s' defined twice with differing signatures",
-                  globals[i].name);
-         ++i;
+         if (globals[i].flags & DEFUN_const)
+           fputs (" ATTRIBUTE_CONST", stdout);
+         else if (strcmp (globals[i].name, "Fnext_read_file_uses_dialog_p")
+                  == 0)
+           {
+             /* It would be nice to have a cleaner way to deal with this
+                special hack.  */
+             fputs (("\n"
+                     "#if ! (defined USE_GTK || defined USE_MOTIF \\\n"
+                     "       || defined HAVE_NS || defined HAVE_NTGUI)\n"
+                     "\tATTRIBUTE_CONST\n"
+                     "#endif\n"),
+                    stdout);
+           }
+
+         puts (";");
        }
     }
 
   if (!seen_defun)
-    close_emacs_globals ();
+    close_emacs_globals (num_symbols);
+
+  puts ("#ifdef DEFINE_SYMBOLS");
+  puts ("static char const *const defsym_name[] = {");
+  for (int i = 0; i < num_globals; i++)
+    {
+      if (globals[i].type == SYMBOL)
+       printf ("\t\"%s\",\n", globals[i].v.svalue);
+      while (i + 1 < num_globals
+            && strcmp (globals[i].name, globals[i + 1].name) == 0)
+       i++;
+    }
+  puts ("};");
+  puts ("#endif");
 }
 
 \f
@@ -700,9 +773,6 @@ static int
 scan_c_file (char *filename, const char *mode)
 {
   FILE *infile;
-  register int c;
-  register int commas;
-  int minargs, maxargs;
   int extension = filename[strlen (filename) - 1];
 
   if (extension == 'o')
@@ -728,8 +798,32 @@ scan_c_file (char *filename, const char *mode)
 
   /* Reset extension to be able to detect duplicate files.  */
   filename[strlen (filename) - 1] = extension;
+  return scan_c_stream (infile);
+}
+
+/* Return 1 if next input from INFILE is equal to P, -1 if EOF,
+   0 if input doesn't match.  */
+
+static int
+stream_match (FILE *infile, const char *p)
+{
+  for (; *p; p++)
+    {
+      int c = getc (infile);
+      if (c == EOF)
+       return -1;
+      if (c != *p)
+       return 0;
+    }
+  return 1;
+}
+
+static int
+scan_c_stream (FILE *infile)
+{
+  int commas, minargs, maxargs;
+  int c = '\n';
 
-  c = '\n';
   while (!feof (infile))
     {
       int doc_keyword = 0;
@@ -758,37 +852,53 @@ scan_c_file (char *filename, const char *mode)
          if (c != 'F')
            continue;
          c = getc (infile);
-         if (c != 'V')
-           continue;
-         c = getc (infile);
-         if (c != 'A')
-           continue;
-         c = getc (infile);
-         if (c != 'R')
-           continue;
-         c = getc (infile);
-         if (c != '_')
-           continue;
-
-         defvarflag = 1;
-
-         c = getc (infile);
-         defvarperbufferflag = (c == 'P');
-         if (generate_globals)
+         if (c == 'S')
            {
-             if (c == 'I')
-               type = EMACS_INTEGER;
-             else if (c == 'L')
-               type = LISP_OBJECT;
-             else if (c == 'B')
-               type = BOOLEAN;
+             c = getc (infile);
+             if (c != 'Y')
+               continue;
+             c = getc (infile);
+             if (c != 'M')
+               continue;
+             c = getc (infile);
+             if (c != ' ' && c != '\t' && c != '(')
+               continue;
+             type = SYMBOL;
            }
+         else if (c == 'V')
+           {
+             c = getc (infile);
+             if (c != 'A')
+               continue;
+             c = getc (infile);
+             if (c != 'R')
+               continue;
+             c = getc (infile);
+             if (c != '_')
+               continue;
 
-         c = getc (infile);
-         /* We need to distinguish between DEFVAR_BOOL and
-            DEFVAR_BUFFER_DEFAULTS.  */
-         if (generate_globals && type == BOOLEAN && c != 'O')
-           type = INVALID;
+             defvarflag = 1;
+
+             c = getc (infile);
+             defvarperbufferflag = (c == 'P');
+             if (generate_globals)
+               {
+                 if (c == 'I')
+                   type = EMACS_INTEGER;
+                 else if (c == 'L')
+                   type = LISP_OBJECT;
+                 else if (c == 'B')
+                   type = BOOLEAN;
+               }
+
+             c = getc (infile);
+             /* We need to distinguish between DEFVAR_BOOL and
+                DEFVAR_BUFFER_DEFAULTS.  */
+             if (generate_globals && type == BOOLEAN && c != 'O')
+               type = INVALID;
+           }
+         else
+           continue;
        }
       else if (c == 'D')
        {
@@ -805,7 +915,7 @@ scan_c_file (char *filename, const char *mode)
 
       if (generate_globals
          && (!defvarflag || defvarperbufferflag || type == INVALID)
-         && !defunflag)
+         && !defunflag && type != SYMBOL)
        continue;
 
       while (c != '(')
@@ -815,15 +925,19 @@ scan_c_file (char *filename, const char *mode)
          c = getc (infile);
        }
 
-      /* Lisp variable or function name.  */
-      c = getc (infile);
-      if (c != '"')
-       continue;
-      c = read_c_string_or_comment (infile, -1, 0, 0);
+      if (type != SYMBOL)
+       {
+         /* Lisp variable or function name.  */
+         c = getc (infile);
+         if (c != '"')
+           continue;
+         c = read_c_string_or_comment (infile, -1, 0, 0);
+       }
 
       if (generate_globals)
        {
          int i = 0;
+         char const *svalue = 0;
 
          /* Skip "," and whitespace.  */
          do
@@ -835,6 +949,8 @@ scan_c_file (char *filename, const char *mode)
          /* Read in the identifier.  */
          do
            {
+             if (c < 0)
+               goto eof;
              input_buffer[i++] = c;
              c = getc (infile);
            }
@@ -845,13 +961,27 @@ scan_c_file (char *filename, const char *mode)
          name = xmalloc (i + 1);
          memcpy (name, input_buffer, i + 1);
 
+         if (type == SYMBOL)
+           {
+             do
+               c = getc (infile);
+             while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
+             if (c != '"')
+               continue;
+             c = read_c_string_or_comment (infile, -1, 0, 0);
+             svalue = xstrdup (input_buffer);
+           }
+
          if (!defunflag)
            {
-             add_global (type, name, 0);
+             add_global (type, name, 0, svalue);
              continue;
            }
        }
 
+      if (type == SYMBOL)
+       continue;
+
       /* DEFVAR_LISP ("name", addr, "doc")
         DEFVAR_LISP ("name", addr /\* doc *\/)
         DEFVAR_LISP ("name", addr, doc: /\* doc *\/)  */
@@ -904,7 +1034,63 @@ scan_c_file (char *filename, const char *mode)
 
       if (generate_globals)
        {
-         add_global (FUNCTION, name, maxargs);
+         struct global *g = add_global (FUNCTION, name, maxargs, 0);
+
+         /* The following code tries to recognize function attributes
+            specified after the docstring, e.g.:
+
+            DEFUN ("foo", Ffoo, Sfoo, X, Y, Z,
+                  doc: /\* doc *\/
+                  attributes: attribute1 attribute2 ...)
+              (Lisp_Object arg...)
+
+            Now only 'noreturn' and 'const' attributes are used.  */
+
+         /* Advance to the end of docstring.  */
+         c = getc (infile);
+         if (c == EOF)
+           goto eof;
+         int d = getc (infile);
+         if (d == EOF)
+           goto eof;
+         while (1)
+           {
+             if (c == '*' && d == '/')
+               break;
+             c = d, d = getc (infile);
+             if (d == EOF)
+               goto eof;
+           }
+         /* Skip spaces, if any.  */
+         do
+           {
+             c = getc (infile);
+             if (c == EOF)
+               goto eof;
+           }
+         while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
+         /* Check for 'attributes:' token.  */
+         if (c == 'a' && stream_match (infile, "ttributes:"))
+           {
+             char *p = input_buffer;
+             /* Collect attributes up to ')'.  */
+             while (1)
+               {
+                 c = getc (infile);
+                 if (c == EOF)
+                   goto eof;
+                 if (c == ')')
+                   break;
+                 if (p - input_buffer > sizeof (input_buffer))
+                   abort ();
+                 *p++ = c;
+               }
+             *p = 0;
+             if (strstr (input_buffer, "noreturn"))
+               g->flags |= DEFUN_noreturn;
+             if (strstr (input_buffer, "const"))
+               g->flags |= DEFUN_const;
+           }
          continue;
        }
 
@@ -941,9 +1127,7 @@ scan_c_file (char *filename, const char *mode)
          int comment = c != '"';
          int saw_usage;
 
-         putc (037, outfile);
-         putc (defvarflag ? 'V' : 'F', outfile);
-         fprintf (outfile, "%s\n", input_buffer);
+         printf ("\037%c%s\n", defvarflag ? 'V' : 'F', input_buffer);
 
          if (comment)
            getc (infile);      /* Skip past `*'.  */
@@ -985,8 +1169,8 @@ scan_c_file (char *filename, const char *mode)
              while (c != ')');
              *p = '\0';
              /* Output them.  */
-             fprintf (outfile, "\n\n");
-             write_c_args (outfile, input_buffer, argbuf, minargs, maxargs);
+             fputs ("\n\n", stdout);
+             write_c_args (input_buffer, argbuf, minargs, maxargs);
            }
          else if (defunflag && maxargs == -1 && !saw_usage)
            /* The DOC should provide the usage form.  */
@@ -1075,7 +1259,7 @@ read_lisp_symbol (FILE *infile, char *buffer)
 static int
 search_lisp_doc_at_eol (FILE *infile)
 {
-  char c = 0, c1 = 0, c2 = 0;
+  int c = 0, c1 = 0, c2 = 0;
 
   /* Skip until the end of line; remember two previous chars.  */
   while (c != '\n' && c != '\r' && c != EOF)
@@ -1422,12 +1606,10 @@ scan_lisp_file (const char *filename, const char *mode)
         In the latter case, the opening quote (and leading backslash-newline)
         have already been read.  */
 
-      putc (037, outfile);
-      putc (type, outfile);
-      fprintf (outfile, "%s\n", buffer);
+      printf ("\037%c%s\n", type, buffer);
       if (saved_string)
        {
-         fputs (saved_string, outfile);
+         fputs (saved_string, stdout);
          /* Don't use one dynamic doc string twice.  */
          free (saved_string);
          saved_string = 0;