X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/86b0513a2cc57df26af9aa756384a13704abc924..39c41ad4211ebf2ce76fc49d9621adace0439399:/lib-src/make-docfile.c?ds=sidebyside diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index fbcebde144..bfdb206ad9 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -1,5 +1,6 @@ /* Generate doc-string file for GNU Emacs from source files. - Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1992, 1993, 1994, 1997, 1999, 2000, 2001, + 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,12 +16,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ /* The arguments given to this program are all the C and Lisp source files of GNU Emacs. .elc and .el and .c files are allowed. A .o file can also be specified; the .c file it was made from is used. This helps the makefile pass the correct list of files. + Option -d DIR means change to DIR before looking for files. The results, which go to standard output or to a file specified with -a or -o (-a to append, -o to start from nothing), @@ -31,6 +34,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ Then comes the documentation for that function or variable. */ +#define NO_SHORTNAMES /* Tell config not to load remap.h */ +#include + +/* defined to be emacs_main, sys_fopen, etc. in config.h */ +#undef main +#undef fopen +#undef chdir + #include #ifdef MSDOS #include @@ -49,12 +60,73 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READ_BINARY "r" #endif /* not DOS_NT */ +#ifndef DIRECTORY_SEP +#ifdef MAC_OS8 +#define DIRECTORY_SEP ':' +#else /* not MAC_OS8 */ +#define DIRECTORY_SEP '/' +#endif /* not MAC_OS8 */ +#endif + +#ifndef IS_DIRECTORY_SEP +#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) +#endif + int scan_file (); int scan_lisp_file (); int scan_c_file (); +#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 + +#ifdef HAVE_UNISTD_H +#include +#endif + +/* Stdio stream for output to the DOC file. */ FILE *outfile; +/* Name this program was invoked with. */ +char *progname; + +/* Print error message. `s1' is printf control string, `s2' is arg for it. */ + +/* VARARGS1 */ +void +error (s1, s2) + char *s1, *s2; +{ + fprintf (stderr, "%s: ", progname); + fprintf (stderr, s1, s2); + fprintf (stderr, "\n"); +} + +/* Print error message and exit. */ + +/* VARARGS1 */ +void +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + exit (EXIT_FAILURE); +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +void * +xmalloc (size) + unsigned int size; +{ + void *result = (void *) malloc (size); + if (result == NULL) + fatal ("virtual memory exhausted", 0); + return result; +} + int main (argc, argv) int argc; @@ -64,19 +136,25 @@ main (argc, argv) 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 */ - outfile = stdout; - /* If first two args are -o FILE, output to FILE. */ i = 1; if (argc > i + 1 && !strcmp (argv[i], "-o")) @@ -95,6 +173,9 @@ main (argc, argv) i += 2; } + if (outfile == 0) + fatal ("No output file specified", ""); + first_infile = i; for (; i < argc; i++) { @@ -106,10 +187,25 @@ main (argc, argv) if (j == i) err_count += scan_file (argv[i]); } -#ifndef VMS - exit (err_count > 0); -#endif /* VMS */ - return err_count > 0; + 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; +{ + char *tmp; + + for (tmp = filename; *tmp; tmp++) + { + if (IS_DIRECTORY_SEP(*tmp)) + filename = tmp + 1; + } + + putc (037, outfile); + putc ('S', outfile); + fprintf (outfile, "%s\n", filename); } /* Read file FILENAME and output its doc strings to outfile. */ @@ -120,9 +216,11 @@ scan_file (filename) char *filename; { int len = strlen (filename); - if (!strcmp (filename + len - 4, ".elc")) + + put_filename (filename); + if (len > 4 && !strcmp (filename + len - 4, ".elc")) return scan_lisp_file (filename, READ_BINARY); - else if (!strcmp (filename + len - 3, ".el")) + else if (len > 3 && !strcmp (filename + len - 3, ".el")) return scan_lisp_file (filename, READ_TEXT); else return scan_c_file (filename, READ_TEXT); @@ -130,30 +228,173 @@ scan_file (filename) char buf[128]; -/* Skip a C string from INFILE, - and return the character that follows the closing ". - If 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. */ +/* Some state during the execution of `read_c_string_or_comment'. */ +struct rcsoc_state +{ + /* A count of spaces and newlines that have been read, but not output. */ + unsigned pending_spaces, pending_newlines; + + /* Where we're reading from. */ + FILE *in_file; + + /* If non-zero, a buffer into which to copy characters. */ + char *buf_ptr; + /* If non-zero, a file into which to copy characters. */ + FILE *out_file; + + /* 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 + the input stream. */ + char *cur_keyword_ptr; + /* Set to true if we saw an occurance of KEYWORD. */ + int saw_keyword; +}; + +/* Output CH to the file or buffer in STATE. Any pending newlines or + spaces are output first. */ + +static INLINE void +put_char (ch, state) + int ch; + struct rcsoc_state *state; +{ + int out_ch; + do + { + if (state->pending_newlines > 0) + { + state->pending_newlines--; + out_ch = '\n'; + } + else if (state->pending_spaces > 0) + { + state->pending_spaces--; + out_ch = ' '; + } + else + out_ch = ch; + + if (state->out_file) + putc (out_ch, state->out_file); + if (state->buf_ptr) + *state->buf_ptr++ = out_ch; + } + while (out_ch != ch); +} + +/* If in the middle of scanning a keyword, continue scanning with + character CH, otherwise output CH to the file or buffer in STATE. + Any pending newlines or spaces are output first, as well as any + previously scanned characters that were thought to be part of a + keyword, but were in fact not. */ + +static void +scan_keyword_or_put_char (ch, state) + int ch; + struct rcsoc_state *state; +{ + if (state->keyword + && *state->cur_keyword_ptr == ch + && (state->cur_keyword_ptr > state->keyword + || state->pending_newlines > 0)) + /* We might be looking at STATE->keyword at some point. + Keep looking until we know for sure. */ + { + if (*++state->cur_keyword_ptr == '\0') + /* Saw the whole keyword. Set SAW_KEYWORD flag to true. */ + { + state->saw_keyword = 1; + + /* Reset the scanning pointer. */ + state->cur_keyword_ptr = state->keyword; + + /* Canonicalize whitespace preceding a usage string. */ + state->pending_newlines = 2; + state->pending_spaces = 0; + + /* Skip any whitespace between the keyword and the + usage string. */ + do + ch = getc (state->in_file); + while (ch == ' ' || ch == '\n'); + + /* Output the open-paren we just read. */ + put_char (ch, state); + + /* Skip the function name and replace it with `fn'. */ + do + ch = getc (state->in_file); + while (ch != ' ' && ch != ')'); + put_char ('f', state); + put_char ('n', state); + + /* Put back the last character. */ + ungetc (ch, state->in_file); + } + } + else + { + if (state->keyword && state->cur_keyword_ptr > state->keyword) + /* We scanned the beginning of a potential usage + keyword, but it was a false alarm. Output the + part we scanned. */ + { + char *p; + + for (p = state->keyword; p < state->cur_keyword_ptr; p++) + put_char (*p, state); + + state->cur_keyword_ptr = state->keyword; + } + + put_char (ch, 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 + 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:' + at the beginning of a line will be removed, and *SAW_USAGE set to + true if any were encountered. */ int -read_c_string (infile, printflag) +read_c_string_or_comment (infile, printflag, comment, saw_usage) FILE *infile; int printflag; + int *saw_usage; + int comment; { register int c; - char *p = buf; + struct rcsoc_state state; + + state.in_file = infile; + state.buf_ptr = (printflag < 0 ? buf : 0); + state.out_file = (printflag > 0 ? outfile : 0); + state.pending_spaces = 0; + state.pending_newlines = 0; + state.keyword = (saw_usage ? "usage:" : 0); + state.cur_keyword_ptr = state.keyword; + state.saw_keyword = 0; c = getc (infile); + if (comment) + while (c == '\n' || c == '\r' || c == '\t' || c == ' ') + c = getc (infile); + while (c != EOF) { - while (c != '"' && c != EOF) + while (c != EOF && (comment ? c != '*' : c != '"')) { if (c == '\\') { c = getc (infile); - if (c == '\n') + if (c == '\n' || c == '\r') { c = getc (infile); continue; @@ -163,24 +404,53 @@ read_c_string (infile, printflag) if (c == 't') c = '\t'; } - if (printflag > 0) - putc (c, outfile); - else if (printflag < 0) - *p++ = c; + + if (c == ' ') + state.pending_spaces++; + else if (c == '\n') + { + state.pending_newlines++; + state.pending_spaces = 0; + } + else + scan_keyword_or_put_char (c, &state); + + c = getc (infile); + } + + if (c != EOF) + c = getc (infile); + + if (comment) + { + if (c == '/') + { + c = getc (infile); + break; + } + + scan_keyword_or_put_char ('*', &state); + } + else + { + if (c != '"') + break; + + /* If we had a "", concatenate the two strings. */ c = getc (infile); } - c = getc (infile); - if (c != '"') - break; - /* If we had a "", concatenate the two strings. */ - c = getc (infile); } if (printflag < 0) - *p = 0; + *state.buf_ptr = 0; + + if (saw_usage) + *saw_usage = state.saw_keyword; return c; } + + /* 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. */ @@ -196,7 +466,7 @@ write_c_args (out, func, buf, minargs, maxargs) int just_spaced = 0; int need_space = 1; - fprintf (out, "(%s", func); + fprintf (out, "(fn"); if (*buf == '(') ++buf; @@ -233,10 +503,12 @@ write_c_args (out, func, buf, minargs, maxargs) } /* 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 = ' '; + 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. */ @@ -252,7 +524,7 @@ write_c_args (out, func, buf, minargs, maxargs) in_ident = 0; just_spaced = 0; } - else if (c != ' ' || ! just_spaced) + else if (c != ' ' || !just_spaced) { if (c >= 'a' && c <= 'z') /* Upcase the letter. */ @@ -260,7 +532,7 @@ write_c_args (out, func, buf, minargs, maxargs) putc (c, out); } - just_spaced = (c == ' '); + just_spaced = c == ' '; need_space = 0; } } @@ -281,8 +553,9 @@ scan_c_file (filename, mode) register int defvarperbufferflag; register int defvarflag; int minargs, maxargs; + int extension = filename[strlen (filename) - 1]; - if (filename[strlen (filename) - 1] == 'o') + if (extension == 'o') filename[strlen (filename) - 1] = 'c'; infile = fopen (filename, mode); @@ -294,10 +567,15 @@ scan_c_file (filename, mode) return 0; } + /* Reset extension to be able to detect duplicate files. */ + filename[strlen (filename) - 1] = extension; + c = '\n'; while (!feof (infile)) { - if (c != '\n') + int doc_keyword = 0; + + if (c != '\n' && c != '\r') { c = getc (infile); continue; @@ -347,6 +625,7 @@ scan_c_file (filename, mode) c = getc (infile); defunflag = c == 'U'; defvarflag = 0; + defvarperbufferflag = 0; } else continue; @@ -357,10 +636,15 @@ scan_c_file (filename, mode) c = getc (infile); } + /* Lisp variable or function name. */ c = getc (infile); if (c != '"') continue; - c = read_c_string (infile, -1); + c = read_c_string_or_comment (infile, -1, 0, 0); + + /* DEFVAR_LISP ("name", addr, "doc") + DEFVAR_LISP ("name", addr /\* doc *\/) + DEFVAR_LISP ("name", addr, doc: /\* doc *\/) */ if (defunflag) commas = 5; @@ -376,11 +660,12 @@ scan_c_file (filename, mode) if (c == ',') { commas--; + if (defunflag && (commas == 1 || commas == 2)) { do c = getc (infile); - while (c == ' ' || c == '\n' || c == '\t'); + while (c == ' ' || c == '\n' || c == '\r' || c == '\t'); if (c < 0) goto eof; ungetc (c, infile); @@ -393,40 +678,75 @@ scan_c_file (filename, mode) fscanf (infile, "%d", &maxargs); } } - if (c < 0) + + if (c == EOF) goto eof; c = getc (infile); } - while (c == ' ' || c == '\n' || c == '\t') + + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') c = getc (infile); + if (c == '"') - c = read_c_string (infile, 0); - while (c != ',') - c = getc (infile); - c = getc (infile); - while (c == ' ' || c == '\n' || c == '\t') + c = read_c_string_or_comment (infile, 0, 0, 0); + + while (c != EOF && c != ',' && c != '/') c = getc (infile); + if (c == ',') + { + c = getc (infile); + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') + c = getc (infile); + while ((c >= 'a' && c <= 'z') || (c >= 'Z' && c <= 'Z')) + c = getc (infile); + if (c == ':') + { + doc_keyword = 1; + c = getc (infile); + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') + c = getc (infile); + } + } - if (c == '"') + if (c == '"' + || (c == '/' + && (c = getc (infile), + ungetc (c, infile), + c == '*'))) { + int comment = c != '"'; + int saw_usage; + putc (037, outfile); putc (defvarflag ? 'V' : 'F', outfile); fprintf (outfile, "%s\n", buf); - c = read_c_string (infile, 1); + + if (comment) + getc (infile); /* Skip past `*' */ + c = read_c_string_or_comment (infile, 1, comment, &saw_usage); /* If this is a defun, find the arguments and print them. If this function takes MANY or UNEVALLED args, then the C source won't give the names of the arguments, so we shouldn't bother - trying to find them. */ - if (defunflag && maxargs != -1) + trying to find them. + + Various doc-string styles: + 0: DEFUN (..., "DOC") (args) [!comment] + 1: DEFUN (..., /\* DOC *\/ (args)) [comment && !doc_keyword] + 2: DEFUN (..., doc: /\* DOC *\/) (args) [comment && doc_keyword] + */ + if (defunflag && maxargs != -1 && !saw_usage) { char argbuf[1024], *p = argbuf; - while (c != ')') - { - if (c < 0) - goto eof; - c = getc (infile); - } + + if (!comment || doc_keyword) + while (c != ')') + { + if (c < 0) + goto eof; + c = getc (infile); + } + /* Skip into arguments. */ while (c != '(') { @@ -444,6 +764,9 @@ scan_c_file (filename, mode) fprintf (outfile, "\n\n"); write_c_args (outfile, buf, 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); } } eof: @@ -455,21 +778,31 @@ scan_c_file (filename, mode) Looks for (defun NAME ARGS DOCSTRING ...) (defmacro NAME ARGS DOCSTRING ...) + (defsubst NAME ARGS DOCSTRING ...) (autoload (quote NAME) FILE DOCSTRING ...) (defvar NAME VALUE DOCSTRING) (defconst NAME VALUE DOCSTRING) (fset (quote NAME) (make-byte-code ... DOCSTRING ...)) (fset (quote NAME) #[... DOCSTRING ...]) (defalias (quote NAME) #[... DOCSTRING ...]) + (custom-declare-variable (quote NAME) VALUE DOCSTRING ...) starting in column zero. (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 kludgy + + We also look for #@LENGTH CONTENTS^_ at the beginning of the line. + When we find that, we save it for the following defining-form, + and we use that instead of reading a doc string within that defining-form. + + For defvar, defconst, and fset we skip to the docstring with a kludgy 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 + initial open-paren (the one in column zero) and must contain a backslash + and a newline 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 + For defun, defmacro, and autoload, we know how to skip over the + 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. The NAME and DOCSTRING are output. @@ -482,7 +815,7 @@ skip_white (infile) FILE *infile; { char c = ' '; - while (c == ' ' || c == '\t' || c == '\n') + while (c == ' ' || c == '\t' || c == '\n' || c == '\r') c = getc (infile); ungetc (c, infile); } @@ -501,7 +834,7 @@ read_lisp_symbol (infile, buffer) c = getc (infile); if (c == '\\') *(++fillp) = getc (infile); - else if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')') + else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '(' || c == ')') { ungetc (c, infile); *fillp = 0; @@ -513,7 +846,7 @@ read_lisp_symbol (infile, buffer) if (! buffer[0]) fprintf (stderr, "## expected a symbol, got '%c'\n", c); - + skip_white (infile); } @@ -523,6 +856,7 @@ scan_lisp_file (filename, mode) { FILE *infile; register int c; + char *saved_string = 0; infile = fopen (filename, mode); if (infile == NULL) @@ -534,22 +868,68 @@ scan_lisp_file (filename, mode) c = '\n'; while (!feof (infile)) { - char buffer [BUFSIZ]; + char buffer[BUFSIZ]; char type; - if (c != '\n') + /* If not at end of line, skip till we get to one. */ + if (c != '\n' && c != '\r') { c = getc (infile); continue; } - c = getc (infile); + /* Skip the line break. */ + while (c == '\n' || c == '\r') + c = getc (infile); + /* Detect a dynamic doc string and save it for the next expression. */ + if (c == '#') + { + c = getc (infile); + if (c == '@') + { + int length = 0; + int i; + + /* Read the length. */ + while ((c = getc (infile), + c >= '0' && c <= '9')) + { + length *= 10; + length += c - '0'; + } + + /* 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. */ + length--; + + /* Read in the contents. */ + if (saved_string != 0) + free (saved_string); + saved_string = (char *) malloc (length); + for (i = 0; i < length; i++) + saved_string[i] = getc (infile); + /* The last character is a ^_. + That is needed in the .elc file + 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') + c = getc (infile); + /* Skip the following line. */ + while (c != '\n' && c != '\r') + c = getc (infile); + } + continue; + } + if (c != '(') continue; read_lisp_symbol (infile, buffer); - if (! strcmp (buffer, "defun") || - ! strcmp (buffer, "defmacro")) + if (! strcmp (buffer, "defun") + || ! strcmp (buffer, "defmacro") + || ! strcmp (buffer, "defsubst")) { type = 'F'; read_lisp_symbol (infile, buffer); @@ -559,8 +939,8 @@ scan_lisp_file (filename, mode) c = getc (infile); if (c == 'n') /* nil */ { - if ((c = getc (infile)) != 'i' || - (c = getc (infile)) != 'l') + if ((c = getc (infile)) != 'i' + || (c = getc (infile)) != 'l') { fprintf (stderr, "## unparsable arglist in %s (%s)\n", buffer, filename); @@ -581,9 +961,9 @@ scan_lisp_file (filename, mode) /* 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 = getc (infile)) != '"' + || (c = getc (infile)) != '\\' + || ((c = getc (infile)) != '\n' && c != '\r')) { #ifdef DEBUG fprintf (stderr, "## non-docstring in %s (%s)\n", @@ -593,30 +973,93 @@ scan_lisp_file (filename, mode) } } - else if (! strcmp (buffer, "defvar") || - ! strcmp (buffer, "defconst")) + else if (! strcmp (buffer, "defvar") + || ! strcmp (buffer, "defconst")) { char c1 = 0, c2 = 0; type = 'V'; read_lisp_symbol (infile, buffer); - /* Skip until the first newline; remember the two previous chars. */ - while (c != '\n' && c >= 0) + if (saved_string == 0) + { + + /* Skip until the end of line; remember two previous chars. */ + while (c != '\n' && c != '\r' && c >= 0) + { + 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 != '\\') + { +#ifdef DEBUG + fprintf (stderr, "## non-docstring in %s (%s)\n", + buffer, filename); +#endif + continue; + } + } + } + + else if (! strcmp (buffer, "custom-declare-variable")) + { + char c1 = 0, c2 = 0; + type = 'V'; + + c = getc (infile); + if (c == '\'') + read_lisp_symbol (infile, buffer); + else { - c2 = c1; - c1 = c; + if (c != '(') + { + fprintf (stderr, + "## unparsable name in custom-declare-variable in %s\n", + filename); + continue; + } + read_lisp_symbol (infile, buffer); + if (strcmp (buffer, "quote")) + { + fprintf (stderr, + "## unparsable name in custom-declare-variable in %s\n", + filename); + continue; + } + read_lisp_symbol (infile, buffer); c = getc (infile); + if (c != ')') + { + fprintf (stderr, + "## unparsable quoted name in custom-declare-variable in %s\n", + filename); + continue; + } } - - /* If two previous characters were " and \, - this is a doc string. Otherwise, there is none. */ - if (c2 != '"' || c1 != '\\') + + if (saved_string == 0) { + /* Skip to end of line; remember the two previous chars. */ + while (c != '\n' && c != '\r' && c >= 0) + { + 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 != '\\') + { #ifdef DEBUG - fprintf (stderr, "## non-docstring in %s (%s)\n", - buffer, filename); + fprintf (stderr, "## non-docstring in %s (%s)\n", + buffer, filename); #endif - continue; + continue; + } } } @@ -654,23 +1097,26 @@ scan_lisp_file (filename, mode) } } - /* Skip until the first newline; remember the two previous chars. */ - while (c != '\n' && c >= 0) - { - 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 != '\\') + if (saved_string == 0) { + /* Skip to end of line; remember the two previous chars. */ + while (c != '\n' && c != '\r' && c >= 0) + { + 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 != '\\') + { #ifdef DEBUG - fprintf (stderr, "## non-docstring in %s (%s)\n", - buffer, filename); + fprintf (stderr, "## non-docstring in %s (%s)\n", + buffer, filename); #endif - continue; + continue; + } } } @@ -712,27 +1158,29 @@ scan_lisp_file (filename, mode) buffer, filename); continue; } - read_c_string (infile, 0); + read_c_string_or_comment (infile, 0, 0, 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 (saved_string == 0) { + /* 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' && c != '\r')) + { #ifdef DEBUG - fprintf (stderr, "## non-docstring in %s (%s)\n", - buffer, filename); + fprintf (stderr, "## non-docstring in %s (%s)\n", + buffer, filename); #endif - continue; + continue; + } } } #ifdef DEBUG - else if (! strcmp (buffer, "if") || - ! strcmp (buffer, "byte-code")) + else if (! strcmp (buffer, "if") + || ! strcmp (buffer, "byte-code")) ; #endif @@ -745,15 +1193,31 @@ scan_lisp_file (filename, mode) continue; } - /* At this point, there is a docstring that we should gobble. - The opening quote (and leading backslash-newline) have already - been read. - */ + /* At this point, we should either use the previous + dynamic doc string in saved_string + or gobble a doc string from the input file. + + 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); - read_c_string (infile, 1); + if (saved_string) + { + fputs (saved_string, outfile); + /* Don't use one dynamic doc string twice. */ + free (saved_string); + saved_string = 0; + } + else + read_c_string_or_comment (infile, 1, 0, 0); } fclose (infile); return 0; } + +/* arch-tag: f7203aaf-991a-4238-acb5-601db56f2894 + (do not change this comment) */ + +/* make-docfile.c ends here */