diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 43 | ||||
| -rw-r--r-- | src/lread.c | 59 |
2 files changed, 56 insertions, 46 deletions
diff --git a/src/editfns.c b/src/editfns.c index 98187df5d97..1dbae8f5d4b 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3851,6 +3851,23 @@ usage: (propertize STRING &rest PROPERTIES) */) | |||
| 3851 | return string; | 3851 | return string; |
| 3852 | } | 3852 | } |
| 3853 | 3853 | ||
| 3854 | /* Convert the prefix of STR from ASCII decimal digits to a number. | ||
| 3855 | Set *STR_END to the address of the first non-digit. Return the | ||
| 3856 | number, or PTRDIFF_MAX on overflow. Return 0 if there is no number. | ||
| 3857 | This is like strtol for ptrdiff_t and base 10 and C locale, | ||
| 3858 | except without negative numbers or errno. */ | ||
| 3859 | |||
| 3860 | static ptrdiff_t | ||
| 3861 | str2num (char *str, char **str_end) | ||
| 3862 | { | ||
| 3863 | ptrdiff_t n = 0; | ||
| 3864 | for (; c_isdigit (*str); str++) | ||
| 3865 | if (INT_MULTIPLY_WRAPV (n, 10, &n) || INT_ADD_WRAPV (n, *str - '0', &n)) | ||
| 3866 | n = PTRDIFF_MAX; | ||
| 3867 | *str_end = str; | ||
| 3868 | return n; | ||
| 3869 | } | ||
| 3870 | |||
| 3854 | DEFUN ("format", Fformat, Sformat, 1, MANY, 0, | 3871 | DEFUN ("format", Fformat, Sformat, 1, MANY, 0, |
| 3855 | doc: /* Format a string out of a format-string and arguments. | 3872 | doc: /* Format a string out of a format-string and arguments. |
| 3856 | The first argument is a format control string. | 3873 | The first argument is a format control string. |
| @@ -4057,17 +4074,16 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4057 | digits to print after the '.' for floats, or the max. | 4074 | digits to print after the '.' for floats, or the max. |
| 4058 | number of chars to print from a string. */ | 4075 | number of chars to print from a string. */ |
| 4059 | 4076 | ||
| 4060 | uintmax_t num; | 4077 | ptrdiff_t num; |
| 4061 | char *num_end; | 4078 | char *num_end; |
| 4062 | if (c_isdigit (*format)) | 4079 | if (c_isdigit (*format)) |
| 4063 | { | 4080 | { |
| 4064 | num = strtoumax (format, &num_end, 10); | 4081 | num = str2num (format, &num_end); |
| 4065 | if (*num_end == '$') | 4082 | if (*num_end == '$') |
| 4066 | { | 4083 | { |
| 4067 | if (num == 0) | 4084 | if (num == 0) |
| 4068 | error ("Invalid format field number 0"); | 4085 | error ("Invalid format field number 0"); |
| 4069 | n = min (num, PTRDIFF_MAX); | 4086 | n = num - 1; |
| 4070 | n--; | ||
| 4071 | format = num_end + 1; | 4087 | format = num_end + 1; |
| 4072 | } | 4088 | } |
| 4073 | } | 4089 | } |
| @@ -4095,15 +4111,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4095 | space_flag &= ! plus_flag; | 4111 | space_flag &= ! plus_flag; |
| 4096 | zero_flag &= ! minus_flag; | 4112 | zero_flag &= ! minus_flag; |
| 4097 | 4113 | ||
| 4098 | num = strtoumax (format, &num_end, 10); | 4114 | num = str2num (format, &num_end); |
| 4099 | if (max_bufsize <= num) | 4115 | if (max_bufsize <= num) |
| 4100 | string_overflow (); | 4116 | string_overflow (); |
| 4101 | ptrdiff_t field_width = num; | 4117 | ptrdiff_t field_width = num; |
| 4102 | 4118 | ||
| 4103 | bool precision_given = *num_end == '.'; | 4119 | bool precision_given = *num_end == '.'; |
| 4104 | uintmax_t precision = (precision_given | 4120 | ptrdiff_t precision = (precision_given |
| 4105 | ? strtoumax (num_end + 1, &num_end, 10) | 4121 | ? str2num (num_end + 1, &num_end) |
| 4106 | : UINTMAX_MAX); | 4122 | : PTRDIFF_MAX); |
| 4107 | format = num_end; | 4123 | format = num_end; |
| 4108 | 4124 | ||
| 4109 | if (format == end) | 4125 | if (format == end) |
| @@ -4176,7 +4192,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4176 | /* handle case (precision[n] >= 0) */ | 4192 | /* handle case (precision[n] >= 0) */ |
| 4177 | 4193 | ||
| 4178 | ptrdiff_t prec = -1; | 4194 | ptrdiff_t prec = -1; |
| 4179 | if (precision_given && precision <= TYPE_MAXIMUM (ptrdiff_t)) | 4195 | if (precision_given) |
| 4180 | prec = precision; | 4196 | prec = precision; |
| 4181 | 4197 | ||
| 4182 | /* lisp_string_width ignores a precision of 0, but GNU | 4198 | /* lisp_string_width ignores a precision of 0, but GNU |
| @@ -4424,8 +4440,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4424 | padding and excess precision. Deal with excess precision | 4440 | padding and excess precision. Deal with excess precision |
| 4425 | first. This happens only when the format specifies | 4441 | first. This happens only when the format specifies |
| 4426 | ridiculously large precision. */ | 4442 | ridiculously large precision. */ |
| 4427 | uintmax_t excess_precision = precision - prec; | 4443 | ptrdiff_t excess_precision |
| 4428 | uintmax_t leading_zeros = 0, trailing_zeros = 0; | 4444 | = precision_given ? precision - prec : 0; |
| 4445 | ptrdiff_t leading_zeros = 0, trailing_zeros = 0; | ||
| 4429 | if (excess_precision) | 4446 | if (excess_precision) |
| 4430 | { | 4447 | { |
| 4431 | if (float_conversion) | 4448 | if (float_conversion) |
| @@ -4451,7 +4468,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4451 | 4468 | ||
| 4452 | /* Compute the total bytes needed for this item, including | 4469 | /* Compute the total bytes needed for this item, including |
| 4453 | excess precision and padding. */ | 4470 | excess precision and padding. */ |
| 4454 | uintmax_t numwidth = sprintf_bytes + excess_precision; | 4471 | ptrdiff_t numwidth; |
| 4472 | if (INT_ADD_WRAPV (sprintf_bytes, excess_precision, &numwidth)) | ||
| 4473 | numwidth = PTRDIFF_MAX; | ||
| 4455 | ptrdiff_t padding | 4474 | ptrdiff_t padding |
| 4456 | = numwidth < field_width ? field_width - numwidth : 0; | 4475 | = numwidth < field_width ? field_width - numwidth : 0; |
| 4457 | if (max_bufsize - sprintf_bytes <= excess_precision | 4476 | if (max_bufsize - sprintf_bytes <= excess_precision |
diff --git a/src/lread.c b/src/lread.c index 368b86e8189..f8493982c67 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -3495,25 +3495,18 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg) | |||
| 3495 | } | 3495 | } |
| 3496 | 3496 | ||
| 3497 | 3497 | ||
| 3498 | #define LEAD_INT 1 | 3498 | /* Convert STRING to a number, assuming base BASE. Return a fixnum if |
| 3499 | #define DOT_CHAR 2 | 3499 | STRING has integer syntax and fits in a fixnum, else return the |
| 3500 | #define TRAIL_INT 4 | 3500 | nearest float if STRING has either floating point or integer syntax |
| 3501 | #define E_EXP 16 | 3501 | and BASE is 10, else return nil. If IGNORE_TRAILING, consider just |
| 3502 | 3502 | the longest prefix of STRING that has valid floating point syntax. | |
| 3503 | 3503 | Signal an overflow if BASE is not 10 and the number has integer | |
| 3504 | /* Convert STRING to a number, assuming base BASE. Return a fixnum if CP has | 3504 | syntax but does not fit. */ |
| 3505 | integer syntax and fits in a fixnum, else return the nearest float if CP has | ||
| 3506 | either floating point or integer syntax and BASE is 10, else return nil. If | ||
| 3507 | IGNORE_TRAILING, consider just the longest prefix of CP that has | ||
| 3508 | valid floating point syntax. Signal an overflow if BASE is not 10 and the | ||
| 3509 | number has integer syntax but does not fit. */ | ||
| 3510 | 3505 | ||
| 3511 | Lisp_Object | 3506 | Lisp_Object |
| 3512 | string_to_number (char const *string, int base, bool ignore_trailing) | 3507 | string_to_number (char const *string, int base, bool ignore_trailing) |
| 3513 | { | 3508 | { |
| 3514 | int state; | ||
| 3515 | char const *cp = string; | 3509 | char const *cp = string; |
| 3516 | int leading_digit; | ||
| 3517 | bool float_syntax = 0; | 3510 | bool float_syntax = 0; |
| 3518 | double value = 0; | 3511 | double value = 0; |
| 3519 | 3512 | ||
| @@ -3525,15 +3518,23 @@ string_to_number (char const *string, int base, bool ignore_trailing) | |||
| 3525 | bool signedp = negative || *cp == '+'; | 3518 | bool signedp = negative || *cp == '+'; |
| 3526 | cp += signedp; | 3519 | cp += signedp; |
| 3527 | 3520 | ||
| 3528 | state = 0; | 3521 | enum { INTOVERFLOW = 1, LEAD_INT = 2, DOT_CHAR = 4, TRAIL_INT = 8, |
| 3529 | 3522 | E_EXP = 16 }; | |
| 3530 | leading_digit = digit_to_number (*cp, base); | 3523 | int state = 0; |
| 3524 | int leading_digit = digit_to_number (*cp, base); | ||
| 3525 | uintmax_t n = leading_digit; | ||
| 3531 | if (leading_digit >= 0) | 3526 | if (leading_digit >= 0) |
| 3532 | { | 3527 | { |
| 3533 | state |= LEAD_INT; | 3528 | state |= LEAD_INT; |
| 3534 | do | 3529 | for (int digit; 0 <= (digit = digit_to_number (*++cp, base)); ) |
| 3535 | ++cp; | 3530 | { |
| 3536 | while (digit_to_number (*cp, base) >= 0); | 3531 | if (INT_MULTIPLY_OVERFLOW (n, base)) |
| 3532 | state |= INTOVERFLOW; | ||
| 3533 | n *= base; | ||
| 3534 | if (INT_ADD_OVERFLOW (n, digit)) | ||
| 3535 | state |= INTOVERFLOW; | ||
| 3536 | n += digit; | ||
| 3537 | } | ||
| 3537 | } | 3538 | } |
| 3538 | if (*cp == '.') | 3539 | if (*cp == '.') |
| 3539 | { | 3540 | { |
| @@ -3583,32 +3584,22 @@ string_to_number (char const *string, int base, bool ignore_trailing) | |||
| 3583 | } | 3584 | } |
| 3584 | 3585 | ||
| 3585 | float_syntax = ((state & (DOT_CHAR|TRAIL_INT)) == (DOT_CHAR|TRAIL_INT) | 3586 | float_syntax = ((state & (DOT_CHAR|TRAIL_INT)) == (DOT_CHAR|TRAIL_INT) |
| 3586 | || state == (LEAD_INT|E_EXP)); | 3587 | || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); |
| 3587 | } | 3588 | } |
| 3588 | 3589 | ||
| 3589 | /* Return nil if the number uses invalid syntax. If IGNORE_TRAILING, accept | 3590 | /* Return nil if the number uses invalid syntax. If IGNORE_TRAILING, accept |
| 3590 | any prefix that matches. Otherwise, the entire string must match. */ | 3591 | any prefix that matches. Otherwise, the entire string must match. */ |
| 3591 | if (! (ignore_trailing | 3592 | if (! (ignore_trailing |
| 3592 | ? ((state & LEAD_INT) != 0 || float_syntax) | 3593 | ? ((state & LEAD_INT) != 0 || float_syntax) |
| 3593 | : (!*cp && ((state & ~DOT_CHAR) == LEAD_INT || float_syntax)))) | 3594 | : (!*cp && ((state & ~(INTOVERFLOW | DOT_CHAR)) == LEAD_INT |
| 3595 | || float_syntax)))) | ||
| 3594 | return Qnil; | 3596 | return Qnil; |
| 3595 | 3597 | ||
| 3596 | /* If the number uses integer and not float syntax, and is in C-language | 3598 | /* If the number uses integer and not float syntax, and is in C-language |
| 3597 | range, use its value, preferably as a fixnum. */ | 3599 | range, use its value, preferably as a fixnum. */ |
| 3598 | if (leading_digit >= 0 && ! float_syntax) | 3600 | if (leading_digit >= 0 && ! float_syntax) |
| 3599 | { | 3601 | { |
| 3600 | uintmax_t n; | 3602 | if (state & INTOVERFLOW) |
| 3601 | |||
| 3602 | /* Fast special case for single-digit integers. This also avoids a | ||
| 3603 | glitch when BASE is 16 and IGNORE_TRAILING, because in that | ||
| 3604 | case some versions of strtoumax accept numbers like "0x1" that Emacs | ||
| 3605 | does not allow. */ | ||
| 3606 | if (digit_to_number (string[signedp + 1], base) < 0) | ||
| 3607 | return make_number (negative ? -leading_digit : leading_digit); | ||
| 3608 | |||
| 3609 | errno = 0; | ||
| 3610 | n = strtoumax (string + signedp, NULL, base); | ||
| 3611 | if (errno == ERANGE) | ||
| 3612 | { | 3603 | { |
| 3613 | /* Unfortunately there's no simple and accurate way to convert | 3604 | /* Unfortunately there's no simple and accurate way to convert |
| 3614 | non-base-10 numbers that are out of C-language range. */ | 3605 | non-base-10 numbers that are out of C-language range. */ |