make-docfile cleanup for I/O, etc.

* lib-src/make-docfile.c (progname, generate_globals, num_globals)
(num_globals_allocated, globals): Now static.
(generate_globals, struct rcsoc_state, read_c_string_or_comment):
(write_c_args, scan_c_stream, search_lisp_doc_at_eol, scan_lisp_file):
Use bool for boolean.
(verror): New function.
(fatal, error): Use it.  API is now like printf.  All callers changed.
(main): Remove err_count local that was always 0.
(main, scan_c_stream, scan_lisp_file): Check for I/O error.
(scan_file, scan_c_file, scan_c_stream, scan_lisp_file):
Return void, not 0.
(put_char, scan_keyword_or_put_char, scan_c_file): Use char for byte.
(scan_keyword_or_put_char): Check for missing ( and unexpected EOF.
(close_emacs_globals): Use ptrdiff_t for index, not int.
(scan_c_file, scan_lisp_file): Exit with failure if file cannot be
opened, rather than diagnosing but exiting with status 0.
(search_lisp_doc_at_eol): Don't worry about ungetc of EOF; it's
portable now.
This commit is contained in:
Paul Eggert 2016-02-10 11:40:09 -08:00
parent 25ec995c06
commit 456c0a3137

View file

@ -65,46 +65,58 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#define IS_SLASH(c) ((c) == '/') #define IS_SLASH(c) ((c) == '/')
#endif /* not DOS_NT */ #endif /* not DOS_NT */
static int scan_file (char *filename); static void scan_file (char *filename);
static int scan_lisp_file (const char *filename, const char *mode); static void scan_lisp_file (const char *filename, const char *mode);
static int scan_c_file (char *filename, const char *mode); static void scan_c_file (char *filename, const char *mode);
static int scan_c_stream (FILE *infile); static void scan_c_stream (FILE *infile);
static void start_globals (void); static void start_globals (void);
static void write_globals (void); static void write_globals (void);
#include <unistd.h> #include <unistd.h>
/* Name this program was invoked with. */ /* Name this program was invoked with. */
char *progname; static char *progname;
/* Nonzero if this invocation is generating globals.h. */ /* True if this invocation is generating globals.h. */
int generate_globals; static bool generate_globals;
/* Print error message. `s1' is printf control string, `s2' is arg for it. */ /* Print error message. Args are like vprintf. */
/* VARARGS1 */ static void ATTRIBUTE_FORMAT_PRINTF (1, 0)
static void verror (char const *m, va_list ap)
error (const char *s1, const char *s2)
{ {
fprintf (stderr, "%s: ", progname); fprintf (stderr, "%s: ", progname);
fprintf (stderr, s1, s2); vfprintf (stderr, m, ap);
fprintf (stderr, "\n"); fprintf (stderr, "\n");
} }
/* Print error message and exit. */ /* Print error message. Args are like printf. */
/* VARARGS1 */ static void ATTRIBUTE_FORMAT_PRINTF (1, 2)
static _Noreturn void error (char const *m, ...)
fatal (const char *s1, const char *s2)
{ {
error (s1, s2); va_list ap;
va_start (ap, m);
verror (m, ap);
va_end (ap);
}
/* Print error message and exit. Args are like printf. */
static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (1, 2)
fatal (char const *m, ...)
{
va_list ap;
va_start (ap, m);
verror (m, ap);
va_end (ap);
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
static _Noreturn void static _Noreturn void
memory_exhausted (void) memory_exhausted (void)
{ {
fatal ("virtual memory exhausted", 0); fatal ("virtual memory exhausted");
} }
/* Like malloc but get fatal error if memory is exhausted. */ /* Like malloc but get fatal error if memory is exhausted. */
@ -134,7 +146,6 @@ int
main (int argc, char **argv) main (int argc, char **argv)
{ {
int i; int i;
int err_count = 0;
progname = argv[0]; progname = argv[0];
@ -169,7 +180,7 @@ main (int argc, char **argv)
} }
if (argc > i && !strcmp (argv[i], "-g")) if (argc > i && !strcmp (argv[i], "-g"))
{ {
generate_globals = 1; generate_globals = true;
++i; ++i;
} }
@ -191,14 +202,17 @@ main (int argc, char **argv)
if (strcmp (argv[i], argv[j]) == 0) if (strcmp (argv[i], argv[j]) == 0)
break; break;
if (j == i) if (j == i)
err_count += scan_file (argv[i]); scan_file (argv[i]);
} }
} }
if (err_count == 0 && generate_globals) if (generate_globals)
write_globals (); write_globals ();
return (err_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS); if (ferror (stdout) || fclose (stdout) != 0)
fatal ("write error");
return EXIT_SUCCESS;
} }
/* Add a source file name boundary marker in the output file. */ /* Add a source file name boundary marker in the output file. */
@ -217,9 +231,9 @@ put_filename (char *filename)
} }
/* Read file FILENAME and output its doc strings to stdout. /* Read file FILENAME and output its doc strings to stdout.
Return 1 if file is not found, 0 if it is found. */ Return true if file is found, false otherwise. */
static int static void
scan_file (char *filename) scan_file (char *filename)
{ {
ptrdiff_t len = strlen (filename); ptrdiff_t len = strlen (filename);
@ -227,11 +241,11 @@ scan_file (char *filename)
if (!generate_globals) if (!generate_globals)
put_filename (filename); put_filename (filename);
if (len > 4 && !strcmp (filename + len - 4, ".elc")) if (len > 4 && !strcmp (filename + len - 4, ".elc"))
return scan_lisp_file (filename, "rb"); scan_lisp_file (filename, "rb");
else if (len > 3 && !strcmp (filename + len - 3, ".el")) else if (len > 3 && !strcmp (filename + len - 3, ".el"))
return scan_lisp_file (filename, "r"); scan_lisp_file (filename, "r");
else else
return scan_c_file (filename, "r"); scan_c_file (filename, "r");
} }
static void static void
@ -265,16 +279,16 @@ struct rcsoc_state
the input stream. */ the input stream. */
const char *cur_keyword_ptr; const char *cur_keyword_ptr;
/* Set to true if we saw an occurrence of KEYWORD. */ /* Set to true if we saw an occurrence of KEYWORD. */
int saw_keyword; bool saw_keyword;
}; };
/* Output CH to the file or buffer in STATE. Any pending newlines or /* Output CH to the file or buffer in STATE. Any pending newlines or
spaces are output first. */ spaces are output first. */
static void static void
put_char (int ch, struct rcsoc_state *state) put_char (char ch, struct rcsoc_state *state)
{ {
int out_ch; char out_ch;
do do
{ {
if (state->pending_newlines > 0) if (state->pending_newlines > 0)
@ -305,7 +319,7 @@ put_char (int ch, struct rcsoc_state *state)
keyword, but were in fact not. */ keyword, but were in fact not. */
static void static void
scan_keyword_or_put_char (int ch, struct rcsoc_state *state) scan_keyword_or_put_char (char ch, struct rcsoc_state *state)
{ {
if (state->keyword if (state->keyword
&& *state->cur_keyword_ptr == ch && *state->cur_keyword_ptr == ch
@ -317,7 +331,7 @@ scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
if (*++state->cur_keyword_ptr == '\0') if (*++state->cur_keyword_ptr == '\0')
/* Saw the whole keyword. Set SAW_KEYWORD flag to true. */ /* Saw the whole keyword. Set SAW_KEYWORD flag to true. */
{ {
state->saw_keyword = 1; state->saw_keyword = true;
/* Reset the scanning pointer. */ /* Reset the scanning pointer. */
state->cur_keyword_ptr = state->keyword; state->cur_keyword_ptr = state->keyword;
@ -328,22 +342,29 @@ scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
/* Skip any whitespace between the keyword and the /* Skip any whitespace between the keyword and the
usage string. */ usage string. */
int c;
do do
ch = getc (state->in_file); c = getc (state->in_file);
while (ch == ' ' || ch == '\n'); while (c == ' ' || c == '\n');
/* Output the open-paren we just read. */ /* Output the open-paren we just read. */
put_char (ch, state); if (c != '(')
fatal ("Missing '(' after keyword");
put_char (c, state);
/* Skip the function name and replace it with `fn'. */ /* Skip the function name and replace it with `fn'. */
do do
ch = getc (state->in_file); {
while (ch != ' ' && ch != ')'); c = getc (state->in_file);
if (c == EOF)
fatal ("Unexpected EOF after keyword");
}
while (c != ' ' && c != ')');
put_char ('f', state); put_char ('f', state);
put_char ('n', state); put_char ('n', state);
/* Put back the last character. */ /* Put back the last character. */
ungetc (ch, state->in_file); ungetc (c, state->in_file);
} }
} }
else else
@ -367,18 +388,19 @@ scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
/* Skip a C string or C-style comment from INFILE, and return the /* Skip a C string or C-style comment from INFILE, and return the
character that follows. COMMENT non-zero means skip a comment. If byte that follows, or EOF. COMMENT means skip a comment. If
PRINTFLAG is positive, output string contents to stdout. If it is PRINTFLAG is positive, output string contents to stdout. If it is
negative, store contents in buf. Convert escape sequences \n and negative, store contents in buf. Convert escape sequences \n and
\t to newline and tab; discard \ followed by newline. \t to newline and tab; discard \ followed by newline.
If SAW_USAGE is non-zero, then any occurrences of the string `usage:' If SAW_USAGE is non-null, then any occurrences of the string "usage:"
at the beginning of a line will be removed, and *SAW_USAGE set to at the beginning of a line will be removed, and *SAW_USAGE set to
true if any were encountered. */ true if any were encountered. */
static int static int
read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usage) read_c_string_or_comment (FILE *infile, int printflag, bool comment,
bool *saw_usage)
{ {
register int c; int c;
struct rcsoc_state state; struct rcsoc_state state;
state.in_file = infile; state.in_file = infile;
@ -388,7 +410,7 @@ read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usa
state.pending_newlines = 0; state.pending_newlines = 0;
state.keyword = (saw_usage ? "usage:" : 0); state.keyword = (saw_usage ? "usage:" : 0);
state.cur_keyword_ptr = state.keyword; state.cur_keyword_ptr = state.keyword;
state.saw_keyword = 0; state.saw_keyword = false;
c = getc (infile); c = getc (infile);
if (comment) if (comment)
@ -467,7 +489,7 @@ static void
write_c_args (char *func, char *buf, int minargs, int maxargs) write_c_args (char *func, char *buf, int minargs, int maxargs)
{ {
char *p; char *p;
int in_ident = 0; bool in_ident = false;
char *ident_start IF_LINT (= NULL); char *ident_start IF_LINT (= NULL);
ptrdiff_t ident_length = 0; ptrdiff_t ident_length = 0;
@ -489,12 +511,12 @@ write_c_args (char *func, char *buf, int minargs, int maxargs)
{ {
if (!in_ident) if (!in_ident)
{ {
in_ident = 1; in_ident = true;
ident_start = p; ident_start = p;
} }
else else
{ {
in_ident = 0; in_ident = false;
ident_length = p - ident_start; ident_length = p - ident_start;
} }
} }
@ -573,9 +595,9 @@ enum { DEFUN_noreturn = 1, DEFUN_const = 2 };
/* All the variable names we saw while scanning C sources in `-g' /* All the variable names we saw while scanning C sources in `-g'
mode. */ mode. */
ptrdiff_t num_globals; static ptrdiff_t num_globals;
ptrdiff_t num_globals_allocated; static ptrdiff_t num_globals_allocated;
struct global *globals; static struct global *globals;
static struct global * static struct global *
add_global (enum global_type type, char const *name, int value, add_global (enum global_type type, char const *name, int value,
@ -636,7 +658,7 @@ compare_globals (const void *a, const void *b)
} }
static void static void
close_emacs_globals (int num_symbols) close_emacs_globals (ptrdiff_t num_symbols)
{ {
printf (("};\n" printf (("};\n"
"extern struct emacs_globals globals;\n" "extern struct emacs_globals globals;\n"
@ -644,7 +666,7 @@ close_emacs_globals (int num_symbols)
"#ifndef DEFINE_SYMBOLS\n" "#ifndef DEFINE_SYMBOLS\n"
"extern\n" "extern\n"
"#endif\n" "#endif\n"
"struct Lisp_Symbol alignas (GCALIGNMENT) lispsym[%d];\n"), "struct Lisp_Symbol alignas (GCALIGNMENT) lispsym[%td];\n"),
num_symbols); num_symbols);
} }
@ -700,7 +722,7 @@ write_globals (void)
} }
break; break;
default: default:
fatal ("not a recognized DEFVAR_", 0); fatal ("not a recognized DEFVAR_");
} }
if (type) if (type)
@ -761,11 +783,11 @@ write_globals (void)
Looks for DEFUN constructs such as are defined in ../src/lisp.h. Looks for DEFUN constructs such as are defined in ../src/lisp.h.
Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */ Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
static int static void
scan_c_file (char *filename, const char *mode) scan_c_file (char *filename, const char *mode)
{ {
FILE *infile; FILE *infile;
int extension = filename[strlen (filename) - 1]; char extension = filename[strlen (filename) - 1];
if (extension == 'o') if (extension == 'o')
filename[strlen (filename) - 1] = 'c'; filename[strlen (filename) - 1] = 'c';
@ -781,16 +803,15 @@ scan_c_file (char *filename, const char *mode)
filename[strlen (filename) - 1] = 'c'; /* Don't confuse people. */ filename[strlen (filename) - 1] = 'c'; /* Don't confuse people. */
} }
/* No error if non-ex input file. */
if (infile == NULL) if (infile == NULL)
{ {
perror (filename); perror (filename);
return 0; exit (EXIT_FAILURE);
} }
/* Reset extension to be able to detect duplicate files. */ /* Reset extension to be able to detect duplicate files. */
filename[strlen (filename) - 1] = extension; filename[strlen (filename) - 1] = extension;
return scan_c_stream (infile); scan_c_stream (infile);
} }
/* Return 1 if next input from INFILE is equal to P, -1 if EOF, /* Return 1 if next input from INFILE is equal to P, -1 if EOF,
@ -810,7 +831,7 @@ stream_match (FILE *infile, const char *p)
return 1; return 1;
} }
static int static void
scan_c_stream (FILE *infile) scan_c_stream (FILE *infile)
{ {
int commas, minargs, maxargs; int commas, minargs, maxargs;
@ -818,10 +839,10 @@ scan_c_stream (FILE *infile)
while (!feof (infile)) while (!feof (infile))
{ {
int doc_keyword = 0; bool doc_keyword = false;
int defunflag = 0; bool defunflag = false;
int defvarperbufferflag = 0; bool defvarperbufferflag = false;
int defvarflag = 0; bool defvarflag = false;
enum global_type type = INVALID; enum global_type type = INVALID;
static char *name; static char *name;
static ptrdiff_t name_size; static ptrdiff_t name_size;
@ -870,7 +891,7 @@ scan_c_stream (FILE *infile)
if (c != '_') if (c != '_')
continue; continue;
defvarflag = 1; defvarflag = true;
c = getc (infile); c = getc (infile);
defvarperbufferflag = (c == 'P'); defvarperbufferflag = (c == 'P');
@ -924,7 +945,7 @@ scan_c_stream (FILE *infile)
c = getc (infile); c = getc (infile);
if (c != '"') if (c != '"')
continue; continue;
c = read_c_string_or_comment (infile, -1, 0, 0); c = read_c_string_or_comment (infile, -1, false, 0);
} }
if (generate_globals) if (generate_globals)
@ -970,7 +991,7 @@ scan_c_stream (FILE *infile)
while (c == ' ' || c == '\t' || c == '\n' || c == '\r'); while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
if (c != '"') if (c != '"')
continue; continue;
c = read_c_string_or_comment (infile, -1, 0, 0); c = read_c_string_or_comment (infile, -1, false, 0);
svalue = input_buffer; svalue = input_buffer;
} }
@ -1102,7 +1123,7 @@ scan_c_stream (FILE *infile)
c = getc (infile); c = getc (infile);
if (c == '"') if (c == '"')
c = read_c_string_or_comment (infile, 0, 0, 0); c = read_c_string_or_comment (infile, 0, false, 0);
while (c != EOF && c != ',' && c != '/') while (c != EOF && c != ',' && c != '/')
c = getc (infile); c = getc (infile);
@ -1115,7 +1136,7 @@ scan_c_stream (FILE *infile)
c = getc (infile); c = getc (infile);
if (c == ':') if (c == ':')
{ {
doc_keyword = 1; doc_keyword = true;
c = getc (infile); c = getc (infile);
while (c == ' ' || c == '\n' || c == '\r' || c == '\t') while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
c = getc (infile); c = getc (infile);
@ -1128,8 +1149,8 @@ scan_c_stream (FILE *infile)
ungetc (c, infile), ungetc (c, infile),
c == '*'))) c == '*')))
{ {
int comment = c != '"'; bool comment = c != '"';
int saw_usage; bool saw_usage;
printf ("\037%c%s\n", defvarflag ? 'V' : 'F', input_buffer); printf ("\037%c%s\n", defvarflag ? 'V' : 'F', input_buffer);
@ -1183,8 +1204,8 @@ scan_c_stream (FILE *infile)
} }
} }
eof: eof:
fclose (infile); if (ferror (infile) || fclose (infile) != 0)
return 0; fatal ("read error");
} }
/* Read a file of Lisp code, compiled or interpreted. /* Read a file of Lisp code, compiled or interpreted.
@ -1260,7 +1281,7 @@ read_lisp_symbol (FILE *infile, char *buffer)
skip_white (infile); skip_white (infile);
} }
static int static bool
search_lisp_doc_at_eol (FILE *infile) search_lisp_doc_at_eol (FILE *infile)
{ {
int c = 0, c1 = 0, c2 = 0; int c = 0, c1 = 0, c2 = 0;
@ -1280,16 +1301,15 @@ search_lisp_doc_at_eol (FILE *infile)
#ifdef DEBUG #ifdef DEBUG
fprintf (stderr, "## non-docstring found\n"); fprintf (stderr, "## non-docstring found\n");
#endif #endif
if (c != EOF) ungetc (c, infile);
ungetc (c, infile); return false;
return 0;
} }
return 1; return true;
} }
#define DEF_ELISP_FILE(fn) { #fn, sizeof(#fn) - 1 } #define DEF_ELISP_FILE(fn) { #fn, sizeof(#fn) - 1 }
static int static void
scan_lisp_file (const char *filename, const char *mode) scan_lisp_file (const char *filename, const char *mode)
{ {
FILE *infile; FILE *infile;
@ -1309,22 +1329,22 @@ scan_lisp_file (const char *filename, const char *mode)
DEF_ELISP_FILE (cp51932.el), DEF_ELISP_FILE (cp51932.el),
DEF_ELISP_FILE (eucjp-ms.el) DEF_ELISP_FILE (eucjp-ms.el)
}; };
int i, match; int i;
int flen = strlen (filename); int flen = strlen (filename);
if (generate_globals) if (generate_globals)
fatal ("scanning lisp file when -g specified", 0); fatal ("scanning lisp file when -g specified");
if (flen > 3 && !strcmp (filename + flen - 3, ".el")) if (flen > 3 && !strcmp (filename + flen - 3, ".el"))
{ {
for (i = 0, match = 0; i < sizeof (uncompiled) / sizeof (uncompiled[0]); bool match = false;
i++) for (i = 0; i < sizeof (uncompiled) / sizeof (uncompiled[0]); i++)
{ {
if (uncompiled[i].fl <= flen if (uncompiled[i].fl <= flen
&& !strcmp (filename + flen - uncompiled[i].fl, uncompiled[i].fn) && !strcmp (filename + flen - uncompiled[i].fl, uncompiled[i].fn)
&& (flen == uncompiled[i].fl && (flen == uncompiled[i].fl
|| IS_SLASH (filename[flen - uncompiled[i].fl - 1]))) || IS_SLASH (filename[flen - uncompiled[i].fl - 1])))
{ {
match = 1; match = true;
break; break;
} }
} }
@ -1336,7 +1356,7 @@ scan_lisp_file (const char *filename, const char *mode)
if (infile == NULL) if (infile == NULL)
{ {
perror (filename); perror (filename);
return 0; /* No error. */ exit (EXIT_FAILURE);
} }
c = '\n'; c = '\n';
@ -1374,10 +1394,10 @@ scan_lisp_file (const char *filename, const char *mode)
} }
if (length <= 1) if (length <= 1)
fatal ("invalid dynamic doc string length", ""); fatal ("invalid dynamic doc string length");
if (c != ' ') if (c != ' ')
fatal ("space not found after dynamic doc string length", ""); fatal ("space not found after dynamic doc string length");
/* The next character is a space that is counted in the length /* The next character is a space that is counted in the length
but not part of the doc string. but not part of the doc string.
@ -1585,7 +1605,7 @@ scan_lisp_file (const char *filename, const char *mode)
buffer, filename); buffer, filename);
continue; continue;
} }
read_c_string_or_comment (infile, 0, 0, 0); read_c_string_or_comment (infile, 0, false, 0);
if (saved_string == 0) if (saved_string == 0)
if (!search_lisp_doc_at_eol (infile)) if (!search_lisp_doc_at_eol (infile))
@ -1621,11 +1641,11 @@ scan_lisp_file (const char *filename, const char *mode)
saved_string = 0; saved_string = 0;
} }
else else
read_c_string_or_comment (infile, 1, 0, 0); read_c_string_or_comment (infile, 1, false, 0);
} }
free (saved_string); free (saved_string);
fclose (infile); if (ferror (infile) || fclose (infile) != 0)
return 0; fatal ("%s: read error", filename);
} }