X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/ca23cc8840efb1354ebe16c6bb99bf1f8880e9b6..eab3844f965646b62e242aa622754b86d1fd3444:/src/lread.c diff --git a/src/lread.c b/src/lread.c index 8777bc3454..2ce2a4398a 100644 --- a/src/lread.c +++ b/src/lread.c @@ -19,6 +19,7 @@ along with GNU Emacs. If not, see . */ #include +#include #include #include #include @@ -61,20 +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 Qlexical_binding; -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. */ @@ -90,7 +92,7 @@ static Lisp_Object Qload_in_progress; 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. @@ -1410,16 +1412,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); @@ -1453,11 +1455,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; @@ -2428,7 +2430,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 (XVECTOR_SIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS) error ("Invalid size char-table"); XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE); return tmp; @@ -2447,7 +2449,7 @@ 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 = XVECTOR_SIZE (tmp) - 2; if (chartab_size [depth] != size) error ("Invalid size char-table"); XSETPVECTYPE (XVECTOR (tmp), PVEC_SUB_CHAR_TABLE); @@ -2497,7 +2499,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 (XVECTOR_SIZE (tmp), XVECTOR (tmp)->contents); } if (c == '(') @@ -3004,86 +3006,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; @@ -3241,74 +3166,179 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg) } +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 -1; + + return digit < base ? digit : -1; +} + #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') + if (base == 10) { - 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') - { - 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) + xsignal (Qoverflow_error, list1 (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); } @@ -3326,7 +3356,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 = XVECTOR_SIZE (vector); ptr = XVECTOR (vector)->contents; for (i = 0; i < size; i++) { @@ -3577,11 +3607,11 @@ 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 int oblookup_last_bucket_number; static int hash_string (const char *ptr, int len); @@ -3591,7 +3621,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) || XVECTOR_SIZE (obarray) == 0) { /* If Vobarray is now invalid, force it to be valid. */ if (EQ (Vobarray, obarray)) Vobarray = initial_obarray; @@ -3611,7 +3641,7 @@ intern (const char *str) Lisp_Object obarray; obarray = Vobarray; - if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0) + if (!VECTORP (obarray) || XVECTOR_SIZE (obarray) == 0) obarray = check_obarray (obarray); tem = oblookup (obarray, str, len, len); if (SYMBOLP (tem)) @@ -3627,7 +3657,7 @@ intern_c_string (const char *str) Lisp_Object obarray; obarray = Vobarray; - if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0) + if (!VECTORP (obarray) || XVECTOR_SIZE (obarray) == 0) obarray = check_obarray (obarray); tem = oblookup (obarray, str, len, len); if (SYMBOLP (tem)) @@ -3641,18 +3671,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. @@ -3812,10 +3830,10 @@ oblookup (Lisp_Object obarray, register const char *ptr, EMACS_INT size, EMACS_I Lisp_Object bucket, tem; if (!VECTORP (obarray) - || (obsize = XVECTOR (obarray)->size) == 0) + || (obsize = XVECTOR_SIZE (obarray)) == 0) { obarray = check_obarray (obarray); - obsize = XVECTOR (obarray)->size; + obsize = XVECTOR_SIZE (obarray); } /* This is sometimes needed in the middle of GC. */ obsize &= ~ARRAY_MARK_FLAG; @@ -3863,7 +3881,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 = XVECTOR_SIZE (obarray) - 1; i >= 0; i--) { tail = XVECTOR (obarray)->contents[i]; if (SYMBOLP (tail)) @@ -3943,7 +3961,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); }