]> code.delx.au - gnu-emacs/blobdiff - lib-src/make-docfile.c
* indent.el (indent-region, indent-region-function): Doc fix.
[gnu-emacs] / lib-src / make-docfile.c
index 1af038027e05ccf1545364701390528b3e7c27ad..83602f86e8ac8e438b4b9c0653e686999a3251c3 100644 (file)
@@ -1,11 +1,11 @@
 /* Generate doc-string file for GNU Emacs from source files.
-   Copyright (C) 1985, 1986 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs 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 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -143,32 +143,49 @@ write_c_args (out, buf, minargs, maxargs)
      char *buf;
      int minargs, maxargs;
 {
-  register int c;
-  register char *p = buf;
-  int space = 0;
+  register char *p;
+  int in_ident = 0;
+  int just_spaced = 0;
 
   fprintf (out, "arguments: ");
 
-  while (*p)
+  for (p = buf; *p; p++)
     {
-      c = *p++;
-      if (c == ',')
+      char c = *p;
+
+      /* Notice when we start printing a new identifier.  */
+      if ((('A' <= c && c <= 'Z')
+          || ('a' <= c && c <= 'z')
+          || ('0' <= c && c <= '9')
+          || c == '_')
+         != in_ident)
        {
-         minargs--;
-         maxargs--;
-         if (!space)
-           putc (' ', out);
-         if (minargs == 0 && maxargs > 0)
-           fprintf (out, "&optional ");
-         space = 1;
-         continue;
+         if (!in_ident)
+           {
+             in_ident = 1;
+
+             if (minargs == 0 && maxargs > 0)
+               fprintf (out, "&optional ");
+             just_spaced = 1;
+
+             minargs--;
+             maxargs--;
+           }
+         else
+           in_ident = 0;
        }
-      else if (c == ' ' && space)
-       continue;
-      space = (c == ' ');
-      putc (c, out);
+
+      /* Print the C argument list as it would appear in lisp:
+        print underscores as hyphens, and print commas as spaces.
+        Collapse adjacent spaces into one.  */
+      if (c == '_') c = '-';
+      if (c == ',') c = ' ';
+
+      if (c != ' ' || ! just_spaced)
+       putc (c, out);
+
+      just_spaced = (c == ' ');
     }
-  putc ('\n', out);
 }
 \f
 /* Read through a c file.  If a .o file is named,
@@ -183,6 +200,7 @@ scan_c_file (filename)
   register int c;
   register int commas;
   register int defunflag;
+  register int defvarperbufferflag;
   register int defvarflag;
   int minargs, maxargs;
 
@@ -222,8 +240,22 @@ scan_c_file (filename)
          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;
          defunflag = 0;
+
+         c = getc (infile);
+         defvarperbufferflag = (c == 'P');
+
          c = getc (infile);
        }
       else if (c == 'D')
@@ -254,6 +286,8 @@ scan_c_file (filename)
 
       if (defunflag)
        commas = 5;
+      else if (defvarperbufferflag)
+       commas = 2;
       else if (defvarflag)
        commas = 1;
       else  /* For DEFSIMPLE and DEFPRED */
