X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/8c536f15bf95916d56bb50495d22b7da7e09fff9..8a28a5b8d8acb314d8850b85fe5cd956a86e8ff9:/lib-src/make-docfile.c diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index 1314a7b682..54a53c0d44 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -1,6 +1,7 @@ /* Generate doc-string file for GNU Emacs from source files. - Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2012 - Free Software Foundation, Inc. + +Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2013 Free Software +Foundation, Inc. This file is part of GNU Emacs. @@ -35,57 +36,41 @@ along with GNU Emacs. If not, see . */ #include -/* Defined to be emacs_main, sys_fopen, etc. in config.h. */ -#undef main -#undef fopen -#undef chdir - #include -#include +#include /* config.h unconditionally includes this anyway */ #ifdef MSDOS #include #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 #include #endif /* WINDOWSNT */ #ifdef DOS_NT +/* Defined to be sys_chdir in ms-w32.h, but only #ifdef emacs, so this + is really just insurance. + + 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 */ -#ifndef DIRECTORY_SEP -#define DIRECTORY_SEP '/' -#endif - -#ifndef IS_DIRECTORY_SEP -#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) -#endif - -/* Use this to suppress gcc's `...may be used before initialized' warnings. */ -#ifdef lint -# define IF_LINT(Code) Code -#else -# define IF_LINT(Code) /* empty */ -#endif - 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 - file where that function is defined. */ -#undef chdir -#endif - #include /* Stdio stream for output to the DOC file. */ @@ -111,7 +96,7 @@ error (const char *s1, const char *s2) /* Print error message and exit. */ /* VARARGS1 */ -static void +static _Noreturn void fatal (const char *s1, const char *s2) { error (s1, s2); @@ -542,7 +527,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 && strncmp (ident_start, "defalt", 6) == 0) + if (ident_length == 6 && memcmp (ident_start, "defalt", 6) == 0) fprintf (out, "DEFAULT"); else while (ident_length-- > 0) @@ -562,13 +547,15 @@ write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs) putc (')', out); } -/* The types of globals. */ +/* The types of globals. These are sorted roughly in decreasing alignment + order to avoid allocation gaps, except that functions are last. */ enum global_type { + INVALID, + LISP_OBJECT, EMACS_INTEGER, BOOLEAN, - LISP_OBJECT, - INVALID + FUNCTION, }; /* A single global. */ @@ -576,6 +563,7 @@ struct global { enum global_type type; char *name; + int value; }; /* All the variable names we saw while scanning C sources in `-g' @@ -585,7 +573,7 @@ int num_globals_allocated; struct global *globals; static void -add_global (enum global_type type, char *name) +add_global (enum global_type type, char *name, int value) { /* Ignore the one non-symbol that can occur. */ if (strcmp (name, "...")) @@ -606,6 +594,7 @@ add_global (enum global_type type, char *name) globals[num_globals - 1].type = type; globals[num_globals - 1].name = name; + globals[num_globals - 1].value = value; } } @@ -614,13 +603,24 @@ compare_globals (const void *a, const void *b) { const struct global *ga = a; const struct global *gb = b; + + if (ga->type != gb->type) + return ga->type - gb->type; + return strcmp (ga->name, gb->name); } +static void +close_emacs_globals (void) +{ + fprintf (outfile, "};\n"); + fprintf (outfile, "extern struct emacs_globals globals;\n"); +} + static void write_globals (void) { - int i; + int i, seen_defun = 0; qsort (globals, num_globals, sizeof (struct global), compare_globals); for (i = 0; i < num_globals; ++i) { @@ -632,25 +632,62 @@ write_globals (void) type = "EMACS_INT"; break; case BOOLEAN: - type = "int"; + type = "bool"; break; case LISP_OBJECT: type = "Lisp_Object"; break; + case FUNCTION: + if (!seen_defun) + { + close_emacs_globals (); + fprintf (outfile, "\n"); + seen_defun = 1; + } + break; default: fatal ("not a recognized DEFVAR_", 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); + if (globals[i].type != FUNCTION) + { + fprintf (outfile, " %s f_%s;\n", type, globals[i].name); + fprintf (outfile, "#define %s globals.f_%s\n", + 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"); + else + fprintf (outfile, "%d", globals[i].value); + fprintf (outfile, ");\n"); + } + while (i + 1 < num_globals && !strcmp (globals[i].name, globals[i + 1].name)) - ++i; + { + if (globals[i].type == FUNCTION + && globals[i].value != globals[i + 1].value) + error ("function '%s' defined twice with differing signatures", + globals[i].name); + ++i; + } } - fprintf (outfile, "};\n"); - fprintf (outfile, "extern struct emacs_globals globals;\n"); + if (!seen_defun) + close_emacs_globals (); } @@ -700,6 +737,7 @@ scan_c_file (char *filename, const char *mode) int defvarperbufferflag = 0; int defvarflag = 0; enum global_type type = INVALID; + char *name IF_LINT (= 0); if (c != '\n' && c != '\r') { @@ -765,8 +803,9 @@ scan_c_file (char *filename, const char *mode) } else continue; - if (generate_globals && (!defvarflag || defvarperbufferflag - || type == INVALID)) + if (generate_globals + && (!defvarflag || defvarperbufferflag || type == INVALID) + && !defunflag) continue; while (c != '(') @@ -785,7 +824,6 @@ scan_c_file (char *filename, const char *mode) if (generate_globals) { int i = 0; - char *name; /* Skip "," and whitespace. */ do @@ -806,8 +844,12 @@ scan_c_file (char *filename, const char *mode) name = xmalloc (i + 1); memcpy (name, input_buffer, i + 1); - add_global (type, name); - continue; + + if (!defunflag) + { + add_global (type, name, 0); + continue; + } } /* DEFVAR_LISP ("name", addr, "doc") @@ -815,7 +857,7 @@ scan_c_file (char *filename, const char *mode) DEFVAR_LISP ("name", addr, doc: /\* doc *\/) */ if (defunflag) - commas = 5; + commas = generate_globals ? 4 : 5; else if (defvarperbufferflag) commas = 3; else if (defvarflag) @@ -842,7 +884,12 @@ scan_c_file (char *filename, const char *mode) scanned = fscanf (infile, "%d", &minargs); else /* Pick up maxargs. */ if (c == 'M' || c == 'U') /* MANY || UNEVALLED */ - maxargs = -1; + { + if (generate_globals) + maxargs = (c == 'M') ? -1 : -2; + else + maxargs = -1; + } else scanned = fscanf (infile, "%d", &maxargs); if (scanned < 0) @@ -855,6 +902,12 @@ scan_c_file (char *filename, const char *mode) c = getc (infile); } + if (generate_globals) + { + add_global (FUNCTION, name, maxargs); + continue; + } + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') c = getc (infile); @@ -974,9 +1027,9 @@ scan_c_file (char *filename, const char *mode) arglist, but the doc string must still have a backslash and newline immediately after the double quote. The only source files that must follow this convention are preloaded - uncompiled ones like loaddefs.el and bindings.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. + uncompiled ones like loaddefs.el; aside from that, it is always the .elc + file that we should 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 ". @@ -1025,7 +1078,7 @@ search_lisp_doc_at_eol (FILE *infile) char c = 0, c1 = 0, c2 = 0; /* Skip until the end of line; remember two previous chars. */ - while (c != '\n' && c != '\r' && c >= 0) + while (c != '\n' && c != '\r' && c != EOF) { c2 = c1; c1 = c; @@ -1040,20 +1093,57 @@ search_lisp_doc_at_eol (FILE *infile) fprintf (stderr, "## non-docstring in %s (%s)\n", buffer, filename); #endif + if (c != EOF) + ungetc (c, infile); return 0; } return 1; } +#define DEF_ELISP_FILE(fn) { #fn, sizeof(#fn) - 1 } + static int scan_lisp_file (const char *filename, const char *mode) { FILE *infile; register int c; char *saved_string = 0; + /* These are the only files that are loaded uncompiled, and must + follow the conventions of the doc strings expected by this + function. These conventions are automatically followed by the + byte compiler when it produces the .elc files. */ + static struct { + const char *fn; + size_t fl; + } const uncompiled[] = { + DEF_ELISP_FILE (loaddefs.el), + DEF_ELISP_FILE (loadup.el), + DEF_ELISP_FILE (charprop.el), + DEF_ELISP_FILE (cp51932.el), + DEF_ELISP_FILE (eucjp-ms.el) + }; + int i, match; + size_t flen = strlen (filename); if (generate_globals) fatal ("scanning lisp file when -g specified", 0); + if (flen > 3 && !strcmp (filename + flen - 3, ".el")) + { + for (i = 0, match = 0; i < sizeof (uncompiled) / sizeof (uncompiled[0]); + i++) + { + if (uncompiled[i].fl <= flen + && !strcmp (filename + flen - uncompiled[i].fl, uncompiled[i].fn) + && (flen == uncompiled[i].fl + || IS_SLASH (filename[flen - uncompiled[i].fl - 1]))) + { + match = 1; + break; + } + } + if (!match) + fatal ("uncompiled lisp file %s is not supported", filename); + } infile = fopen (filename, mode); if (infile == NULL)