static void * check_nonnull (void *p) { if (! p) memory_exhausted (errno); return p; }
static struct global * add_global (enum global_type type, char const *name, int value, char const *svalue) { /* Ignore the one non-symbol that can occur. */ if (strcmp (name, "...")) { if (num_globals == num_globals_allocated) { ptrdiff_t num_globals_max = (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *globals); if (num_globals_allocated == num_globals_max) memory_exhausted (); if (num_globals_allocated < num_globals_max / 2) num_globals_allocated = 2 * num_globals_allocated + 1; else num_globals_allocated = num_globals_max; globals = xrealloc (globals, num_globals_allocated * sizeof *globals); } ++num_globals; ptrdiff_t namesize = strlen (name) + 1; char *buf = xmalloc (namesize + (svalue ? strlen (svalue) + 1 : 0)); globals[num_globals - 1].type = type; globals[num_globals - 1].name = strcpy (buf, name); if (svalue) globals[num_globals - 1].v.svalue = strcpy (buf + namesize, svalue); else globals[num_globals - 1].v.value = value; globals[num_globals - 1].flags = 0; return globals + num_globals - 1; } return NULL; }
static void * xrealloc (void *arg, ptrdiff_t size) { void *result = realloc (arg, size); if (result == NULL) memory_exhausted (); return result; }
static void * xmalloc (ptrdiff_t size) { void *result = malloc (size); if (result == NULL) memory_exhausted (); return result; }
void * checked_grow_alloc (void *ptr, size_t *size) { size_t max = -1; if (*size == max) memory_exhausted (0); *size = *size < max / 2 ? 2 * *size : max; return checked_realloc (ptr, *size); }
static void scan_lisp_file (const char *filename, const char *mode) { FILE *infile; 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; int 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; int flen = strlen (filename); if (generate_globals) fatal ("scanning lisp file when -g specified"); if (flen > 3 && !strcmp (filename + flen - 3, ".el")) { bool match = false; for (i = 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 = true; break; } } if (!match) fatal ("uncompiled lisp file %s is not supported", filename); } infile = fopen (filename, mode); if (infile == NULL) { perror (filename); exit (EXIT_FAILURE); } c = '\n'; while (!feof (infile)) { char buffer[BUFSIZ]; char type; /* If not at end of line, skip till we get to one. */ if (c != '\n' && c != '\r') { c = getc (infile); continue; } /* 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 == '@') { ptrdiff_t length = 0; ptrdiff_t i; /* Read the length. */ while ((c = getc (infile), c >= '0' && c <= '9')) { if (INT_MULTIPLY_WRAPV (length, 10, &length) || INT_ADD_WRAPV (length, c - '0', &length) || SIZE_MAX < length) memory_exhausted (); } 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. */ length--; /* Read in the contents. */ free (saved_string); saved_string = xmalloc (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") || ! strcmp (buffer, "defsubst")) { type = 'F'; read_lisp_symbol (infile, buffer); /* Skip the arguments: either "nil" or a list in parens. */ c = getc (infile); if (c == 'n') /* nil */ { if ((c = getc (infile)) != 'i' || (c = getc (infile)) != 'l') { fprintf (stderr, "## unparsable arglist in %s (%s)\n", buffer, filename); continue; } } else if (c != '(') { fprintf (stderr, "## unparsable arglist in %s (%s)\n", buffer, filename); continue; } else while (c != ')') c = getc (infile); 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' && c != '\r')) { #ifdef DEBUG fprintf (stderr, "## non-docstring in %s (%s)\n", buffer, filename); #endif continue; } } /* defcustom can only occur in uncompiled Lisp files. */ else if (! strcmp (buffer, "defvar") || ! strcmp (buffer, "defconst") || ! strcmp (buffer, "defcustom")) { type = 'V'; read_lisp_symbol (infile, buffer); if (saved_string == 0) if (!search_lisp_doc_at_eol (infile)) continue; } else if (! strcmp (buffer, "custom-declare-variable") || ! strcmp (buffer, "defvaralias") ) { type = 'V'; c = getc (infile); if (c == '\'') read_lisp_symbol (infile, buffer); else { 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 (saved_string == 0) if (!search_lisp_doc_at_eol (infile)) continue; } else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias")) { type = 'F'; c = getc (infile); if (c == '\'') read_lisp_symbol (infile, buffer); else { if (c != '(') { fprintf (stderr, "## unparsable name in fset in %s\n", filename); continue; } read_lisp_symbol (infile, buffer); if (strcmp (buffer, "quote")) { fprintf (stderr, "## unparsable name in fset in %s\n", filename); continue; } read_lisp_symbol (infile, buffer); c = getc (infile); if (c != ')') { fprintf (stderr, "## unparsable quoted name in fset in %s\n", filename); continue; } } if (saved_string == 0) if (!search_lisp_doc_at_eol (infile)) continue; } else if (! strcmp (buffer, "autoload")) { type = 'F'; c = getc (infile); if (c == '\'') read_lisp_symbol (infile, buffer); else { if (c != '(') { fprintf (stderr, "## unparsable name in autoload in %s\n", filename); continue; } read_lisp_symbol (infile, buffer); if (strcmp (buffer, "quote")) { fprintf (stderr, "## unparsable name in autoload in %s\n", filename); continue; } read_lisp_symbol (infile, buffer); c = getc (infile); if (c != ')') { fprintf (stderr, "## unparsable quoted name in autoload in %s\n", filename); continue; } } skip_white (infile); if ((c = getc (infile)) != '\"') { fprintf (stderr, "## autoload of %s unparsable (%s)\n", buffer, filename); continue; } read_c_string_or_comment (infile, 0, false, 0); if (saved_string == 0) if (!search_lisp_doc_at_eol (infile)) continue; } #ifdef DEBUG else if (! strcmp (buffer, "if") || ! strcmp (buffer, "byte-code")) continue; #endif else { #ifdef DEBUG fprintf (stderr, "## unrecognized top-level form, %s (%s)\n", buffer, filename); #endif continue; } /* 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. */ printf ("\037%c%s\n", type, buffer); if (saved_string) { fputs (saved_string, stdout); /* Don't use one dynamic doc string twice. */ free (saved_string); saved_string = 0; } else read_c_string_or_comment (infile, 1, false, 0); } free (saved_string); if (ferror (infile) || fclose (infile) != 0) fatal ("%s: read error", filename); }