X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/aa56f3613e788df186bef09e2b5414428140377a..39019e542536660936a5fd1a7369ae54fdc6ddd2:/src/lread.c?ds=sidebyside diff --git a/src/lread.c b/src/lread.c index 855869cd90..a2f78f848a 100644 --- a/src/lread.c +++ b/src/lread.c @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include /* for CHAR_BIT */ #include #include "lisp.h" #include "intervals.h" @@ -61,19 +62,21 @@ along with GNU Emacs. If not, see . */ #endif /* hash table read constants */ -Lisp_Object Qhash_table, Qdata; -Lisp_Object Qtest, Qsize; -Lisp_Object Qweakness; -Lisp_Object Qrehash_size; -Lisp_Object Qrehash_threshold; - -Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list; +static Lisp_Object Qhash_table, Qdata; +static Lisp_Object Qtest, Qsize; +static Lisp_Object Qweakness; +static Lisp_Object Qrehash_size; +static Lisp_Object Qrehash_threshold; + +static Lisp_Object Qread_char, Qget_file_char, Qcurrent_load_list; +Lisp_Object Qstandard_input; Lisp_Object Qvariable_documentation; -Lisp_Object Qascii_character, Qload, Qload_file_name; +static Lisp_Object Qascii_character, Qload, Qload_file_name; Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction; -Lisp_Object Qinhibit_file_name_operation; -Lisp_Object Qeval_buffer_list; -Lisp_Object Qfile_truename, Qdo_after_load_evaluation; /* ACM 2006/5/16 */ +static Lisp_Object Qinhibit_file_name_operation; +static Lisp_Object Qeval_buffer_list; +static Lisp_Object Qlexical_binding; +static Lisp_Object Qfile_truename, Qdo_after_load_evaluation; /* ACM 2006/5/16 */ /* Used instead of Qget_file_char while loading *.elc files compiled by Emacs 21 or older. */ @@ -81,13 +84,15 @@ static Lisp_Object Qget_emacs_mule_file_char; static Lisp_Object Qload_force_doc_strings; +extern Lisp_Object Qinternal_interpreter_environment; + static Lisp_Object Qload_in_progress; /* The association list of objects read with the #n=object form. Each member of the list has the form (n . object), and is used to look up the object for the corresponding #n# construct. It must be set to nil before all top-level calls to read0. */ -Lisp_Object read_objects; +static Lisp_Object read_objects; /* Nonzero means READCHAR should read bytes one by one (not character) when READCHARFUN is Qget_file_char or Qget_emacs_mule_file_char. @@ -115,9 +120,9 @@ static EMACS_INT readchar_count; /* This contains the last string skipped with #@. */ static char *saved_doc_string; /* Length of buffer allocated in saved_doc_string. */ -static int saved_doc_string_size; +static ptrdiff_t saved_doc_string_size; /* Length of actual data in saved_doc_string. */ -static int saved_doc_string_length; +static ptrdiff_t saved_doc_string_length; /* This is the file position that string came from. */ static file_offset saved_doc_string_position; @@ -126,9 +131,9 @@ static file_offset saved_doc_string_position; is put in saved_doc_string. */ static char *prev_saved_doc_string; /* Length of buffer allocated in prev_saved_doc_string. */ -static int prev_saved_doc_string_size; +static ptrdiff_t prev_saved_doc_string_size; /* Length of actual data in prev_saved_doc_string. */ -static int prev_saved_doc_string_length; +static ptrdiff_t prev_saved_doc_string_length; /* This is the file position that string came from. */ static file_offset prev_saved_doc_string_position; @@ -147,14 +152,13 @@ static Lisp_Object Vloads_in_progress; static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), Lisp_Object); -static void readevalloop (Lisp_Object, FILE*, Lisp_Object, - Lisp_Object (*) (Lisp_Object), int, +static void readevalloop (Lisp_Object, FILE*, Lisp_Object, int, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); static Lisp_Object load_unwind (Lisp_Object); static Lisp_Object load_descriptor_unwind (Lisp_Object); -static void invalid_syntax (const char *, int) NO_RETURN; +static void invalid_syntax (const char *) NO_RETURN; static void end_of_file_error (void) NO_RETURN; @@ -368,15 +372,15 @@ unreadchar (Lisp_Object readcharfun, int c) else if (BUFFERP (readcharfun)) { struct buffer *b = XBUFFER (readcharfun); + EMACS_INT charpos = BUF_PT (b); EMACS_INT bytepos = BUF_PT_BYTE (b); - BUF_PT (b)--; if (! NILP (BVAR (b, enable_multibyte_characters))) BUF_DEC_POS (b, bytepos); else bytepos--; - BUF_PT_BYTE (b) = bytepos; + SET_BUF_PT_BOTH (b, charpos - 1, bytepos); } else if (MARKERP (readcharfun)) { @@ -769,6 +773,119 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0, + +/* Return true if the lisp code read using READCHARFUN defines a non-nil + `lexical-binding' file variable. After returning, the stream is + positioned following the first line, if it is a comment, otherwise + nothing is read. */ + +static int +lisp_file_lexically_bound_p (Lisp_Object readcharfun) +{ + int ch = READCHAR; + if (ch != ';') + /* The first line isn't a comment, just give up. */ + { + UNREAD (ch); + return 0; + } + else + /* Look for an appropriate file-variable in the first line. */ + { + int rv = 0; + enum { + NOMINAL, AFTER_FIRST_DASH, AFTER_ASTERIX, + } beg_end_state = NOMINAL; + int in_file_vars = 0; + +#define UPDATE_BEG_END_STATE(ch) \ + if (beg_end_state == NOMINAL) \ + beg_end_state = (ch == '-' ? AFTER_FIRST_DASH : NOMINAL); \ + else if (beg_end_state == AFTER_FIRST_DASH) \ + beg_end_state = (ch == '*' ? AFTER_ASTERIX : NOMINAL); \ + else if (beg_end_state == AFTER_ASTERIX) \ + { \ + if (ch == '-') \ + in_file_vars = !in_file_vars; \ + beg_end_state = NOMINAL; \ + } + + /* Skip until we get to the file vars, if any. */ + do + { + ch = READCHAR; + UPDATE_BEG_END_STATE (ch); + } + while (!in_file_vars && ch != '\n' && ch != EOF); + + while (in_file_vars) + { + char var[100], val[100]; + unsigned i; + + ch = READCHAR; + + /* Read a variable name. */ + while (ch == ' ' || ch == '\t') + ch = READCHAR; + + i = 0; + while (ch != ':' && ch != '\n' && ch != EOF && in_file_vars) + { + if (i < sizeof var - 1) + var[i++] = ch; + UPDATE_BEG_END_STATE (ch); + ch = READCHAR; + } + + /* Stop scanning if no colon was found before end marker. */ + if (!in_file_vars) + break; + + while (i > 0 && (var[i - 1] == ' ' || var[i - 1] == '\t')) + i--; + var[i] = '\0'; + + if (ch == ':') + { + /* Read a variable value. */ + ch = READCHAR; + + while (ch == ' ' || ch == '\t') + ch = READCHAR; + + i = 0; + while (ch != ';' && ch != '\n' && ch != EOF && in_file_vars) + { + if (i < sizeof val - 1) + val[i++] = ch; + UPDATE_BEG_END_STATE (ch); + ch = READCHAR; + } + if (! in_file_vars) + /* The value was terminated by an end-marker, which + remove. */ + i -= 3; + while (i > 0 && (val[i - 1] == ' ' || val[i - 1] == '\t')) + i--; + val[i] = '\0'; + + if (strcmp (var, "lexical-binding") == 0) + /* This is it... */ + { + rv = (strcmp (val, "nil") != 0); + break; + } + } + } + + while (ch != '\n' && ch != EOF) + ch = READCHAR; + + return rv; + } +} + /* Value is a version number of byte compiled code if the file associated with file descriptor FD is a compiled Lisp file that's safe to load. Only files compiled with Emacs are safe to load. @@ -796,7 +913,7 @@ safe_to_load_p (int fd) if (i == 4) version = buf[i]; - if (i == nbytes + if (i >= nbytes || fast_c_string_match_ignore_case (Vbytecomp_version_regexp, buf + i) < 0) safe_p = 0; @@ -1020,10 +1137,10 @@ Return t if the file exists and loads successfully. */) Also, just loading a file recursively is not always an error in the general case; the second load may do something different. */ { - int count = 0; + int load_count = 0; Lisp_Object tem; for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem)) - if (!NILP (Fequal (found, XCAR (tem))) && (++count > 3)) + if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3)) { if (fd >= 0) emacs_close (fd); @@ -1033,6 +1150,12 @@ Return t if the file exists and loads successfully. */) Vloads_in_progress = Fcons (found, Vloads_in_progress); } + /* All loads are by default dynamic, unless the file itself specifies + otherwise using a file-variable in the first line. This is bound here + so that it takes effect whether or not we use + Vload_source_file_function. */ + specbind (Qlexical_binding, Qnil); + /* Get the name for load-history. */ hist_file_name = (! NILP (Vpurify_flag) ? Fconcat (2, (tmp[0] = Ffile_name_directory (file), @@ -1080,12 +1203,15 @@ Return t if the file exists and loads successfully. */) #ifdef DOS_NT fmode = "rb"; #endif /* DOS_NT */ - stat (SSDATA (efound), &s1); - SSET (efound, SBYTES (efound) - 1, 0); - result = stat (SSDATA (efound), &s2); - SSET (efound, SBYTES (efound) - 1, 'c'); + result = stat (SSDATA (efound), &s1); + if (result == 0) + { + SSET (efound, SBYTES (efound) - 1, 0); + result = stat (SSDATA (efound), &s2); + SSET (efound, SBYTES (efound) - 1, 'c'); + } - if (result >= 0 && (unsigned) s1.st_mtime < (unsigned) s2.st_mtime) + if (result == 0 && s1.st_mtime < s2.st_mtime) { /* Make the progress messages mention that source is newer. */ newer = 1; @@ -1157,15 +1283,20 @@ Return t if the file exists and loads successfully. */) load_descriptor_list = Fcons (make_number (fileno (stream)), load_descriptor_list); specbind (Qload_in_progress, Qt); + + instream = stream; + if (lisp_file_lexically_bound_p (Qget_file_char)) + Fset (Qlexical_binding, Qt); + if (! version || version >= 22) readevalloop (Qget_file_char, stream, hist_file_name, - Feval, 0, Qnil, Qnil, Qnil, Qnil); + 0, Qnil, Qnil, Qnil, Qnil); else { /* We can't handle a file which was compiled with byte-compile-dynamic by older version of Emacs. */ specbind (Qload_force_doc_strings, Qt); - readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, Feval, + readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, 0, Qnil, Qnil, Qnil, Qnil); } unbind_to (count, Qnil); @@ -1288,16 +1419,16 @@ int openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *storeptr, Lisp_Object predicate) { register int fd; - int fn_size = 100; + EMACS_INT fn_size = 100; char buf[100]; register char *fn = buf; int absolute = 0; - int want_size; + EMACS_INT want_length; Lisp_Object filename; struct stat st; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; Lisp_Object string, tail, encoded_fn; - int max_suffix_len = 0; + EMACS_INT max_suffix_len = 0; CHECK_STRING (str); @@ -1331,11 +1462,11 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto continue; } - /* Calculate maximum size of any filename made from + /* Calculate maximum length of any filename made from this path element/specified file name and any possible suffix. */ - want_size = max_suffix_len + SBYTES (filename) + 1; - if (fn_size < want_size) - fn = (char *) alloca (fn_size = 100 + want_size); + want_length = max_suffix_len + SBYTES (filename); + if (fn_size <= want_length) + fn = (char *) alloca (fn_size = 100 + want_length); /* Loop over suffixes. */ for (tail = NILP (suffixes) ? Fcons (empty_unibyte_string, Qnil) : suffixes; @@ -1384,7 +1515,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto Lisp_Object tmp = call1 (predicate, string); exists = !NILP (tmp) && (EQ (tmp, Qdir_ok) - || !NILP (Ffile_directory_p (string))); + || NILP (Ffile_directory_p (string))); } if (exists) @@ -1402,8 +1533,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, Lisp_Object *sto encoded_fn = ENCODE_FILE (string); pfn = SSDATA (encoded_fn); - exists = (stat (pfn, &st) >= 0 - && (st.st_mode & S_IFMT) != S_IFDIR); + exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode)); if (exists) { /* Check that we can access or open it. */ @@ -1536,7 +1666,6 @@ static void readevalloop (Lisp_Object readcharfun, FILE *stream, Lisp_Object sourcename, - Lisp_Object (*evalfun) (Lisp_Object), int printflag, Lisp_Object unibyte, Lisp_Object readfun, Lisp_Object start, Lisp_Object end) @@ -1547,6 +1676,7 @@ readevalloop (Lisp_Object readcharfun, struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; struct buffer *b = 0; int continue_reading_p; + Lisp_Object lex_bound; /* Nonzero if reading an entire buffer. */ int whole_buffer = 0; /* 1 on the first time around. */ @@ -1572,6 +1702,14 @@ readevalloop (Lisp_Object readcharfun, record_unwind_protect (readevalloop_1, load_convert_to_unibyte ? Qt : Qnil); load_convert_to_unibyte = !NILP (unibyte); + /* If lexical binding is active (either because it was specified in + the file's header, or via a buffer-local variable), create an empty + lexical environment, otherwise, turn off lexical binding. */ + lex_bound = find_symbol_value (Qlexical_binding); + specbind (Qinternal_interpreter_environment, + NILP (lex_bound) || EQ (lex_bound, Qunbound) + ? Qnil : Fcons (Qt, Qnil)); + GCPRO4 (sourcename, readfun, start, end); /* Try to ensure sourcename is a truename, except whilst preloading. */ @@ -1655,8 +1793,8 @@ readevalloop (Lisp_Object readcharfun, to a different value when evaluated. */ if (BUFFERP (readcharfun)) { - struct buffer *b = XBUFFER (readcharfun); - if (BUF_PT (b) == BUF_ZV (b)) + struct buffer *buf = XBUFFER (readcharfun); + if (BUF_PT (buf) == BUF_ZV (buf)) continue_reading_p = 0; } } @@ -1673,7 +1811,7 @@ readevalloop (Lisp_Object readcharfun, unbind_to (count1, Qnil); /* Now eval what we just read. */ - val = (*evalfun) (val); + val = eval_sub (val); if (printflag) { @@ -1733,7 +1871,8 @@ This function preserves the position of point. */) specbind (Qstandard_output, tem); record_unwind_protect (save_excursion_restore, save_excursion_save ()); BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf))); - readevalloop (buf, 0, filename, Feval, + specbind (Qlexical_binding, lisp_file_lexically_bound_p (buf) ? Qt : Qnil); + readevalloop (buf, 0, filename, !NILP (printflag), unibyte, Qnil, Qnil, Qnil); unbind_to (count, Qnil); @@ -1754,6 +1893,7 @@ which is the input stream for reading characters. This function does not move point. */) (Lisp_Object start, Lisp_Object end, Lisp_Object printflag, Lisp_Object read_function) { + /* FIXME: Do the eval-sexp-add-defvars danse! */ int count = SPECPDL_INDEX (); Lisp_Object tem, cbuf; @@ -1767,7 +1907,7 @@ This function does not move point. */) specbind (Qeval_buffer_list, Fcons (cbuf, Veval_buffer_list)); /* readevalloop calls functions which check the type of start and end. */ - readevalloop (cbuf, 0, BVAR (XBUFFER (cbuf), filename), Feval, + readevalloop (cbuf, 0, BVAR (XBUFFER (cbuf), filename), !NILP (printflag), Qnil, read_function, start, end); @@ -1874,11 +2014,9 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end) S is error string of length N (if > 0) */ static void -invalid_syntax (const char *s, int n) +invalid_syntax (const char *s) { - if (!n) - n = strlen (s); - xsignal1 (Qinvalid_read_syntax, make_string (s, n)); + xsignal1 (Qinvalid_read_syntax, build_string (s)); } @@ -2070,6 +2208,8 @@ read_escape (Lisp_Object readcharfun, int stringp) UNREAD (c); break; } + if (MAX_CHAR < i) + error ("Hex character out of range: \\x%x...", i); count++; } @@ -2098,10 +2238,7 @@ read_escape (Lisp_Object readcharfun, int stringp) else if (c >= 'a' && c <= 'f') i = (i << 4) + (c - 'a') + 10; else if (c >= 'A' && c <= 'F') i = (i << 4) + (c - 'A') + 10; else - { - error ("Non-hex digit used for Unicode escape"); - break; - } + error ("Non-hex digit used for Unicode escape"); } if (i > 0x10FFFF) error ("Non-Unicode character: 0x%x", i); @@ -2113,6 +2250,26 @@ read_escape (Lisp_Object readcharfun, int stringp) } } +/* Return the digit that CHARACTER stands for in the given BASE. + Return -1 if CHARACTER is out of range for BASE, + and -2 if CHARACTER is not valid for any supported BASE. */ +static inline int +digit_to_number (int character, int base) +{ + int digit; + + if ('0' <= character && character <= '9') + digit = character - '0'; + else if ('a' <= character && character <= 'z') + digit = character - 'a' + 10; + else if ('A' <= character && character <= 'Z') + digit = character - 'A' + 10; + else + return -2; + + return digit < base ? digit : -1; +} + /* Read an integer in radix RADIX using READCHARFUN to read characters. RADIX must be in the interval [2..36]; if it isn't, a read error is signaled . Value is the integer read. Signals an @@ -2122,59 +2279,64 @@ read_escape (Lisp_Object readcharfun, int stringp) static Lisp_Object read_integer (Lisp_Object readcharfun, int radix) { - int ndigits = 0, invalid_p, c, sign = 0; - /* We use a floating point number because */ - double number = 0; + /* Room for sign, leading 0, other digits, trailing null byte. */ + char buf[1 + 1 + sizeof (uintmax_t) * CHAR_BIT + 1]; + + int valid = -1; /* 1 if valid, 0 if not, -1 if incomplete. */ if (radix < 2 || radix > 36) - invalid_p = 1; + valid = 0; else { - number = ndigits = invalid_p = 0; - sign = 1; + char *p = buf; + int c, digit; c = READCHAR; - if (c == '-') + if (c == '-' || c == '+') { + *p++ = c; c = READCHAR; - sign = -1; } - else if (c == '+') - c = READCHAR; - while (c >= 0) + if (c == '0') { - int digit; - - if (c >= '0' && c <= '9') - digit = c - '0'; - else if (c >= 'a' && c <= 'z') - digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'Z') - digit = c - 'A' + 10; - else - { - UNREAD (c); - break; - } + *p++ = c; + valid = 1; + + /* Ignore redundant leading zeros, so the buffer doesn't + fill up with them. */ + do + c = READCHAR; + while (c == '0'); + } - if (digit < 0 || digit >= radix) - invalid_p = 1; + while (-1 <= (digit = digit_to_number (c, radix))) + { + if (digit == -1) + valid = 0; + if (valid < 0) + valid = 1; + + if (p < buf + sizeof buf - 1) + *p++ = c; + else + valid = 0; - number = radix * number + digit; - ++ndigits; c = READCHAR; } + + if (c >= 0) + UNREAD (c); + *p = '\0'; } - if (ndigits == 0 || invalid_p) + if (! valid) { - char buf[50]; sprintf (buf, "integer, radix %d", radix); - invalid_syntax (buf, 0); + invalid_syntax (buf); } - return make_fixnum_or_float (sign * number); + return string_to_number (buf, radix, 0); } @@ -2188,7 +2350,7 @@ static Lisp_Object read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) { register int c; - int uninterned_symbol = 0; + unsigned uninterned_symbol = 0; int multibyte; *pch = 0; @@ -2288,7 +2450,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) return ht; } UNREAD (c); - invalid_syntax ("#", 1); + invalid_syntax ("#"); } if (c == '^') { @@ -2297,7 +2459,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) { Lisp_Object tmp; tmp = read_vector (readcharfun, 0); - if (XVECTOR (tmp)->size < CHAR_TABLE_STANDARD_SLOTS) + if (ASIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS) error ("Invalid size char-table"); XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE); return tmp; @@ -2316,15 +2478,15 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) depth = XINT (AREF (tmp, 0)); if (depth < 1 || depth > 3) error ("Invalid depth in char-table"); - size = XVECTOR (tmp)->size - 2; + size = ASIZE (tmp) - 2; if (chartab_size [depth] != size) error ("Invalid size char-table"); XSETPVECTYPE (XVECTOR (tmp), PVEC_SUB_CHAR_TABLE); return tmp; } - invalid_syntax ("#^^", 3); + invalid_syntax ("#^^"); } - invalid_syntax ("#^", 2); + invalid_syntax ("#^"); } if (c == '&') { @@ -2348,7 +2510,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) version. */ && ! (XFASTINT (length) == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) - invalid_syntax ("#&...", 5); + invalid_syntax ("#&..."); val = Fmake_bool_vector (length, Qnil); memcpy (XBOOL_VECTOR (val)->data, SDATA (tmp), size_in_chars); @@ -2358,7 +2520,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) &= (1 << (XINT (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1; return val; } - invalid_syntax ("#&...", 5); + invalid_syntax ("#&..."); } if (c == '[') { @@ -2366,7 +2528,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) build them using function calls. */ Lisp_Object tmp; tmp = read_vector (readcharfun, 1); - return Fmake_byte_code (XVECTOR (tmp)->size, + return Fmake_byte_code (ASIZE (tmp), XVECTOR (tmp)->contents); } if (c == '(') @@ -2378,7 +2540,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) /* Read the string itself. */ tmp = read1 (readcharfun, &ch, 0); if (ch != 0 || !STRINGP (tmp)) - invalid_syntax ("#", 1); + invalid_syntax ("#"); GCPRO1 (tmp); /* Read the intervals and their properties. */ while (1) @@ -2394,7 +2556,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (ch == 0) plist = read1 (readcharfun, &ch, 0); if (ch) - invalid_syntax ("Invalid string property list", 0); + invalid_syntax ("Invalid string property list"); Fset_text_properties (beg, end, plist, tmp); } UNGCPRO; @@ -2406,13 +2568,16 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) and function definitions. */ if (c == '@') { - int i, nskip = 0; + enum { extra = 100 }; + ptrdiff_t i, nskip = 0; load_each_byte = 1; /* Read a decimal integer. */ while ((c = READCHAR) >= 0 && c >= '0' && c <= '9') { + if ((STRING_BYTES_BOUND - extra) / 10 <= nskip) + string_overflow (); nskip *= 10; nskip += c - '0'; } @@ -2431,9 +2596,9 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) with prev_saved_doc_string, so we save two strings. */ { char *temp = saved_doc_string; - int temp_size = saved_doc_string_size; + ptrdiff_t temp_size = saved_doc_string_size; file_offset temp_pos = saved_doc_string_position; - int temp_len = saved_doc_string_length; + ptrdiff_t temp_len = saved_doc_string_length; saved_doc_string = prev_saved_doc_string; saved_doc_string_size = prev_saved_doc_string_size; @@ -2448,12 +2613,12 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (saved_doc_string_size == 0) { - saved_doc_string_size = nskip + 100; + saved_doc_string_size = nskip + extra; saved_doc_string = (char *) xmalloc (saved_doc_string_size); } if (nskip > saved_doc_string_size) { - saved_doc_string_size = nskip + 100; + saved_doc_string_size = nskip + extra; saved_doc_string = (char *) xrealloc (saved_doc_string, saved_doc_string_size); } @@ -2551,7 +2716,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) return read_integer (readcharfun, 2); UNREAD (c); - invalid_syntax ("#", 1); + invalid_syntax ("#"); case ';': while ((c = READCHAR) >= 0 && c != '\n'); @@ -2668,14 +2833,14 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (ok) return make_number (c); - invalid_syntax ("?", 1); + invalid_syntax ("?"); } case '"': { char *p = read_buffer; char *end = read_buffer + read_buffer_size; - register int c; + register int ch; /* Nonzero if we saw an escape sequence specifying a multibyte character. */ int force_multibyte = 0; @@ -2685,8 +2850,8 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) int cancel = 0; int nchars = 0; - while ((c = READCHAR) >= 0 - && c != '\"') + while ((ch = READCHAR) >= 0 + && ch != '\"') { if (end - p < MAX_MULTIBYTE_LENGTH) { @@ -2697,44 +2862,44 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) end = read_buffer + read_buffer_size; } - if (c == '\\') + if (ch == '\\') { int modifiers; - c = read_escape (readcharfun, 1); + ch = read_escape (readcharfun, 1); - /* C is -1 if \ newline has just been seen */ - if (c == -1) + /* CH is -1 if \ newline has just been seen */ + if (ch == -1) { if (p == read_buffer) cancel = 1; continue; } - modifiers = c & CHAR_MODIFIER_MASK; - c = c & ~CHAR_MODIFIER_MASK; + modifiers = ch & CHAR_MODIFIER_MASK; + ch = ch & ~CHAR_MODIFIER_MASK; - if (CHAR_BYTE8_P (c)) + if (CHAR_BYTE8_P (ch)) force_singlebyte = 1; - else if (! ASCII_CHAR_P (c)) + else if (! ASCII_CHAR_P (ch)) force_multibyte = 1; - else /* i.e. ASCII_CHAR_P (c) */ + else /* i.e. ASCII_CHAR_P (ch) */ { /* Allow `\C- ' and `\C-?'. */ if (modifiers == CHAR_CTL) { - if (c == ' ') - c = 0, modifiers = 0; - else if (c == '?') - c = 127, modifiers = 0; + if (ch == ' ') + ch = 0, modifiers = 0; + else if (ch == '?') + ch = 127, modifiers = 0; } if (modifiers & CHAR_SHIFT) { /* Shift modifier is valid only with [A-Za-z]. */ - if (c >= 'A' && c <= 'Z') + if (ch >= 'A' && ch <= 'Z') modifiers &= ~CHAR_SHIFT; - else if (c >= 'a' && c <= 'z') - c -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT; + else if (ch >= 'a' && ch <= 'z') + ch -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT; } if (modifiers & CHAR_META) @@ -2742,7 +2907,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) /* Move the meta bit to the right place for a string. */ modifiers &= ~CHAR_META; - c = BYTE8_TO_CHAR (c | 0x80); + ch = BYTE8_TO_CHAR (ch | 0x80); force_singlebyte = 1; } } @@ -2750,20 +2915,20 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) /* Any modifiers remaining are invalid. */ if (modifiers) error ("Invalid modifier in string"); - p += CHAR_STRING (c, (unsigned char *) p); + p += CHAR_STRING (ch, (unsigned char *) p); } else { - p += CHAR_STRING (c, (unsigned char *) p); - if (CHAR_BYTE8_P (c)) + p += CHAR_STRING (ch, (unsigned char *) p); + if (CHAR_BYTE8_P (ch)) force_singlebyte = 1; - else if (! ASCII_CHAR_P (c)) + else if (! ASCII_CHAR_P (ch)) force_multibyte = 1; } nchars++; } - if (c < 0) + if (ch < 0) end_of_file_error (); /* If purifying, and string starts with \ newline, @@ -2782,8 +2947,9 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) p = read_buffer + nchars; } else - /* Otherwise, READ_BUFFER contains only ASCII. */ - ; + { + /* Otherwise, READ_BUFFER contains only ASCII. */ + } /* We want readchar_count to be the number of characters, not bytes. Hence we adjust for multibyte characters in the @@ -2872,86 +3038,9 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list) if (!quoted && !uninterned_symbol) { - register char *p1; - p1 = read_buffer; - if (*p1 == '+' || *p1 == '-') p1++; - /* Is it an integer? */ - if (p1 != p) - { - while (p1 != p && (c = *p1) >= '0' && c <= '9') p1++; - /* Integers can have trailing decimal points. */ - if (p1 > read_buffer && p1 < p && *p1 == '.') p1++; - if (p1 == p) - /* It is an integer. */ - { - if (p1[-1] == '.') - p1[-1] = '\0'; - { - /* EMACS_INT n = atol (read_buffer); */ - char *endptr = NULL; - EMACS_INT n = (errno = 0, - strtol (read_buffer, &endptr, 10)); - if (errno == ERANGE && endptr) - { - Lisp_Object args - = Fcons (make_string (read_buffer, - endptr - read_buffer), - Qnil); - xsignal (Qoverflow_error, args); - } - return make_fixnum_or_float (n); - } - } - } - if (isfloat_string (read_buffer, 0)) - { - /* Compute NaN and infinities using 0.0 in a variable, - to cope with compilers that think they are smarter - than we are. */ - double zero = 0.0; - - double value; - - /* Negate the value ourselves. This treats 0, NaNs, - and infinity properly on IEEE floating point hosts, - and works around a common bug where atof ("-0.0") - drops the sign. */ - int negative = read_buffer[0] == '-'; - - /* The only way p[-1] can be 'F' or 'N', after isfloat_string - returns 1, is if the input ends in e+INF or e+NaN. */ - switch (p[-1]) - { - case 'F': - value = 1.0 / zero; - break; - case 'N': - value = zero / zero; - - /* If that made a "negative" NaN, negate it. */ - - { - int i; - union { double d; char c[sizeof (double)]; } u_data, u_minus_zero; - - u_data.d = value; - u_minus_zero.d = - 0.0; - for (i = 0; i < sizeof (double); i++) - if (u_data.c[i] & u_minus_zero.c[i]) - { - value = - value; - break; - } - } - /* Now VALUE is a positive NaN. */ - break; - default: - value = atof (read_buffer + negative); - break; - } - - return make_float (negative ? - value : value); - } + Lisp_Object result = string_to_number (read_buffer, 10, 0); + if (! NILP (result)) + return result; } { Lisp_Object name, result; @@ -3112,71 +3201,159 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg) #define LEAD_INT 1 #define DOT_CHAR 2 #define TRAIL_INT 4 -#define E_CHAR 8 -#define EXP_INT 16 +#define E_EXP 16 -int -isfloat_string (const char *cp, int ignore_trailing) + +/* Convert STRING to a number, assuming base BASE. Return a fixnum if CP has + integer syntax and fits in a fixnum, else return the nearest float if CP has + either floating point or integer syntax and BASE is 10, else return nil. If + IGNORE_TRAILING is nonzero, consider just the longest prefix of CP that has + valid floating point syntax. Signal an overflow if BASE is not 10 and the + number has integer syntax but does not fit. */ + +Lisp_Object +string_to_number (char const *string, int base, int ignore_trailing) { int state; - const char *start = cp; + char const *cp = string; + int leading_digit; + int float_syntax = 0; + double value = 0; + + /* Compute NaN and infinities using a variable, to cope with compilers that + think they are smarter than we are. */ + double zero = 0; + + /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on + IEEE floating point hosts, and works around a formerly-common bug where + atof ("-0.0") drops the sign. */ + int negative = *cp == '-'; + + int signedp = negative || *cp == '+'; + cp += signedp; state = 0; - if (*cp == '+' || *cp == '-') - cp++; - if (*cp >= '0' && *cp <= '9') + leading_digit = digit_to_number (*cp, base); + if (0 <= leading_digit) { state |= LEAD_INT; - while (*cp >= '0' && *cp <= '9') - cp++; + do + ++cp; + while (0 <= digit_to_number (*cp, base)); } if (*cp == '.') { state |= DOT_CHAR; cp++; } - if (*cp >= '0' && *cp <= '9') - { - state |= TRAIL_INT; - while (*cp >= '0' && *cp <= '9') - cp++; - } - if (*cp == 'e' || *cp == 'E') - { - state |= E_CHAR; - cp++; - if (*cp == '+' || *cp == '-') - cp++; - } - if (*cp >= '0' && *cp <= '9') - { - state |= EXP_INT; - while (*cp >= '0' && *cp <= '9') - cp++; - } - else if (cp == start) - ; - else if (cp[-1] == '+' && cp[0] == 'I' && cp[1] == 'N' && cp[2] == 'F') + if (base == 10) { - state |= EXP_INT; - cp += 3; + if ('0' <= *cp && *cp <= '9') + { + state |= TRAIL_INT; + do + cp++; + while ('0' <= *cp && *cp <= '9'); + } + if (*cp == 'e' || *cp == 'E') + { + char const *ecp = cp; + cp++; + if (*cp == '+' || *cp == '-') + cp++; + if ('0' <= *cp && *cp <= '9') + { + state |= E_EXP; + do + cp++; + while ('0' <= *cp && *cp <= '9'); + } + else if (cp[-1] == '+' + && cp[0] == 'I' && cp[1] == 'N' && cp[2] == 'F') + { + state |= E_EXP; + cp += 3; + value = 1.0 / zero; + } + else if (cp[-1] == '+' + && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N') + { + state |= E_EXP; + cp += 3; + value = zero / zero; + + /* If that made a "negative" NaN, negate it. */ + { + int i; + union { double d; char c[sizeof (double)]; } + u_data, u_minus_zero; + u_data.d = value; + u_minus_zero.d = -0.0; + for (i = 0; i < sizeof (double); i++) + if (u_data.c[i] & u_minus_zero.c[i]) + { + value = -value; + break; + } + } + /* Now VALUE is a positive NaN. */ + } + else + cp = ecp; + } + + float_syntax = ((state & (DOT_CHAR|TRAIL_INT)) == (DOT_CHAR|TRAIL_INT) + || state == (LEAD_INT|E_EXP)); } - else if (cp[-1] == '+' && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N') + + /* Return nil if the number uses invalid syntax. If IGNORE_TRAILING, accept + any prefix that matches. Otherwise, the entire string must match. */ + if (! (ignore_trailing + ? ((state & LEAD_INT) != 0 || float_syntax) + : (!*cp && ((state & ~DOT_CHAR) == LEAD_INT || float_syntax)))) + return Qnil; + + /* If the number uses integer and not float syntax, and is in C-language + range, use its value, preferably as a fixnum. */ + if (0 <= leading_digit && ! float_syntax) { - state |= EXP_INT; - cp += 3; + uintmax_t n; + + /* Fast special case for single-digit integers. This also avoids a + glitch when BASE is 16 and IGNORE_TRAILING is nonzero, because in that + case some versions of strtoumax accept numbers like "0x1" that Emacs + does not allow. */ + if (digit_to_number (string[signedp + 1], base) < 0) + return make_number (negative ? -leading_digit : leading_digit); + + errno = 0; + n = strtoumax (string + signedp, NULL, base); + if (errno == ERANGE) + { + /* Unfortunately there's no simple and accurate way to convert + non-base-10 numbers that are out of C-language range. */ + if (base != 10) + xsignal1 (Qoverflow_error, build_string (string)); + } + else if (n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM)) + { + EMACS_INT signed_n = n; + return make_number (negative ? -signed_n : signed_n); + } + else + value = n; } - return ((ignore_trailing - || *cp == 0 || *cp == ' ' || *cp == '\t' || *cp == '\n' - || *cp == '\r' || *cp == '\f') - && (state == (LEAD_INT|DOT_CHAR|TRAIL_INT) - || state == (DOT_CHAR|TRAIL_INT) - || state == (LEAD_INT|E_CHAR|EXP_INT) - || state == (LEAD_INT|DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT) - || state == (DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT))); + /* Either the number uses float syntax, or it does not fit into a fixnum. + Convert it from string to floating point, unless the value is already + known because it is an infinity, a NAN, or its absolute value fits in + uintmax_t. */ + if (! value) + value = atof (string + signedp); + + return make_float (negative ? -value : value); } @@ -3194,7 +3371,7 @@ read_vector (Lisp_Object readcharfun, int bytecodeflag) len = Flength (tem); vector = (read_pure ? make_pure_vector (XINT (len)) : Fmake_vector (len, Qnil)); - size = XVECTOR (vector)->size; + size = ASIZE (vector); ptr = XVECTOR (vector)->contents; for (i = 0; i < size; i++) { @@ -3324,7 +3501,7 @@ read_list (int flag, register Lisp_Object readcharfun) { if (ch == ']') return val; - invalid_syntax (") or . in a vector", 18); + invalid_syntax (") or . in a vector"); } if (ch == ')') return val; @@ -3353,7 +3530,7 @@ read_list (int flag, register Lisp_Object readcharfun) doc string, caller must make it multibyte. */ - int pos = XINT (XCDR (val)); + EMACS_INT pos = XINT (XCDR (val)); /* Position is negative for user variables. */ if (pos < 0) pos = -pos; if (pos >= saved_doc_string_position @@ -3426,9 +3603,9 @@ read_list (int flag, register Lisp_Object readcharfun) return val; } - invalid_syntax (". in wrong context", 18); + invalid_syntax (". in wrong context"); } - invalid_syntax ("] in a list", 11); + invalid_syntax ("] in a list"); } tem = (read_pure && flag <= 0 ? pure_cons (elt, Qnil) @@ -3445,13 +3622,13 @@ read_list (int flag, register Lisp_Object readcharfun) } } -Lisp_Object initial_obarray; +static Lisp_Object initial_obarray; /* oblookup stores the bucket number here, for the sake of Funintern. */ -int oblookup_last_bucket_number; +static size_t oblookup_last_bucket_number; -static int hash_string (const char *ptr, int len); +static size_t hash_string (const char *ptr, size_t len); /* Get an error if OBARRAY is not an obarray. If it is one, return it. */ @@ -3459,7 +3636,7 @@ static int hash_string (const char *ptr, int len); Lisp_Object check_obarray (Lisp_Object obarray) { - if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0) + if (!VECTORP (obarray) || ASIZE (obarray) == 0) { /* If Vobarray is now invalid, force it to be valid. */ if (EQ (Vobarray, obarray)) Vobarray = initial_obarray; @@ -3475,11 +3652,11 @@ Lisp_Object intern (const char *str) { Lisp_Object tem; - int len = strlen (str); + ptrdiff_t len = strlen (str); Lisp_Object obarray; obarray = Vobarray; - if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0) + if (!VECTORP (obarray) || ASIZE (obarray) == 0) obarray = check_obarray (obarray); tem = oblookup (obarray, str, len, len); if (SYMBOLP (tem)) @@ -3491,11 +3668,11 @@ Lisp_Object intern_c_string (const char *str) { Lisp_Object tem; - int len = strlen (str); + ptrdiff_t len = strlen (str); Lisp_Object obarray; obarray = Vobarray; - if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0) + if (!VECTORP (obarray) || ASIZE (obarray) == 0) obarray = check_obarray (obarray); tem = oblookup (obarray, str, len, len); if (SYMBOLP (tem)) @@ -3509,18 +3686,6 @@ intern_c_string (const char *str) return Fintern (make_pure_c_string (str), obarray); } - -/* Create an uninterned symbol with name STR. */ - -Lisp_Object -make_symbol (const char *str) -{ - int len = strlen (str); - - return Fmake_symbol (!NILP (Vpurify_flag) - ? make_pure_string (str, len, len, 0) - : make_string (str, len)); -} DEFUN ("intern", Fintern, Sintern, 1, 2, 0, doc: /* Return the canonical symbol whose name is STRING. @@ -3605,7 +3770,7 @@ OBARRAY defaults to the value of the variable `obarray'. */) (Lisp_Object name, Lisp_Object obarray) { register Lisp_Object string, tem; - int hash; + size_t hash; if (NILP (obarray)) obarray = Vobarray; obarray = check_obarray (obarray); @@ -3674,16 +3839,16 @@ OBARRAY defaults to the value of the variable `obarray'. */) Lisp_Object oblookup (Lisp_Object obarray, register const char *ptr, EMACS_INT size, EMACS_INT size_byte) { - int hash; - int obsize; + size_t hash; + size_t obsize; register Lisp_Object tail; Lisp_Object bucket, tem; if (!VECTORP (obarray) - || (obsize = XVECTOR (obarray)->size) == 0) + || (obsize = ASIZE (obarray)) == 0) { obarray = check_obarray (obarray); - obsize = XVECTOR (obarray)->size; + obsize = ASIZE (obarray); } /* This is sometimes needed in the middle of GC. */ obsize &= ~ARRAY_MARK_FLAG; @@ -3708,21 +3873,21 @@ oblookup (Lisp_Object obarray, register const char *ptr, EMACS_INT size, EMACS_I return tem; } -static int -hash_string (const char *ptr, int len) +static size_t +hash_string (const char *ptr, size_t len) { register const char *p = ptr; register const char *end = p + len; register unsigned char c; - register int hash = 0; + register size_t hash = 0; while (p != end) { c = *p++; if (c >= 0140) c -= 40; - hash = ((hash<<3) + (hash>>28) + c); + hash = (hash << 3) + (hash >> (CHAR_BIT * sizeof hash - 4)) + c; } - return hash & 07777777777; + return hash; } void @@ -3731,7 +3896,7 @@ map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Ob register int i; register Lisp_Object tail; CHECK_VECTOR (obarray); - for (i = XVECTOR (obarray)->size - 1; i >= 0; i--) + for (i = ASIZE (obarray) - 1; i >= 0; i--) { tail = XVECTOR (obarray)->contents[i]; if (SYMBOLP (tail)) @@ -3811,7 +3976,7 @@ defsubr (struct Lisp_Subr *sname) { Lisp_Object sym; sym = intern_c_string (sname->symbol_name); - XSETPVECTYPE (sname, PVEC_SUBR); + XSETTYPED_PVECTYPE (sname, size, PVEC_SUBR); XSETSUBR (XSYMBOL (sym)->function, sname); } @@ -3838,6 +4003,7 @@ defvar_int (struct Lisp_Intfwd *i_fwd, sym = intern_c_string (namestring); i_fwd->type = Lisp_Fwd_Int; i_fwd->intvar = address; + XSYMBOL (sym)->declared_special = 1; XSYMBOL (sym)->redirect = SYMBOL_FORWARDED; SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)i_fwd); } @@ -3852,6 +4018,7 @@ defvar_bool (struct Lisp_Boolfwd *b_fwd, sym = intern_c_string (namestring); b_fwd->type = Lisp_Fwd_Bool; b_fwd->boolvar = address; + XSYMBOL (sym)->declared_special = 1; XSYMBOL (sym)->redirect = SYMBOL_FORWARDED; SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)b_fwd); Vbyte_boolean_vars = Fcons (sym, Vbyte_boolean_vars); @@ -3870,6 +4037,7 @@ defvar_lisp_nopro (struct Lisp_Objfwd *o_fwd, sym = intern_c_string (namestring); o_fwd->type = Lisp_Fwd_Obj; o_fwd->objvar = address; + XSYMBOL (sym)->declared_special = 1; XSYMBOL (sym)->redirect = SYMBOL_FORWARDED; SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)o_fwd); } @@ -3893,6 +4061,7 @@ defvar_kboard (struct Lisp_Kboard_Objfwd *ko_fwd, sym = intern_c_string (namestring); ko_fwd->type = Lisp_Fwd_Kboard_Obj; ko_fwd->offset = offset; + XSYMBOL (sym)->declared_special = 1; XSYMBOL (sym)->redirect = SYMBOL_FORWARDED; SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)ko_fwd); } @@ -4320,6 +4489,15 @@ to load. See also `load-dangerous-libraries'. */); Vbytecomp_version_regexp = make_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)"); + Qlexical_binding = intern ("lexical-binding"); + staticpro (&Qlexical_binding); + DEFVAR_LISP ("lexical-binding", Vlexical_binding, + doc: /* If non-nil, use lexical binding when evaluating code. +This only applies to code evaluated by `eval-buffer' and `eval-region'. +This variable is automatically set from the file variables of an interpreted + Lisp file read using `load'. */); + Fmake_variable_buffer_local (Qlexical_binding); + DEFVAR_LISP ("eval-buffer-list", Veval_buffer_list, doc: /* List of buffers being read from by calls to `eval-buffer' and `eval-region'. */); Veval_buffer_list = Qnil; @@ -4385,7 +4563,7 @@ to load. See also `load-dangerous-libraries'. */); Qdir_ok = intern_c_string ("dir-ok"); staticpro (&Qdir_ok); - + Qdo_after_load_evaluation = intern_c_string ("do-after-load-evaluation"); staticpro (&Qdo_after_load_evaluation) ;