/*
=head1 Numeric functions
+=cut
+
This file contains all the stuff needed by perl for manipulating numeric
values, including such things as replacements for the OS's atof() function
-=cut
-
*/
#include "EXTERN.h"
#include "perl.h"
U32
-Perl_cast_ulong(pTHX_ NV f)
+Perl_cast_ulong(NV f)
{
- PERL_UNUSED_CONTEXT;
if (f < 0.0)
return f < I32_MIN ? (U32) I32_MIN : (U32)(I32) f;
if (f < U32_MAX_P1) {
}
I32
-Perl_cast_i32(pTHX_ NV f)
+Perl_cast_i32(NV f)
{
- PERL_UNUSED_CONTEXT;
if (f < I32_MAX_P1)
return f < I32_MIN ? I32_MIN : (I32) f;
if (f < U32_MAX_P1) {
}
IV
-Perl_cast_iv(pTHX_ NV f)
+Perl_cast_iv(NV f)
{
- PERL_UNUSED_CONTEXT;
if (f < IV_MAX_P1)
return f < IV_MIN ? IV_MIN : (IV) f;
if (f < UV_MAX_P1) {
}
UV
-Perl_cast_uv(pTHX_ NV f)
+Perl_cast_uv(NV f)
{
- PERL_UNUSED_CONTEXT;
if (f < 0.0)
return f < IV_MIN ? (UV) IV_MIN : (UV)(IV) f;
if (f < UV_MAX_P1) {
UV
Perl_grok_hex(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
{
- dVAR;
const char *s = start;
STRLEN len = *len_p;
UV value = 0;
Perl_grok_numeric_radix(pTHX_ const char **sp, const char *send)
{
#ifdef USE_LOCALE_NUMERIC
- dVAR;
-
PERL_ARGS_ASSERT_GROK_NUMERIC_RADIX;
- if (PL_numeric_radix_sv && IN_SOME_LOCALE_FORM) {
- STRLEN len;
- const char * const radix = SvPV(PL_numeric_radix_sv, len);
- if (*sp + len <= send && memEQ(*sp, radix, len)) {
- *sp += len;
- return TRUE;
+ if (IN_LC(LC_NUMERIC)) {
+ DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED();
+ if (PL_numeric_radix_sv) {
+ STRLEN len;
+ const char * const radix = SvPV(PL_numeric_radix_sv, len);
+ if (*sp + len <= send && memEQ(*sp, radix, len)) {
+ *sp += len;
+ RESTORE_LC_NUMERIC();
+ return TRUE;
+ }
}
+ RESTORE_LC_NUMERIC();
}
/* always try "." if numeric radix didn't match because
* we may have data from different locales mixed */
}
/*
-=for apidoc grok_number
+=for apidoc grok_number_flags
Recognise (or not) a number. The type of the number is returned
(0 if unrecognised), otherwise it is a bit-ORed combination of
absolute value). IS_NUMBER_IN_UV is not set if e notation was used or the
number is larger than a UV.
+C<flags> allows only C<PERL_SCAN_TRAILING>, which allows for trailing
+non-numeric text on an otherwise successful I<grok>, setting
+C<IS_NUMBER_TRAILING> on the result.
+
+=for apidoc grok_number
+
+Identical to grok_number_flags() with flags set to zero.
+
=cut
*/
int
Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
{
+ PERL_ARGS_ASSERT_GROK_NUMBER;
+
+ return grok_number_flags(pv, len, valuep, 0);
+}
+
+int
+Perl_grok_number_flags(pTHX_ const char *pv, STRLEN len, UV *valuep, U32 flags)
+{
const char *s = pv;
const char * const send = pv + len;
const UV max_div_10 = UV_MAX / 10;
int sawinf = 0;
int sawnan = 0;
- PERL_ARGS_ASSERT_GROK_NUMBER;
+ PERL_ARGS_ASSERT_GROK_NUMBER_FLAGS;
while (s < send && isSPACE(*s))
s++;
} else if (s < send) {
/* we can have an optional exponent part */
if (*s == 'e' || *s == 'E') {
- /* The only flag we keep is sign. Blow away any "it's UV" */
- numtype &= IS_NUMBER_NEG;
- numtype |= IS_NUMBER_NOT_INT;
s++;
if (s < send && (*s == '-' || *s == '+'))
s++;
s++;
} while (s < send && isDIGIT(*s));
}
+ else if (flags & PERL_SCAN_TRAILING)
+ return numtype | IS_NUMBER_TRAILING;
else
- return 0;
+ return 0;
+
+ /* The only flag we keep is sign. Blow away any "it's UV" */
+ numtype &= IS_NUMBER_NEG;
+ numtype |= IS_NUMBER_NOT_INT;
}
}
while (s < send && isSPACE(*s))
*valuep = 0;
return IS_NUMBER_IN_UV;
}
+ else if (flags & PERL_SCAN_TRAILING) {
+ return numtype | IS_NUMBER_TRAILING;
+ }
+
return 0;
}
+/*
+=for apidoc grok_atou
+
+grok_atou is a safer replacement for atoi and strtol.
+
+grok_atou parses a C-style zero-byte terminated string, looking for
+a decimal unsigned integer.
+
+Returns the unsigned integer, if a valid value can be parsed
+from the beginning of the string.
+
+Accepts only the decimal digits '0'..'9'.
+
+As opposed to atoi or strtol, grok_atou does NOT allow optional
+leading whitespace, or negative inputs. If such features are
+required, the calling code needs to explicitly implement those.
+
+If a valid value cannot be parsed, returns either zero (if non-digits
+are met before any digits) or Size_t_MAX (if the value overflows).
+
+Note that extraneous leading zeros also count as an overflow
+(meaning that only "0" is the zero).
+
+On failure, the *endptr is also set to NULL, unless endptr is NULL.
+
+Trailing non-digit bytes are allowed if the endptr is non-NULL.
+On return the *endptr will contain the pointer to the first non-digit byte.
+
+If the endptr is NULL, the first non-digit byte MUST be
+the zero byte terminating the pv, or zero will be returned.
+
+Background: atoi has severe problems with illegal inputs, it cannot be
+used for incremental parsing, and therefore should be avoided
+atoi and strtol are also affected by locale settings, which can also be
+seen as a bug (global state controlled by user environment).
+
+=cut
+*/
+
+Size_t
+Perl_grok_atou(const char *pv, const char** endptr)
+{
+ const char* s = pv;
+ const char** eptr;
+ const char* end2; /* Used in case endptr is NULL. */
+ /* With Size_t_size of 8 or 4 this works out to be the start plus
+ * either 20 or 10. When 128 or 256-bit systems became reality,
+ * this overshoots (should get 39, 78, but gets 40, 80). */
+ const char* maxend = s + 10 * (Size_t_size / 4);
+ Size_t val = 0; /* The return value. */
+
+ PERL_ARGS_ASSERT_GROK_ATOU;
+
+ eptr = endptr ? endptr : &end2;
+ if (isDIGIT(*s) && !isDIGIT(*(s + 1))) {
+ /* Single-digit inputs are quite common cases, and in addition
+ * the case of zero ("0") here simplifies the decoding loop:
+ * not having to think whether "000" or "000123" are valid
+ * (now they are invalid). */
+ val = *s++ - '0';
+ } else {
+ Size_t tmp = 0; /* Temporary accumulator. */
+
+ while (s < maxend && *s) {
+ /* This could be unrolled like in grok_number(), but
+ * the expected uses of this are not speed-needy, and
+ * unlikely to need full 64-bitness. */
+ if (isDIGIT(*s)) {
+ int digit = *s++ - '0';
+ tmp = tmp * 10 + digit;
+ if (tmp > val) { /* This implictly rejects leading zeros. */
+ val = tmp;
+ } else { /* Overflow. */
+ *eptr = NULL;
+ return Size_t_MAX;
+ }
+ } else {
+ break;
+ }
+ }
+ if (s == pv) {
+ *eptr = NULL; /* If no progress, failed to parse anything. */
+ return 0;
+ }
+ }
+ if (endptr == NULL && *s) {
+ return 0; /* If endptr is NULL, no trailing non-digits allowed. */
+ }
+ *eptr = s;
+ return val;
+}
+
STATIC NV
S_mulexp10(NV value, I32 exponent)
{
{
NV x = 0.0;
#ifdef USE_LOCALE_NUMERIC
- dVAR;
-
PERL_ARGS_ASSERT_MY_ATOF;
{
DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED();
- if (PL_numeric_local && PL_numeric_radix_sv && IN_SOME_LOCALE_FORM) {
+ if (PL_numeric_radix_sv && IN_LC(LC_NUMERIC)) {
const char *standard = NULL, *local = NULL;
bool use_standard_radix;