X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/2db38a6f98c2abb42b746064ce97417cccc27e68..40d83b412f584cc02e68d4eac8fd5e6eb769e2fe:/lib-src/make-docfile.c
diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index af1928c63f..f900ea42e9 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -1,6 +1,5 @@
/* Generate doc-string file for GNU Emacs from source files.
- Copyright (C) 1985, 1986, 1992, 1993, 1994, 1997, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2011
Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -42,11 +41,11 @@ along with GNU Emacs. If not, see . */
#undef chdir
#include
+#include
#ifdef MSDOS
#include
#endif /* MSDOS */
#ifdef WINDOWSNT
-#include
#include
#include
#endif /* WINDOWSNT */
@@ -67,9 +66,12 @@ along with GNU Emacs. If not, see . */
#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
#endif
-int scan_file ();
-int scan_lisp_file ();
-int scan_c_file ();
+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 void fatal (const char *s1, const char *s2) NO_RETURN;
+static void start_globals (void);
+static void write_globals (void);
#ifdef MSDOS
/* s/msdos.h defines this as sys_chdir, but we're not linking with the
@@ -77,9 +79,7 @@ int scan_c_file ();
#undef chdir
#endif
-#ifdef HAVE_UNISTD_H
#include
-#endif
/* Stdio stream for output to the DOC file. */
FILE *outfile;
@@ -87,12 +87,14 @@ FILE *outfile;
/* Name this program was invoked with. */
char *progname;
+/* Nonzero if this invocation is generating globals.h. */
+int generate_globals;
+
/* Print error message. `s1' is printf control string, `s2' is arg for it. */
/* VARARGS1 */
-void
-error (s1, s2)
- char *s1, *s2;
+static void
+error (const char *s1, const char *s2)
{
fprintf (stderr, "%s: ", progname);
fprintf (stderr, s1, s2);
@@ -102,9 +104,8 @@ error (s1, s2)
/* Print error message and exit. */
/* VARARGS1 */
-void
-fatal (s1, s2)
- char *s1, *s2;
+static void
+fatal (const char *s1, const char *s2)
{
error (s1, s2);
exit (EXIT_FAILURE);
@@ -112,20 +113,29 @@ fatal (s1, s2)
/* Like malloc but get fatal error if memory is exhausted. */
-void *
-xmalloc (size)
- unsigned int size;
+static void *
+xmalloc (unsigned int size)
{
void *result = (void *) malloc (size);
if (result == NULL)
fatal ("virtual memory exhausted", 0);
return result;
}
+
+/* Like realloc but get fatal error if memory is exhausted. */
+
+static void *
+xrealloc (void *arg, unsigned int size)
+{
+ void *result = (void *) realloc (arg, size);
+ if (result == NULL)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
int
-main (argc, argv)
- int argc;
- char **argv;
+main (int argc, char **argv)
{
int i;
int err_count = 0;
@@ -164,13 +174,25 @@ main (argc, argv)
}
if (argc > i + 1 && !strcmp (argv[i], "-d"))
{
- chdir (argv[i + 1]);
+ if (chdir (argv[i + 1]) != 0)
+ {
+ perror (argv[i + 1]);
+ return EXIT_FAILURE;
+ }
i += 2;
}
+ if (argc > i && !strcmp (argv[i], "-g"))
+ {
+ generate_globals = 1;
+ ++i;
+ }
if (outfile == 0)
fatal ("No output file specified", "");
+ if (generate_globals)
+ start_globals ();
+
first_infile = i;
for (; i < argc; i++)
{
@@ -182,13 +204,16 @@ main (argc, argv)
if (j == i)
err_count += scan_file (argv[i]);
}
+
+ if (err_count == 0 && generate_globals)
+ write_globals ();
+
return (err_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
/* Add a source file name boundary marker in the output file. */
-void
-put_filename (filename)
- char *filename;
+static void
+put_filename (char *filename)
{
char *tmp;
@@ -206,13 +231,14 @@ put_filename (filename)
/* Read file FILENAME and output its doc strings to outfile. */
/* Return 1 if file is not found, 0 if it is found. */
-int
-scan_file (filename)
- char *filename;
+static int
+scan_file (char *filename)
{
- int len = strlen (filename);
- put_filename (filename);
+ size_t len = strlen (filename);
+
+ if (!generate_globals)
+ put_filename (filename);
if (len > 4 && !strcmp (filename + len - 4, ".elc"))
return scan_lisp_file (filename, READ_BINARY);
else if (len > 3 && !strcmp (filename + len - 3, ".el"))
@@ -220,8 +246,16 @@ scan_file (filename)
else
return scan_c_file (filename, READ_TEXT);
}
+
+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");
+}
-char buf[128];
+static char input_buffer[128];
/* Some state during the execution of `read_c_string_or_comment'. */
struct rcsoc_state
@@ -239,11 +273,11 @@ struct rcsoc_state
/* A keyword we look for at the beginning of lines. If found, it is
not copied, and SAW_KEYWORD is set to true. */
- char *keyword;
- /* The current point we've reached in an occurance of KEYWORD in
+ const char *keyword;
+ /* The current point we've reached in an occurrence of KEYWORD in
the input stream. */
- char *cur_keyword_ptr;
- /* Set to true if we saw an occurance of KEYWORD. */
+ const char *cur_keyword_ptr;
+ /* Set to true if we saw an occurrence of KEYWORD. */
int saw_keyword;
};
@@ -251,9 +285,7 @@ struct rcsoc_state
spaces are output first. */
static INLINE void
-put_char (ch, state)
- int ch;
- struct rcsoc_state *state;
+put_char (int ch, struct rcsoc_state *state)
{
int out_ch;
do
@@ -286,9 +318,7 @@ put_char (ch, state)
keyword, but were in fact not. */
static void
-scan_keyword_or_put_char (ch, state)
- int ch;
- struct rcsoc_state *state;
+scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
{
if (state->keyword
&& *state->cur_keyword_ptr == ch
@@ -336,7 +366,7 @@ scan_keyword_or_put_char (ch, state)
keyword, but it was a false alarm. Output the
part we scanned. */
{
- char *p;
+ const char *p;
for (p = state->keyword; p < state->cur_keyword_ptr; p++)
put_char (*p, state);
@@ -354,22 +384,18 @@ scan_keyword_or_put_char (ch, state)
PRINTFLAG is positive, output string contents to outfile. 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 occurances of the string `usage:'
+ If SAW_USAGE is non-zero, then any occurrences of the string `usage:'
at the beginning of a line will be removed, and *SAW_USAGE set to
true if any were encountered. */
-int
-read_c_string_or_comment (infile, printflag, comment, saw_usage)
- FILE *infile;
- int printflag;
- int *saw_usage;
- int comment;
+static int
+read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usage)
{
register int c;
struct rcsoc_state state;
state.in_file = infile;
- state.buf_ptr = (printflag < 0 ? buf : 0);
+ state.buf_ptr = (printflag < 0 ? input_buffer : 0);
state.out_file = (printflag > 0 ? outfile : 0);
state.pending_spaces = 0;
state.pending_newlines = 0;
@@ -450,16 +476,13 @@ read_c_string_or_comment (infile, printflag, comment, saw_usage)
/* Write to file OUT the argument names of function FUNC, whose text is in BUF.
MINARGS and MAXARGS are the minimum and maximum number of arguments. */
-void
-write_c_args (out, func, buf, minargs, maxargs)
- FILE *out;
- char *func, *buf;
- int minargs, maxargs;
+static void
+write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
{
register char *p;
int in_ident = 0;
- int just_spaced = 0;
- int need_space = 1;
+ char *ident_start;
+ size_t ident_length = 0;
fprintf (out, "(fn");
@@ -469,9 +492,8 @@ write_c_args (out, func, buf, minargs, maxargs)
for (p = buf; *p; p++)
{
char c = *p;
- int ident_start = 0;
- /* Notice when we start printing a new identifier. */
+ /* Notice when a new identifier starts. */
if ((('A' <= c && c <= 'Z')
|| ('a' <= c && c <= 'z')
|| ('0' <= c && c <= '9')
@@ -481,72 +503,161 @@ write_c_args (out, func, buf, minargs, maxargs)
if (!in_ident)
{
in_ident = 1;
- ident_start = 1;
+ ident_start = p;
+ }
+ else
+ {
+ in_ident = 0;
+ ident_length = p - ident_start;
+ }
+ }
+
+ /* Found the end of an argument, write out the last seen
+ identifier. */
+ if (c == ',' || c == ')')
+ {
+ if (ident_length == 0)
+ {
+ error ("empty arg list for `%s' should be (void), not ()", func);
+ continue;
+ }
- if (need_space)
- putc (' ', out);
+ if (strncmp (ident_start, "void", ident_length) == 0)
+ continue;
- if (minargs == 0 && maxargs > 0)
- fprintf (out, "&optional ");
- just_spaced = 1;
+ putc (' ', out);
- minargs--;
- maxargs--;
- }
+ if (minargs == 0 && maxargs > 0)
+ fprintf (out, "&optional ");
+
+ minargs--;
+ maxargs--;
+
+ /* In C code, `default' is a reserved word, so we spell it
+ `defalt'; unmangle that here. */
+ if (ident_length == 6 && strncmp (ident_start, "defalt", 6) == 0)
+ fprintf (out, "DEFAULT");
else
- in_ident = 0;
+ while (ident_length-- > 0)
+ {
+ c = *ident_start++;
+ if (c >= 'a' && c <= 'z')
+ /* Upcase the letter. */
+ c += 'A' - 'a';
+ else if (c == '_')
+ /* Print underscore as hyphen. */
+ c = '-';
+ putc (c, out);
+ }
}
+ }
+
+ putc (')', out);
+}
+
+/* The types of globals. */
+enum global_type
+{
+ EMACS_INTEGER,
+ BOOLEAN,
+ LISP_OBJECT,
+ INVALID
+};
+
+/* A single global. */
+struct global
+{
+ enum global_type type;
+ char *name;
+};
- /* Print the C argument list as it would appear in lisp:
- print underscores as hyphens, and print commas and newlines
- as spaces. Collapse adjacent spaces into one. */
- if (c == '_')
- c = '-';
- else if (c == ',' || c == '\n')
- c = ' ';
-
- /* In C code, `default' is a reserved word, so we spell it
- `defalt'; unmangle that here. */
- if (ident_start
- && strncmp (p, "defalt", 6) == 0
- && ! (('A' <= p[6] && p[6] <= 'Z')
- || ('a' <= p[6] && p[6] <= 'z')
- || ('0' <= p[6] && p[6] <= '9')
- || p[6] == '_'))
+/* 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)
+{
+ /* Ignore the one non-symbol that can occur. */
+ if (strcmp (name, "..."))
+ {
+ ++num_globals;
+
+ if (num_globals_allocated == 0)
+ {
+ num_globals_allocated = 100;
+ globals = xmalloc (num_globals_allocated * sizeof (struct global));
+ }
+ else if (num_globals == num_globals_allocated)
{
- fprintf (out, "DEFAULT");
- p += 5;
- in_ident = 0;
- just_spaced = 0;
+ num_globals_allocated *= 2;
+ globals = xrealloc (globals,
+ num_globals_allocated * sizeof (struct global));
}
- else if (c != ' ' || !just_spaced)
+
+ globals[num_globals - 1].type = type;
+ globals[num_globals - 1].name = name;
+ }
+}
+
+static int
+compare_globals (const void *a, const void *b)
+{
+ const struct global *ga = a;
+ const struct global *gb = b;
+ return strcmp (ga->name, gb->name);
+}
+
+static void
+write_globals (void)
+{
+ int i;
+ qsort (globals, num_globals, sizeof (struct global), compare_globals);
+ for (i = 0; i < num_globals; ++i)
+ {
+ char const *type;
+
+ switch (globals[i].type)
{
- if (c >= 'a' && c <= 'z')
- /* Upcase the letter. */
- c += 'A' - 'a';
- putc (c, out);
+ case EMACS_INTEGER:
+ type = "EMACS_INT";
+ break;
+ case BOOLEAN:
+ type = "int";
+ break;
+ case LISP_OBJECT:
+ type = "Lisp_Object";
+ break;
+ default:
+ fatal ("not a recognized DEFVAR_", 0);
}
- just_spaced = c == ' ';
- need_space = 0;
+ fprintf (outfile, " %s f_%s;\n", type, globals[i].name);
+ fprintf (outfile, "#define %s globals.f_%s\n",
+ globals[i].name, globals[i].name);
+ while (i + 1 < num_globals
+ && !strcmp (globals[i].name, globals[i + 1].name))
+ ++i;
}
+
+ fprintf (outfile, "};\n");
+ fprintf (outfile, "extern struct emacs_globals globals;\n");
}
+
/* Read through a c file. If a .o file is named,
the corresponding .c or .m file is read instead.
Looks for DEFUN constructs such as are defined in ../src/lisp.h.
Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
-int
-scan_c_file (filename, mode)
- char *filename, *mode;
+static int
+scan_c_file (char *filename, const char *mode)
{
FILE *infile;
register int c;
register int commas;
- register int defunflag;
- register int defvarperbufferflag;
- register int defvarflag;
int minargs, maxargs;
int extension = filename[strlen (filename) - 1];
@@ -578,6 +689,10 @@ scan_c_file (filename, mode)
while (!feof (infile))
{
int doc_keyword = 0;
+ int defunflag = 0;
+ int defvarperbufferflag = 0;
+ int defvarflag = 0;
+ enum global_type type = INVALID;
if (c != '\n' && c != '\r')
{
@@ -611,12 +726,24 @@ scan_c_file (filename, mode)
continue;
defvarflag = 1;
- defunflag = 0;
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 if (c == 'D')
{
@@ -628,11 +755,13 @@ scan_c_file (filename, mode)
continue;
c = getc (infile);
defunflag = c == 'U';
- defvarflag = 0;
- defvarperbufferflag = 0;
}
else continue;
+ if (generate_globals && (!defvarflag || defvarperbufferflag
+ || type == INVALID))
+ continue;
+
while (c != '(')
{
if (c < 0)
@@ -646,6 +775,34 @@ scan_c_file (filename, mode)
continue;
c = read_c_string_or_comment (infile, -1, 0, 0);
+ if (generate_globals)
+ {
+ int i = 0;
+ char *name;
+
+ /* Skip "," and whitespace. */
+ do
+ {
+ c = getc (infile);
+ }
+ while (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r');
+
+ /* Read in the identifier. */
+ do
+ {
+ input_buffer[i++] = c;
+ c = getc (infile);
+ }
+ while (! (c == ',' || c == ' ' || c == '\t' ||
+ c == '\n' || c == '\r'));
+ input_buffer[i] = '\0';
+
+ name = xmalloc (i + 1);
+ memcpy (name, input_buffer, i + 1);
+ add_global (type, name);
+ continue;
+ }
+
/* DEFVAR_LISP ("name", addr, "doc")
DEFVAR_LISP ("name", addr /\* doc *\/)
DEFVAR_LISP ("name", addr, doc: /\* doc *\/) */
@@ -653,7 +810,7 @@ scan_c_file (filename, mode)
if (defunflag)
commas = 5;
else if (defvarperbufferflag)
- commas = 2;
+ commas = 3;
else if (defvarflag)
commas = 1;
else /* For DEFSIMPLE and DEFPRED */
@@ -667,6 +824,7 @@ scan_c_file (filename, mode)
if (defunflag && (commas == 1 || commas == 2))
{
+ int scanned = 0;
do
c = getc (infile);
while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
@@ -674,12 +832,14 @@ scan_c_file (filename, mode)
goto eof;
ungetc (c, infile);
if (commas == 2) /* pick up minargs */
- fscanf (infile, "%d", &minargs);
+ scanned = fscanf (infile, "%d", &minargs);
else /* pick up maxargs */
if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
maxargs = -1;
else
- fscanf (infile, "%d", &maxargs);
+ scanned = fscanf (infile, "%d", &maxargs);
+ if (scanned < 0)
+ goto eof;
}
}
@@ -723,7 +883,7 @@ scan_c_file (filename, mode)
putc (037, outfile);
putc (defvarflag ? 'V' : 'F', outfile);
- fprintf (outfile, "%s\n", buf);
+ fprintf (outfile, "%s\n", input_buffer);
if (comment)
getc (infile); /* Skip past `*' */
@@ -766,11 +926,12 @@ scan_c_file (filename, mode)
*p = '\0';
/* Output them. */
fprintf (outfile, "\n\n");
- write_c_args (outfile, buf, argbuf, minargs, maxargs);
+ write_c_args (outfile, input_buffer, argbuf, minargs, maxargs);
}
else if (defunflag && maxargs == -1 && !saw_usage)
/* The DOC should provide the usage form. */
- fprintf (stderr, "Missing `usage' for function `%s'.\n", buf);
+ fprintf (stderr, "Missing `usage' for function `%s'.\n",
+ input_buffer);
}
}
eof:
@@ -814,9 +975,8 @@ scan_c_file (filename, mode)
An entry is output only if DOCSTRING has \ newline just after the opening "
*/
-void
-skip_white (infile)
- FILE *infile;
+static void
+skip_white (FILE *infile)
{
char c = ' ';
while (c == ' ' || c == '\t' || c == '\n' || c == '\r')
@@ -824,10 +984,8 @@ skip_white (infile)
ungetc (c, infile);
}
-void
-read_lisp_symbol (infile, buffer)
- FILE *infile;
- char *buffer;
+static void
+read_lisp_symbol (FILE *infile, char *buffer)
{
char c;
char *fillp = buffer;
@@ -854,14 +1012,16 @@ read_lisp_symbol (infile, buffer)
skip_white (infile);
}
-int
-scan_lisp_file (filename, mode)
- char *filename, *mode;
+static int
+scan_lisp_file (const char *filename, const char *mode)
{
FILE *infile;
register int c;
char *saved_string = 0;
+ if (generate_globals)
+ fatal ("scanning lisp file when -g specified", 0);
+
infile = fopen (filename, mode);
if (infile == NULL)
{
@@ -890,8 +1050,8 @@ scan_lisp_file (filename, mode)
c = getc (infile);
if (c == '@')
{
- int length = 0;
- int i;
+ size_t length = 0;
+ size_t i;
/* Read the length. */
while ((c = getc (infile),
@@ -901,6 +1061,12 @@ scan_lisp_file (filename, mode)
length += c - '0';
}
+ if (length <= 1)
+ fatal ("invalid dynamic doc string length", "");
+
+ if (c != ' ')
+ fatal ("space not found after dynamic doc string length", "");
+
/* The next character is a space that is counted in the length
but not part of the doc string.
We already read it, so just ignore it. */
@@ -916,7 +1082,7 @@ scan_lisp_file (filename, mode)
but it is redundant in DOC. So get rid of it here. */
saved_string[length - 1] = 0;
/* Skip the line break. */
- while (c == '\n' && c == '\r')
+ while (c == '\n' || c == '\r')
c = getc (infile);
/* Skip the following line. */
while (c != '\n' && c != '\r')
@@ -1222,7 +1388,5 @@ scan_lisp_file (filename, mode)
return 0;
}
-/* arch-tag: f7203aaf-991a-4238-acb5-601db56f2894
- (do not change this comment) */
/* make-docfile.c ends here */