@@ -342,35 +376,74 @@ scan_c_file (filename)
 /* Read a file of Lisp code, compiled or interpreted.
  Looks for
   (defun NAME ARGS DOCSTRING ...)
-  (autoload 'NAME FILE DOCSTRING ...)
+  (defmacro NAME ARGS DOCSTRING ...)
+  (autoload (quote NAME) FILE DOCSTRING ...)
   (defvar NAME VALUE DOCSTRING)
   (defconst NAME VALUE DOCSTRING)
-  (fset (quote NAME) (make-byte-code (quote ARGS) ... "\
-      DOCSTRING")
+  (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
+  (fset (quote NAME) #[... DOCSTRING ...])
  starting in column zero.
- ARGS, FILE or VALUE is ignored.  We do not know how to parse Lisp code
- so we use a kludge to skip them:
-  In a function definition, the form of ARGS of FILE is known, and we
-  can skip it.
-  In a variable definition, we use a formatting convention:
-  the DOCSTRING, if present, must be followed by a closeparen and a newline,
-  and no newline must appear between the defvar or defconst and the docstring,
-  The only source file that must follow this convention is loaddefs.el;
-  aside from that, it is always the .elc file that we look at, and
 they are no problem because byte-compiler output follows this convention.
+ (quote NAME) may appear as 'NAME as well.
+ For defun, defmacro, and autoload, we know how to skip over the arglist.
+ For defvar, defconst, and fset we skip to the docstring with a klugey 
+ formatting convention: all docstrings must appear on the same line as the
+ initial open-paren (the one in column zero) and must contain a backslash 
+ and a double-quote immediately after the initial double-quote.  No newlines
+ must appear between the beginning of the form and the first double-quote.
+ The only source file that must follow this convention is loaddefs.el; aside
+ from that, it is always the .elc file that we look at, and they are no
+ problem because byte-compiler output follows this convention.
  The NAME and DOCSTRING are output.
  NAME is preceded by `F' for a function or `V' for a variable.
  An entry is output only if DOCSTRING has \ newline just after the opening "
  */
 
