X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0c382083b6b550c26fad8ac7f59b1ba09663e728..40d83b412f584cc02e68d4eac8fd5e6eb769e2fe:/lib-src/make-docfile.c diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index e2dc99214d..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,10 +66,12 @@ along with GNU Emacs. If not, see . */ #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) #endif -int scan_file (char *filename); -int scan_lisp_file (const char *filename, const char *mode); -int scan_c_file (char *filename, const char *mode); -void fatal (const char *s1, const char *s2) NO_RETURN; +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 @@ -78,9 +79,7 @@ void fatal (const char *s1, const char *s2) NO_RETURN; #undef chdir #endif -#ifdef HAVE_UNISTD_H #include -#endif /* Stdio stream for output to the DOC file. */ FILE *outfile; @@ -88,10 +87,13 @@ 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 +static void error (const char *s1, const char *s2) { fprintf (stderr, "%s: ", progname); @@ -102,7 +104,7 @@ error (const char *s1, const char *s2) /* Print error message and exit. */ /* VARARGS1 */ -void +static void fatal (const char *s1, const char *s2) { error (s1, s2); @@ -111,7 +113,7 @@ fatal (const char *s1, const char *s2) /* Like malloc but get fatal error if memory is exhausted. */ -void * +static void * xmalloc (unsigned int size) { void *result = (void *) malloc (size); @@ -119,6 +121,18 @@ xmalloc (unsigned int size) 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 (int argc, char **argv) @@ -160,13 +174,25 @@ main (int argc, char **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++) { @@ -178,11 +204,15 @@ main (int argc, char **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 +static void put_filename (char *filename) { char *tmp; @@ -201,13 +231,14 @@ put_filename (char *filename) /* Read file FILENAME and output its doc strings to outfile. */ /* Return 1 if file is not found, 0 if it is found. */ -int +static int scan_file (char *filename) { size_t len = strlen (filename); - put_filename (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")) @@ -215,8 +246,16 @@ scan_file (char *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 @@ -349,14 +388,14 @@ scan_keyword_or_put_char (int ch, struct rcsoc_state *state) at the beginning of a line will be removed, and *SAW_USAGE set to true if any were encountered. */ -int +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; @@ -437,7 +476,7 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa /* 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 +static void write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs) { register char *p; @@ -515,21 +554,110 @@ write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs) 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; +}; + +/* 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) + { + num_globals_allocated *= 2; + globals = xrealloc (globals, + num_globals_allocated * sizeof (struct global)); + } + + 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) + { + 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); + } + + 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 +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]; @@ -561,6 +689,10 @@ scan_c_file (char *filename, const char *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') { @@ -594,12 +726,24 @@ scan_c_file (char *filename, const char *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') { @@ -611,11 +755,13 @@ scan_c_file (char *filename, const char *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) @@ -629,6 +775,34 @@ scan_c_file (char *filename, const char *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 *\/) */ @@ -636,7 +810,7 @@ scan_c_file (char *filename, const char *mode) if (defunflag) commas = 5; else if (defvarperbufferflag) - commas = 2; + commas = 3; else if (defvarflag) commas = 1; else /* For DEFSIMPLE and DEFPRED */ @@ -650,6 +824,7 @@ scan_c_file (char *filename, const char *mode) if (defunflag && (commas == 1 || commas == 2)) { + int scanned = 0; do c = getc (infile); while (c == ' ' || c == '\n' || c == '\r' || c == '\t'); @@ -657,12 +832,14 @@ scan_c_file (char *filename, const char *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; } } @@ -706,7 +883,7 @@ scan_c_file (char *filename, const char *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 `*' */ @@ -749,11 +926,12 @@ scan_c_file (char *filename, const char *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: @@ -797,7 +975,7 @@ scan_c_file (char *filename, const char *mode) An entry is output only if DOCSTRING has \ newline just after the opening " */ -void +static void skip_white (FILE *infile) { char c = ' '; @@ -806,7 +984,7 @@ skip_white (FILE *infile) ungetc (c, infile); } -void +static void read_lisp_symbol (FILE *infile, char *buffer) { char c; @@ -834,13 +1012,16 @@ read_lisp_symbol (FILE *infile, char *buffer) skip_white (infile); } -int +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) { @@ -869,8 +1050,8 @@ scan_lisp_file (const char *filename, const char *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), @@ -880,6 +1061,12 @@ scan_lisp_file (const char *filename, const char *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. */ @@ -895,7 +1082,7 @@ scan_lisp_file (const char *filename, const char *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') @@ -1201,7 +1388,5 @@ scan_lisp_file (const char *filename, const char *mode) return 0; } -/* arch-tag: f7203aaf-991a-4238-acb5-601db56f2894 - (do not change this comment) */ /* make-docfile.c ends here */