aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/editfns.c43
-rw-r--r--src/lread.c59
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
3860static ptrdiff_t
3861str2num (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
3854DEFUN ("format", Fformat, Sformat, 1, MANY, 0, 3871DEFUN ("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.
3856The first argument is a format control string. 3873The 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
3511Lisp_Object 3506Lisp_Object
3512string_to_number (char const *string, int base, bool ignore_trailing) 3507string_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. */