+void
+skip_white (infile)
+     FILE *infile;
+{
+  char c = ' ';
+  while (c == ' ' || c == '\t' || c == '\n')
+    c = getc (infile);
+  ungetc (c, infile);
+}
+
+void
+read_lisp_symbol (infile, buffer)
+     FILE *infile;
+     char *buffer;
+{
+  char c;
+  char *fillp = buffer;
+
+  skip_white (infile);
+  while (1)
+    {
+      c = getc (infile);
+      if (c == '\\')
+       *(++fillp) = getc (infile);
+      else if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')')
+       {
+         ungetc (c, infile);
+         *fillp = 0;
+         break;
+       }
+      else
+       *fillp++ = c;
+    }
+
+  if (! buffer[0])
+    fprintf (stderr, "## expected a symbol, got '%c'\n", c);
+  
+  skip_white (infile);
+}
+
+
 scan_lisp_file (filename)
      char *filename;
 {
   FILE *infile;
   register int c;
-  register int commas;
-  register char *p;
-  int defvarflag;
 
   infile = fopen (filename, "r");
   if (infile == NULL)
@@ -382,6 +455,10 @@ scan_lisp_file (filename)
   c = '\n';
   while (!feof (infile))
     {
+      char buffer [BUFSIZ];
+      char *fillp = buffer;
+      char type;
+
       if (c != '\n')
        {
          c = getc (infile);
@@ -391,382 +468,213 @@ scan_lisp_file (filename)
       if (c != '(')
        continue;
 
-      /* Handle an autoload.  */
-      c = getc (infile);
-      if (c == 'a')
+      read_lisp_symbol (infile, buffer);
+
+      if (! strcmp (buffer, "defun") ||
+         ! strcmp (buffer, "defmacro"))
        {
-         c = getc (infile);
-         if (c != 'u')
-           continue;
-         c = getc (infile);
-         if (c != 't')
-           continue;
-         c = getc (infile);
-         if (c != 'o')
-           continue;
-         c = getc (infile);
-         if (c != 'l')
-           continue;
-         c = getc (infile);
-         if (c != 'o')
-           continue;
-         c = getc (infile);
-         if (c != 'a')
-           continue;
-         c = getc (infile);
-         if (c != 'd')
-           continue;
+         type = 'F';
+         read_lisp_symbol (infile, buffer);
 
-         c = getc (infile);
-         while (c == ' ')
-           c = getc (infile);
+         /* Skip the arguments: either "nil" or a list in parens */
 
-         if (c == '\'')
+         c = getc (infile);
+         if (c == 'n') /* nil */
            {
-             c = getc (infile);
+             if ((c = getc (infile)) != 'i' ||
+                 (c = getc (infile)) != 'l')
+               {
+                 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
+                          buffer, filename);
+                 continue;
+               }
            }
-         else
+         else if (c != '(')
            {
-             if (c != '(')
-               continue;
-             c = getc (infile);
-             if (c != 'q')
-               continue;
-             c = getc (infile);
-             if (c != 'u')
-               continue;
-             c = getc (infile);
-             if (c != 'o')
-               continue;
-             c = getc (infile);
-             if (c != 't')
-               continue;
-             c = getc (infile);
-             if (c != 'e')
-               continue;
-             c = getc (infile);
-             if (c != ' ')
-               continue;
-             while (c == ' ')
-               c = getc (infile);
+             fprintf (stderr, "## unparsable arglist in %s (%s)\n",
+                      buffer, filename);
+             continue;
            }
-
-         p = buf;
-         while (c != ' ' && c != ')')
-           {
-             if (c == EOF)
-               return 1;
-             if (c == '\\')
-               c = getc (infile);
-             *p++ = c;
+         else
+           while (c != ')')
              c = getc (infile);
-           }
-         *p = 0;
-
-         while (c != '"')
+         skip_white (infile);
+
+         /* If the next three characters aren't `dquote bslash newline'
+            then we're not reading a docstring.
+          */
+         if ((c = getc (infile)) != '"' ||
+             (c = getc (infile)) != '\\' ||
+             (c = getc (infile)) != '\n')
            {
-             if (c == EOF)
-               return 1;
-             c = getc (infile);
+#ifdef DEBUG
+             fprintf (stderr, "## non-docstring in %s (%s)\n",
+                      buffer, filename);
+#endif
+             continue;
            }
-         c = read_c_string (infile, 0);
        }
 
-      /* Handle def* clauses.  */
-      else if (c == 'd')
+      else if (! strcmp (buffer, "defvar") ||
+              ! strcmp (buffer, "defconst"))
        {
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-         c = getc (infile);
-         if (c != 'f')
-           continue;
-         c = getc (infile);
+         char c1 = 0, c2 = 0;
+         type = 'V';
+         read_lisp_symbol (infile, buffer);
 
-         /* Is this a defun?  */
-         if (c == 'u')
+         /* Skip until the first newline; remember the two previous chars. */
+         while (c != '\n' && c >= 0)
            {
+             c2 = c1;
+             c1 = c;
              c = getc (infile);
-             if (c != 'n')
-               continue;
-             defvarflag = 0;
            }
-
-         /* Or a defvar?  */
-         else if (c == 'v')
+         
+         /* If two previous characters were " and \,
+            this is a doc string.  Otherwise, there is none.  */
+         if (c2 != '"' || c1 != '\\')
            {
-             c = getc (infile);
-             if (c != 'a')
-               continue;
-             c = getc (infile);
-             if (c != 'r')
-               continue;
-             defvarflag = 1;
+#ifdef DEBUG
+             fprintf (stderr, "## non-docstring in %s (%s)\n",
+                      buffer, filename);
+#endif
+             continue;
            }
+       }
 
-         /* Or a defconst?  */
-         else if (c == 'c')
+      else if (! strcmp (buffer, "fset"))
+       {
+         char c1 = 0, c2 = 0;
+         type = 'F';
+
+         c = getc (infile);
+         if (c == '\'')
+           read_lisp_symbol (infile, buffer);
+         else
            {
+             if (c != '(')
+               {
+                 fprintf (stderr, "## unparsable name in fset in %s\n",
+                          filename);
+                 continue;
+               }
+             read_lisp_symbol (infile, buffer);
+             if (strcmp (buffer, "quote"))
+               {
+                 fprintf (stderr, "## unparsable name in fset in %s\n",
+                          filename);
+                 continue;
+               }
+             read_lisp_symbol (infile, buffer);
              c = getc (infile);
-             if (c != 'o')
-               continue;
-             c = getc (infile);
-             if (c != 'n')
-               continue;
-             c = getc (infile);
-             if (c != 's')
-               continue;
-             c = getc (infile);
-             if (c != 't')
-               continue;
-             defvarflag = 1;
+             if (c != ')')
+               {
+                 fprintf (stderr,
+                          "## unparsable quoted name in fset in %s\n",
+                          filename);
+                 continue;
+               }
            }
-         else
-           continue;
-
-         /* Now we have seen "defun" or "defvar" or "defconst".  */
 
-         while (c != ' ' && c != '\n' && c != '\t')
-           c = getc (infile);
-
-         while (c == ' ' || c == '\n' || c == '\t')
-           c = getc (infile);
-
-         /* Read and store name of function or variable being defined
-            Discard backslashes that are for quoting.  */
-         p = buf;
-         while (c != ' ' && c != '\n' && c != '\t')
+         /* Skip until the first newline; remember the two previous chars. */
+         while (c != '\n' && c >= 0)
            {
-             if (c == '\\')
-               c = getc (infile);
-             *p++ = c;
+             c2 = c1;
+             c1 = c;
              c = getc (infile);
            }
-         *p = 0;
-
-         while (c == ' ' || c == '\n' || c == '\t')
-           c = getc (infile);
+         
+         /* If two previous characters were " and \,
+            this is a doc string.  Otherwise, there is none.  */
+         if (c2 != '"' || c1 != '\\')
+           {
+#ifdef DEBUG
+             fprintf (stderr, "## non-docstring in %s (%s)\n",
+                      buffer, filename);
+#endif
+             continue;
+           }
+       }
 
-         if (! defvarflag)
+      else if (! strcmp (buffer, "autoload"))
+       {
+         type = 'F';
+         c = getc (infile);
+         if (c == '\'')
+           read_lisp_symbol (infile, buffer);
+         else
            {
-             /* A function: */
-             /* Skip the arguments: either "nil" or a list in parens */
-             if (c == 'n')
+             if (c != '(')
                {
-                 while (c != ' ' && c != '\n' && c != '\t')
-                   c = getc (infile);
+                 fprintf (stderr, "## unparsable name in autoload in %s\n",
+                          filename);
+                 continue;
                }
-             else
+             read_lisp_symbol (infile, buffer);
+             if (strcmp (buffer, "quote"))
                {
-                 while (c != '(')
-                   c = getc (infile);
-                 while (c != ')')
-                   c = getc (infile);
+                 fprintf (stderr, "## unparsable name in autoload in %s\n",
+                          filename);
+                 continue;
                }
+             read_lisp_symbol (infile, buffer);
              c = getc (infile);
-           }
-         else
-           {
-             /* A variable:  */
-
-             /* Skip until the first newline; remember
-                the two previous characters.  */
-             char c1 = 0, c2 = 0;
-
-             while (c != '\n' && c >= 0)
+             if (c != ')')
                {
-                 c2 = c1;
-                 c1 = c;
-                 c = getc (infile);
-               }
-
-             /* If two previous characters were " and \,
-                this is a doc string.  Otherwise, there is none.  */
-             if (c2 == '"' && c1 == '\\')
-               {
-                 putc (037, outfile);
-                 putc ('V', outfile);
-                 fprintf (outfile, "%s\n", buf);
-                 read_c_string (infile, 1);
+                 fprintf (stderr,
+                          "## unparsable quoted name in autoload in %s\n",
+                          filename);
+                 continue;
                }
+           }
+         skip_white (infile);
+         if ((c = getc (infile)) != '\"')
+           {
+             fprintf (stderr, "## autoload of %s unparsable (%s)\n",
+                      buffer, filename);
              continue;
            }
-       }
-      
-      /* Handle an fset clause.  */
-      else if (c == 'f') 
-       {
-         c = getc (infile);
-         if (c != 's')
-           continue;
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-         c = getc (infile);
-         if (c != 't')
-           continue;
-
-         /* Skip white space */
-         do
-           c = getc (infile);
-         while (c == ' ' || c == '\n' || c == '\t');
-
-         /* Recognize "(quote".  */
-         if (c != '(')
-           continue;
-         c = getc (infile);
-         if (c != 'q')
-           continue;
-         c = getc (infile);
-         if (c != 'u')
-           continue;
-         c = getc (infile);
-         if (c != 'o')
-           continue;
-         c = getc (infile);
-         if (c != 't')
-           continue;
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-         
-         /* Skip white space */
-         do
-           c = getc (infile);
-         while (c == ' ' || c == '\n' || c == '\t');
-
-         /* Read and store name of function or variable being defined
-            Discard backslashes that are for quoting.  */
-         p = buf;
-         while (c != ')' && c != ' ' && c != '\n' && c != '\t')
+         read_c_string (infile, 0);
+         skip_white (infile);
+
+         /* If the next three characters aren't `dquote bslash newline'
+            then we're not reading a docstring.
+          */
+         if ((c = getc (infile)) != '"' ||
+             (c = getc (infile)) != '\\' ||
+             (c = getc (infile)) != '\n')
            {
-             if (c == '\\')
-               c = getc (infile);
-             *p++ = c;
-             c = getc (infile);
+#ifdef DEBUG
+             fprintf (stderr, "## non-docstring in %s (%s)\n",
+                      buffer, filename);
+#endif
+             continue;
            }
-         *p = '\0';
-
-         /* Skip white space */
-         do
-           c = getc (infile);
-         while (c == ' ' || c == '\n' || c == '\t');
-
-         /* Recognize "(make-byte-code".  */
-         if (c != '(')
-           continue;
-         c = getc (infile);
-         if (c != 'm')
-           continue;
-         c = getc (infile);
-         if (c != 'a')
-           continue;
-         c = getc (infile);
-         if (c != 'k')
-           continue;
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-         c = getc (infile);
-         if (c != '-')
-           continue;
-         c = getc (infile);
-         if (c != 'b')
-           continue;
-         c = getc (infile);
-         if (c != 'y')
-           continue;
-         c = getc (infile);
-         if (c != 't')
-           continue;
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-         c = getc (infile);
-         if (c != '-')
-           continue;
-         c = getc (infile);
-         if (c != 'c')
-           continue;
-         c = getc (infile);
-         if (c != 'o')
-           continue;
-         c = getc (infile);
-         if (c != 'd')
-           continue;
-         c = getc (infile);
-         if (c != 'e')
-           continue;
-
-         /* Scan for a \" followed by a newline, or for )) followed by
-            a newline.  If we find the latter first, this function has
-            no docstring.  */
-         {
-           char c1 = 0, c2 = 0;
-
-           for (;;)
-             {
-
-               /* Find newlines, and remember the two previous characters.  */
-               for (;;)
-                 {
-                   c = getc (infile);
-
-                   if (c == '\n' || c < 0)
-                     break;
-
-                   c2 = c1;
-                   c1 = c;
-                 }
-               
-               /* If we've hit eof, quit.  */
-               if (c == EOF)
-                 break;
-
-               /* If the last two characters were \", this is a docstring.  */
-               else if (c2 == '"' && c1 == '\\')
-                 {
-                   putc (037, outfile);
-                   putc ('F', outfile);
-                   fprintf (outfile, "%s\n", buf);
-                   read_c_string (infile, 1);
-                   break;
-                 }
-               
-               /* If the last two characters were )), there is no
-                  docstring.  */
-               else if (c2 == ')' && c1 == ')')
-                 break;
-             }
-           continue;
-         }
        }
-      else
-       continue;
-
-      /* Here for a function definition.
-        We have skipped the file name or arguments
-        and arrived at where the doc string is,
-        if there is a doc string.  */
 
-      /* Skip whitespace */
+#ifdef DEBUG
+      else if (! strcmp (buffer, "if") ||
+              ! strcmp (buffer, "byte-code"))
+       ;
+#endif
 
-      while (c == ' ' || c == '\n' || c == '\t')
-       c = getc (infile);
-
-      /* " followed by \ and newline means a doc string we should gobble */
-      if (c != '"')
-       continue;
-      c = getc (infile);
-      if (c != '\\')
-       continue;
-      c = getc (infile);
-      if (c != '\n')
-       continue;
+      else
+       {
+#ifdef DEBUG
+         fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
+                  buffer, filename);
+#endif
+         continue;
+       }
 
+      /* At this point, there is a docstring that we should gobble.
+        The opening quote (and leading backslash-newline) have already
+        been read.
+       */
+      putc ('\n', outfile);
       putc (037, outfile);
-      putc ('F', outfile);
-      fprintf (outfile, "%s\n", buf);
+      putc (type, outfile);
+      fprintf (outfile, "%s\n", buffer);
       read_c_string (infile, 1);
     }
   fclose (infile);