aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-05-01 19:58:08 -0700
committerPaul Eggert2011-05-01 19:58:08 -0700
commita108c10b7ae69e5f782c83be925c168e007874fb (patch)
tree0dde94f78ed514445cae11fa159c95ccb7822865 /src
parentad5f9eeaa2f0f872e063849f8f0d24d2c200acfa (diff)
downloademacs-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/ChangeLog10
-rw-r--r--src/lread.c104
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 @@
12011-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
12011-04-30 Paul Eggert <eggert@cs.ucla.edu> 112011-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. */
2251static inline int
2252digit_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)
2254static Lisp_Object 2274static Lisp_Object
2255read_integer (Lisp_Object readcharfun, int radix) 2275read_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
3168static inline int
3169digit_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