diff options
| author | Paul Eggert | 2011-05-01 19:58:08 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-05-01 19:58:08 -0700 |
| commit | a108c10b7ae69e5f782c83be925c168e007874fb (patch) | |
| tree | 0dde94f78ed514445cae11fa159c95ccb7822865 /src | |
| parent | ad5f9eeaa2f0f872e063849f8f0d24d2c200acfa (diff) | |
| download | emacs-a108c10b7ae69e5f782c83be925c168e007874fb.tar.gz emacs-a108c10b7ae69e5f782c83be925c168e007874fb.zip | |
* lread.c (read_integer): Be more consistent with string-to-number.
Use string_to_number to do the actual conversion; this avoids
rounding errors and fixes some other screwups. Without this fix,
for example, #x1fffffffffffffff was misread as -2305843009213693952.
(digit_to_number): Move earlier, for benefit of read_integer.
Return -1 if the digit is out of range for the base, -2 if it is
not a digit in any supported base.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/lread.c | 104 |
2 files changed, 66 insertions, 48 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d043bf7f691..a93cc8d2a9d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,13 @@ | |||
| 1 | 2011-05-02 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | * lread.c (read_integer): Be more consistent with string-to-number. | ||
| 4 | Use string_to_number to do the actual conversion; this avoids | ||
| 5 | rounding errors and fixes some other screwups. Without this fix, | ||
| 6 | for example, #x1fffffffffffffff was misread as -2305843009213693952. | ||
| 7 | (digit_to_number): Move earlier, for benefit of read_integer. | ||
| 8 | Return -1 if the digit is out of range for the base, -2 if it is | ||
| 9 | not a digit in any supported base. | ||
| 10 | |||
| 1 | 2011-04-30 Paul Eggert <eggert@cs.ucla.edu> | 11 | 2011-04-30 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 12 | ||
| 3 | * doprnt.c (doprnt): Support arbitrary pI values, such as "I64". | 13 | * doprnt.c (doprnt): Support arbitrary pI values, such as "I64". |
diff --git a/src/lread.c b/src/lread.c index c7c91f8c3e4..7686f966db2 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2245,6 +2245,26 @@ read_escape (Lisp_Object readcharfun, int stringp) | |||
| 2245 | } | 2245 | } |
| 2246 | } | 2246 | } |
| 2247 | 2247 | ||
| 2248 | /* Return the digit that CHARACTER stands for in the given BASE. | ||
| 2249 | Return -1 if CHARACTER is out of range for BASE, | ||
| 2250 | and -2 if CHARACTER is not valid for any supported BASE. */ | ||
| 2251 | static inline int | ||
| 2252 | digit_to_number (int character, int base) | ||
| 2253 | { | ||
| 2254 | int digit; | ||
| 2255 | |||
| 2256 | if ('0' <= character && character <= '9') | ||
| 2257 | digit = character - '0'; | ||
| 2258 | else if ('a' <= character && character <= 'z') | ||
| 2259 | digit = character - 'a' + 10; | ||
| 2260 | else if ('A' <= character && character <= 'Z') | ||
| 2261 | digit = character - 'A' + 10; | ||
| 2262 | else | ||
| 2263 | return -2; | ||
| 2264 | |||
| 2265 | return digit < base ? digit : -1; | ||
| 2266 | } | ||
| 2267 | |||
| 2248 | /* Read an integer in radix RADIX using READCHARFUN to read | 2268 | /* Read an integer in radix RADIX using READCHARFUN to read |
| 2249 | characters. RADIX must be in the interval [2..36]; if it isn't, a | 2269 | characters. RADIX must be in the interval [2..36]; if it isn't, a |
| 2250 | read error is signaled . Value is the integer read. Signals an | 2270 | read error is signaled . Value is the integer read. Signals an |
| @@ -2254,59 +2274,64 @@ read_escape (Lisp_Object readcharfun, int stringp) | |||
| 2254 | static Lisp_Object | 2274 | static Lisp_Object |
| 2255 | read_integer (Lisp_Object readcharfun, int radix) | 2275 | read_integer (Lisp_Object readcharfun, int radix) |
| 2256 | { | 2276 | { |
| 2257 | int ndigits = 0, invalid_p, c, sign = 0; | 2277 | /* Room for sign, leading 0, other digits, trailing null byte. */ |
| 2258 | /* We use a floating point number because */ | 2278 | char buf[1 + 1 + sizeof (uintmax_t) * CHAR_BIT + 1]; |
| 2259 | double number = 0; | 2279 | |
| 2280 | int valid = -1; /* 1 if valid, 0 if not, -1 if incomplete. */ | ||
| 2260 | 2281 | ||
| 2261 | if (radix < 2 || radix > 36) | 2282 | if (radix < 2 || radix > 36) |
| 2262 | invalid_p = 1; | 2283 | valid = 0; |
| 2263 | else | 2284 | else |
| 2264 | { | 2285 | { |
| 2265 | number = ndigits = invalid_p = 0; | 2286 | char *p = buf; |
| 2266 | sign = 1; | 2287 | int c, digit; |
| 2267 | 2288 | ||
| 2268 | c = READCHAR; | 2289 | c = READCHAR; |
| 2269 | if (c == '-') | 2290 | if (c == '-' || c == '+') |
| 2270 | { | 2291 | { |
| 2292 | *p++ = c; | ||
| 2271 | c = READCHAR; | 2293 | c = READCHAR; |
| 2272 | sign = -1; | ||
| 2273 | } | 2294 | } |
| 2274 | else if (c == '+') | ||
| 2275 | c = READCHAR; | ||
| 2276 | 2295 | ||
| 2277 | while (c >= 0) | 2296 | if (c == '0') |
| 2278 | { | 2297 | { |
| 2279 | int digit; | 2298 | *p++ = c; |
| 2280 | 2299 | valid = 1; | |
| 2281 | if (c >= '0' && c <= '9') | 2300 | |
| 2282 | digit = c - '0'; | 2301 | /* Ignore redundant leading zeros, so the buffer doesn't |
| 2283 | else if (c >= 'a' && c <= 'z') | 2302 | fill up with them. */ |
| 2284 | digit = c - 'a' + 10; | 2303 | do |
| 2285 | else if (c >= 'A' && c <= 'Z') | 2304 | c = READCHAR; |
| 2286 | digit = c - 'A' + 10; | 2305 | while (c == '0'); |
| 2287 | else | 2306 | } |
| 2288 | { | ||
| 2289 | UNREAD (c); | ||
| 2290 | break; | ||
| 2291 | } | ||
| 2292 | 2307 | ||
| 2293 | if (digit < 0 || digit >= radix) | 2308 | while (-1 <= (digit = digit_to_number (c, radix))) |
| 2294 | invalid_p = 1; | 2309 | { |
| 2310 | if (digit == -1) | ||
| 2311 | valid = 0; | ||
| 2312 | if (valid < 0) | ||
| 2313 | valid = 1; | ||
| 2314 | |||
| 2315 | if (p < buf + sizeof buf - 1) | ||
| 2316 | *p++ = c; | ||
| 2317 | else | ||
| 2318 | valid = 0; | ||
| 2295 | 2319 | ||
| 2296 | number = radix * number + digit; | ||
| 2297 | ++ndigits; | ||
| 2298 | c = READCHAR; | 2320 | c = READCHAR; |
| 2299 | } | 2321 | } |
| 2322 | |||
| 2323 | if (c >= 0) | ||
| 2324 | UNREAD (c); | ||
| 2325 | *p = '\0'; | ||
| 2300 | } | 2326 | } |
| 2301 | 2327 | ||
| 2302 | if (ndigits == 0 || invalid_p) | 2328 | if (! valid) |
| 2303 | { | 2329 | { |
| 2304 | char buf[50]; | ||
| 2305 | sprintf (buf, "integer, radix %d", radix); | 2330 | sprintf (buf, "integer, radix %d", radix); |
| 2306 | invalid_syntax (buf, 0); | 2331 | invalid_syntax (buf, 0); |
| 2307 | } | 2332 | } |
| 2308 | 2333 | ||
| 2309 | return make_fixnum_or_float (sign * number); | 2334 | return string_to_number (buf, radix, 0); |
| 2310 | } | 2335 | } |
| 2311 | 2336 | ||
| 2312 | 2337 | ||
| @@ -3165,23 +3190,6 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg) | |||
| 3165 | } | 3190 | } |
| 3166 | 3191 | ||
| 3167 | 3192 | ||
| 3168 | static inline int | ||
| 3169 | digit_to_number (int character, int base) | ||
| 3170 | { | ||
| 3171 | int digit; | ||
| 3172 | |||
| 3173 | if ('0' <= character && character <= '9') | ||
| 3174 | digit = character - '0'; | ||
| 3175 | else if ('a' <= character && character <= 'z') | ||
| 3176 | digit = character - 'a' + 10; | ||
| 3177 | else if ('A' <= character && character <= 'Z') | ||
| 3178 | digit = character - 'A' + 10; | ||
| 3179 | else | ||
| 3180 | return -1; | ||
| 3181 | |||
| 3182 | return digit < base ? digit : -1; | ||
| 3183 | } | ||
| 3184 | |||
| 3185 | #define LEAD_INT 1 | 3193 | #define LEAD_INT 1 |
| 3186 | #define DOT_CHAR 2 | 3194 | #define DOT_CHAR 2 |
| 3187 | #define TRAIL_INT 4 | 3195 | #define TRAIL_INT 4 |