Blame parts/inc/grok

Packit 7d6a7d
################################################################################
Packit 7d6a7d
##
Packit 7d6a7d
##  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
Packit 7d6a7d
##  Version 2.x, Copyright (C) 2001, Paul Marquess.
Packit 7d6a7d
##  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
Packit 7d6a7d
##
Packit 7d6a7d
##  This program is free software; you can redistribute it and/or
Packit 7d6a7d
##  modify it under the same terms as Perl itself.
Packit 7d6a7d
##
Packit 7d6a7d
################################################################################
Packit 7d6a7d
Packit 7d6a7d
=provides
Packit 7d6a7d
Packit 7d6a7d
grok_hex
Packit 7d6a7d
grok_oct
Packit 7d6a7d
grok_bin
Packit 7d6a7d
grok_numeric_radix
Packit 7d6a7d
grok_number
Packit 7d6a7d
__UNDEFINED__
Packit 7d6a7d
Packit 7d6a7d
=implementation
Packit 7d6a7d
Packit 7d6a7d
__UNDEFINED__  IN_PERL_COMPILETIME    (PL_curcop == &PL_compiling)
Packit 7d6a7d
__UNDEFINED__  IN_LOCALE_RUNTIME      (PL_curcop->op_private & HINT_LOCALE)
Packit 7d6a7d
__UNDEFINED__  IN_LOCALE_COMPILETIME  (PL_hints & HINT_LOCALE)
Packit 7d6a7d
__UNDEFINED__  IN_LOCALE              (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME)
Packit 7d6a7d
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_IN_UV                 0x01
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_GREATER_THAN_UV_MAX   0x02
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_NOT_INT               0x04
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_NEG                   0x08
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_INFINITY              0x10
Packit 7d6a7d
__UNDEFINED__  IS_NUMBER_NAN                   0x20
Packit 7d6a7d
Packit 7d6a7d
__UNDEFINED__  GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send)
Packit 7d6a7d
Packit 7d6a7d
__UNDEFINED__  PERL_SCAN_GREATER_THAN_UV_MAX   0x02
Packit 7d6a7d
__UNDEFINED__  PERL_SCAN_SILENT_ILLDIGIT       0x04
Packit 7d6a7d
__UNDEFINED__  PERL_SCAN_ALLOW_UNDERSCORES     0x01
Packit 7d6a7d
__UNDEFINED__  PERL_SCAN_DISALLOW_PREFIX       0x02
Packit 7d6a7d
Packit 7d6a7d
#ifndef grok_numeric_radix
Packit 7d6a7d
#if { NEED grok_numeric_radix }
Packit 7d6a7d
bool
Packit 7d6a7d
grok_numeric_radix(pTHX_ const char **sp, const char *send)
Packit 7d6a7d
{
Packit 7d6a7d
#ifdef USE_LOCALE_NUMERIC
Packit 7d6a7d
#ifdef PL_numeric_radix_sv
Packit 7d6a7d
    if (PL_numeric_radix_sv && IN_LOCALE) {
Packit 7d6a7d
        STRLEN len;
Packit 7d6a7d
        char* radix = SvPV(PL_numeric_radix_sv, len);
Packit 7d6a7d
        if (*sp + len <= send && memEQ(*sp, radix, len)) {
Packit 7d6a7d
            *sp += len;
Packit 7d6a7d
            return TRUE;
Packit 7d6a7d
        }
Packit 7d6a7d
    }
Packit 7d6a7d
#else
Packit 7d6a7d
    /* older perls don't have PL_numeric_radix_sv so the radix
Packit 7d6a7d
     * must manually be requested from locale.h
Packit 7d6a7d
     */
Packit 7d6a7d
#include <locale.h>
Packit 7d6a7d
    dTHR;  /* needed for older threaded perls */
Packit 7d6a7d
    struct lconv *lc = localeconv();
Packit 7d6a7d
    char *radix = lc->decimal_point;
Packit 7d6a7d
    if (radix && IN_LOCALE) {
Packit 7d6a7d
        STRLEN len = strlen(radix);
Packit 7d6a7d
        if (*sp + len <= send && memEQ(*sp, radix, len)) {
Packit 7d6a7d
            *sp += len;
Packit 7d6a7d
            return TRUE;
Packit 7d6a7d
        }
Packit 7d6a7d
    }
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif /* USE_LOCALE_NUMERIC */
Packit 7d6a7d
    /* always try "." if numeric radix didn't match because
Packit 7d6a7d
     * we may have data from different locales mixed */
Packit 7d6a7d
    if (*sp < send && **sp == '.') {
Packit 7d6a7d
        ++*sp;
Packit 7d6a7d
        return TRUE;
Packit 7d6a7d
    }
Packit 7d6a7d
    return FALSE;
Packit 7d6a7d
}
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
#ifndef grok_number
Packit 7d6a7d
#if { NEED grok_number }
Packit 7d6a7d
int
Packit 7d6a7d
grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
Packit 7d6a7d
{
Packit 7d6a7d
  const char *s = pv;
Packit 7d6a7d
  const char *send = pv + len;
Packit 7d6a7d
  const UV max_div_10 = UV_MAX / 10;
Packit 7d6a7d
  const char max_mod_10 = UV_MAX % 10;
Packit 7d6a7d
  int numtype = 0;
Packit 7d6a7d
  int sawinf = 0;
Packit 7d6a7d
  int sawnan = 0;
Packit 7d6a7d
Packit 7d6a7d
  while (s < send && isSPACE(*s))
Packit 7d6a7d
    s++;
Packit 7d6a7d
  if (s == send) {
Packit 7d6a7d
    return 0;
Packit 7d6a7d
  } else if (*s == '-') {
Packit 7d6a7d
    s++;
Packit 7d6a7d
    numtype = IS_NUMBER_NEG;
Packit 7d6a7d
  }
Packit 7d6a7d
  else if (*s == '+')
Packit 7d6a7d
  s++;
Packit 7d6a7d
Packit 7d6a7d
  if (s == send)
Packit 7d6a7d
    return 0;
Packit 7d6a7d
Packit 7d6a7d
  /* next must be digit or the radix separator or beginning of infinity */
Packit 7d6a7d
  if (isDIGIT(*s)) {
Packit 7d6a7d
    /* UVs are at least 32 bits, so the first 9 decimal digits cannot
Packit 7d6a7d
       overflow.  */
Packit 7d6a7d
    UV value = *s - '0';
Packit 7d6a7d
    /* This construction seems to be more optimiser friendly.
Packit 7d6a7d
       (without it gcc does the isDIGIT test and the *s - '0' separately)
Packit 7d6a7d
       With it gcc on arm is managing 6 instructions (6 cycles) per digit.
Packit 7d6a7d
       In theory the optimiser could deduce how far to unroll the loop
Packit 7d6a7d
       before checking for overflow.  */
Packit 7d6a7d
    if (++s < send) {
Packit 7d6a7d
      int digit = *s - '0';
Packit 7d6a7d
      if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
        value = value * 10 + digit;
Packit 7d6a7d
        if (++s < send) {
Packit 7d6a7d
          digit = *s - '0';
Packit 7d6a7d
          if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
            value = value * 10 + digit;
Packit 7d6a7d
            if (++s < send) {
Packit 7d6a7d
              digit = *s - '0';
Packit 7d6a7d
              if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                value = value * 10 + digit;
Packit 7d6a7d
                if (++s < send) {
Packit 7d6a7d
                  digit = *s - '0';
Packit 7d6a7d
                  if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                    value = value * 10 + digit;
Packit 7d6a7d
                    if (++s < send) {
Packit 7d6a7d
                      digit = *s - '0';
Packit 7d6a7d
                      if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                        value = value * 10 + digit;
Packit 7d6a7d
                        if (++s < send) {
Packit 7d6a7d
                          digit = *s - '0';
Packit 7d6a7d
                          if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                            value = value * 10 + digit;
Packit 7d6a7d
                            if (++s < send) {
Packit 7d6a7d
                              digit = *s - '0';
Packit 7d6a7d
                              if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                                value = value * 10 + digit;
Packit 7d6a7d
                                if (++s < send) {
Packit 7d6a7d
                                  digit = *s - '0';
Packit 7d6a7d
                                  if (digit >= 0 && digit <= 9) {
Packit 7d6a7d
                                    value = value * 10 + digit;
Packit 7d6a7d
                                    if (++s < send) {
Packit 7d6a7d
                                      /* Now got 9 digits, so need to check
Packit 7d6a7d
                                         each time for overflow.  */
Packit 7d6a7d
                                      digit = *s - '0';
Packit 7d6a7d
                                      while (digit >= 0 && digit <= 9
Packit 7d6a7d
                                             && (value < max_div_10
Packit 7d6a7d
                                                 || (value == max_div_10
Packit 7d6a7d
                                                     && digit <= max_mod_10))) {
Packit 7d6a7d
                                        value = value * 10 + digit;
Packit 7d6a7d
                                        if (++s < send)
Packit 7d6a7d
                                          digit = *s - '0';
Packit 7d6a7d
                                        else
Packit 7d6a7d
                                          break;
Packit 7d6a7d
                                      }
Packit 7d6a7d
                                      if (digit >= 0 && digit <= 9
Packit 7d6a7d
                                          && (s < send)) {
Packit 7d6a7d
                                        /* value overflowed.
Packit 7d6a7d
                                           skip the remaining digits, don't
Packit 7d6a7d
                                           worry about setting *valuep.  */
Packit 7d6a7d
                                        do {
Packit 7d6a7d
                                          s++;
Packit 7d6a7d
                                        } while (s < send && isDIGIT(*s));
Packit 7d6a7d
                                        numtype |=
Packit 7d6a7d
                                          IS_NUMBER_GREATER_THAN_UV_MAX;
Packit 7d6a7d
                                        goto skip_value;
Packit 7d6a7d
                                      }
Packit 7d6a7d
                                    }
Packit 7d6a7d
                                  }
Packit 7d6a7d
                                }
Packit 7d6a7d
                              }
Packit 7d6a7d
                            }
Packit 7d6a7d
                          }
Packit 7d6a7d
                        }
Packit 7d6a7d
                      }
Packit 7d6a7d
                    }
Packit 7d6a7d
                  }
Packit 7d6a7d
                }
Packit 7d6a7d
              }
Packit 7d6a7d
            }
Packit 7d6a7d
          }
Packit 7d6a7d
        }
Packit 7d6a7d
      }
Packit 7d6a7d
    }
Packit 7d6a7d
    numtype |= IS_NUMBER_IN_UV;
Packit 7d6a7d
    if (valuep)
Packit 7d6a7d
      *valuep = value;
Packit 7d6a7d
Packit 7d6a7d
  skip_value:
Packit 7d6a7d
    if (GROK_NUMERIC_RADIX(&s, send)) {
Packit 7d6a7d
      numtype |= IS_NUMBER_NOT_INT;
Packit 7d6a7d
      while (s < send && isDIGIT(*s))  /* optional digits after the radix */
Packit 7d6a7d
        s++;
Packit 7d6a7d
    }
Packit 7d6a7d
  }
Packit 7d6a7d
  else if (GROK_NUMERIC_RADIX(&s, send)) {
Packit 7d6a7d
    numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */
Packit 7d6a7d
    /* no digits before the radix means we need digits after it */
Packit 7d6a7d
    if (s < send && isDIGIT(*s)) {
Packit 7d6a7d
      do {
Packit 7d6a7d
        s++;
Packit 7d6a7d
      } while (s < send && isDIGIT(*s));
Packit 7d6a7d
      if (valuep) {
Packit 7d6a7d
        /* integer approximation is valid - it's 0.  */
Packit 7d6a7d
        *valuep = 0;
Packit 7d6a7d
      }
Packit 7d6a7d
    }
Packit 7d6a7d
    else
Packit 7d6a7d
      return 0;
Packit 7d6a7d
  } else if (*s == 'I' || *s == 'i') {
Packit 7d6a7d
    s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
Packit 7d6a7d
    s++; if (s == send || (*s != 'F' && *s != 'f')) return 0;
Packit 7d6a7d
    s++; if (s < send && (*s == 'I' || *s == 'i')) {
Packit 7d6a7d
      s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
Packit 7d6a7d
      s++; if (s == send || (*s != 'I' && *s != 'i')) return 0;
Packit 7d6a7d
      s++; if (s == send || (*s != 'T' && *s != 't')) return 0;
Packit 7d6a7d
      s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0;
Packit 7d6a7d
      s++;
Packit 7d6a7d
    }
Packit 7d6a7d
    sawinf = 1;
Packit 7d6a7d
  } else if (*s == 'N' || *s == 'n') {
Packit 7d6a7d
    /* XXX TODO: There are signaling NaNs and quiet NaNs. */
Packit 7d6a7d
    s++; if (s == send || (*s != 'A' && *s != 'a')) return 0;
Packit 7d6a7d
    s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
Packit 7d6a7d
    s++;
Packit 7d6a7d
    sawnan = 1;
Packit 7d6a7d
  } else
Packit 7d6a7d
    return 0;
Packit 7d6a7d
Packit 7d6a7d
  if (sawinf) {
Packit 7d6a7d
    numtype &= IS_NUMBER_NEG; /* Keep track of sign  */
Packit 7d6a7d
    numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
Packit 7d6a7d
  } else if (sawnan) {
Packit 7d6a7d
    numtype &= IS_NUMBER_NEG; /* Keep track of sign  */
Packit 7d6a7d
    numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
Packit 7d6a7d
  } else if (s < send) {
Packit 7d6a7d
    /* we can have an optional exponent part */
Packit 7d6a7d
    if (*s == 'e' || *s == 'E') {
Packit 7d6a7d
      /* The only flag we keep is sign.  Blow away any "it's UV"  */
Packit 7d6a7d
      numtype &= IS_NUMBER_NEG;
Packit 7d6a7d
      numtype |= IS_NUMBER_NOT_INT;
Packit 7d6a7d
      s++;
Packit 7d6a7d
      if (s < send && (*s == '-' || *s == '+'))
Packit 7d6a7d
        s++;
Packit 7d6a7d
      if (s < send && isDIGIT(*s)) {
Packit 7d6a7d
        do {
Packit 7d6a7d
          s++;
Packit 7d6a7d
        } while (s < send && isDIGIT(*s));
Packit 7d6a7d
      }
Packit 7d6a7d
      else
Packit 7d6a7d
      return 0;
Packit 7d6a7d
    }
Packit 7d6a7d
  }
Packit 7d6a7d
  while (s < send && isSPACE(*s))
Packit 7d6a7d
    s++;
Packit 7d6a7d
  if (s >= send)
Packit 7d6a7d
    return numtype;
Packit 7d6a7d
  if (len == 10 && memEQ(pv, "0 but true", 10)) {
Packit 7d6a7d
    if (valuep)
Packit 7d6a7d
      *valuep = 0;
Packit 7d6a7d
    return IS_NUMBER_IN_UV;
Packit 7d6a7d
  }
Packit 7d6a7d
  return 0;
Packit 7d6a7d
}
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
/*
Packit 7d6a7d
 * The grok_* routines have been modified to use warn() instead of
Packit 7d6a7d
 * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit,
Packit 7d6a7d
 * which is why the stack variable has been renamed to 'xdigit'.
Packit 7d6a7d
 */
Packit 7d6a7d
Packit 7d6a7d
#ifndef grok_bin
Packit 7d6a7d
#if { NEED grok_bin }
Packit 7d6a7d
UV
Packit 7d6a7d
grok_bin(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
Packit 7d6a7d
{
Packit 7d6a7d
    const char *s = start;
Packit 7d6a7d
    STRLEN len = *len_p;
Packit 7d6a7d
    UV value = 0;
Packit 7d6a7d
    NV value_nv = 0;
Packit 7d6a7d
Packit 7d6a7d
    const UV max_div_2 = UV_MAX / 2;
Packit 7d6a7d
    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
Packit 7d6a7d
    bool overflowed = FALSE;
Packit 7d6a7d
Packit 7d6a7d
    if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
Packit 7d6a7d
        /* strip off leading b or 0b.
Packit 7d6a7d
           for compatibility silently suffer "b" and "0b" as valid binary
Packit 7d6a7d
           numbers. */
Packit 7d6a7d
        if (len >= 1) {
Packit 7d6a7d
            if (s[0] == 'b') {
Packit 7d6a7d
                s++;
Packit 7d6a7d
                len--;
Packit 7d6a7d
            }
Packit 7d6a7d
            else if (len >= 2 && s[0] == '0' && s[1] == 'b') {
Packit 7d6a7d
                s+=2;
Packit 7d6a7d
                len-=2;
Packit 7d6a7d
            }
Packit 7d6a7d
        }
Packit 7d6a7d
    }
Packit 7d6a7d
Packit 7d6a7d
    for (; len-- && *s; s++) {
Packit 7d6a7d
        char bit = *s;
Packit 7d6a7d
        if (bit == '0' || bit == '1') {
Packit 7d6a7d
            /* Write it in this wonky order with a goto to attempt to get the
Packit 7d6a7d
               compiler to make the common case integer-only loop pretty tight.
Packit 7d6a7d
               With gcc seems to be much straighter code than old scan_bin.  */
Packit 7d6a7d
          redo:
Packit 7d6a7d
            if (!overflowed) {
Packit 7d6a7d
                if (value <= max_div_2) {
Packit 7d6a7d
                    value = (value << 1) | (bit - '0');
Packit 7d6a7d
                    continue;
Packit 7d6a7d
                }
Packit 7d6a7d
                /* Bah. We're just overflowed.  */
Packit 7d6a7d
                warn("Integer overflow in binary number");
Packit 7d6a7d
                overflowed = TRUE;
Packit 7d6a7d
                value_nv = (NV) value;
Packit 7d6a7d
            }
Packit 7d6a7d
            value_nv *= 2.0;
Packit 7d6a7d
            /* If an NV has not enough bits in its mantissa to
Packit 7d6a7d
             * represent a UV this summing of small low-order numbers
Packit 7d6a7d
             * is a waste of time (because the NV cannot preserve
Packit 7d6a7d
             * the low-order bits anyway): we could just remember when
Packit 7d6a7d
             * did we overflow and in the end just multiply value_nv by the
Packit 7d6a7d
             * right amount. */
Packit 7d6a7d
            value_nv += (NV)(bit - '0');
Packit 7d6a7d
            continue;
Packit 7d6a7d
        }
Packit 7d6a7d
        if (bit == '_' && len && allow_underscores && (bit = s[1])
Packit 7d6a7d
            && (bit == '0' || bit == '1'))
Packit 7d6a7d
            {
Packit 7d6a7d
                --len;
Packit 7d6a7d
                ++s;
Packit 7d6a7d
                goto redo;
Packit 7d6a7d
            }
Packit 7d6a7d
        if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
Packit 7d6a7d
            warn("Illegal binary digit '%c' ignored", *s);
Packit 7d6a7d
        break;
Packit 7d6a7d
    }
Packit 7d6a7d
Packit 7d6a7d
    if (   ( overflowed && value_nv > 4294967295.0)
Packit 7d6a7d
#if UVSIZE > 4
Packit 7d6a7d
        || (!overflowed && value > 0xffffffff  )
Packit 7d6a7d
#endif
Packit 7d6a7d
        ) {
Packit 7d6a7d
        warn("Binary number > 0b11111111111111111111111111111111 non-portable");
Packit 7d6a7d
    }
Packit 7d6a7d
    *len_p = s - start;
Packit 7d6a7d
    if (!overflowed) {
Packit 7d6a7d
        *flags = 0;
Packit 7d6a7d
        return value;
Packit 7d6a7d
    }
Packit 7d6a7d
    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
Packit 7d6a7d
    if (result)
Packit 7d6a7d
        *result = value_nv;
Packit 7d6a7d
    return UV_MAX;
Packit 7d6a7d
}
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
#ifndef grok_hex
Packit 7d6a7d
#if { NEED grok_hex }
Packit 7d6a7d
UV
Packit 7d6a7d
grok_hex(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
Packit 7d6a7d
{
Packit 7d6a7d
    const char *s = start;
Packit 7d6a7d
    STRLEN len = *len_p;
Packit 7d6a7d
    UV value = 0;
Packit 7d6a7d
    NV value_nv = 0;
Packit 7d6a7d
Packit 7d6a7d
    const UV max_div_16 = UV_MAX / 16;
Packit 7d6a7d
    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
Packit 7d6a7d
    bool overflowed = FALSE;
Packit 7d6a7d
    const char *xdigit;
Packit 7d6a7d
Packit 7d6a7d
    if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
Packit 7d6a7d
        /* strip off leading x or 0x.
Packit 7d6a7d
           for compatibility silently suffer "x" and "0x" as valid hex numbers.
Packit 7d6a7d
        */
Packit 7d6a7d
        if (len >= 1) {
Packit 7d6a7d
            if (s[0] == 'x') {
Packit 7d6a7d
                s++;
Packit 7d6a7d
                len--;
Packit 7d6a7d
            }
Packit 7d6a7d
            else if (len >= 2 && s[0] == '0' && s[1] == 'x') {
Packit 7d6a7d
                s+=2;
Packit 7d6a7d
                len-=2;
Packit 7d6a7d
            }
Packit 7d6a7d
        }
Packit 7d6a7d
    }
Packit 7d6a7d
Packit 7d6a7d
    for (; len-- && *s; s++) {
Packit 7d6a7d
        xdigit = strchr((char *) PL_hexdigit, *s);
Packit 7d6a7d
        if (xdigit) {
Packit 7d6a7d
            /* Write it in this wonky order with a goto to attempt to get the
Packit 7d6a7d
               compiler to make the common case integer-only loop pretty tight.
Packit 7d6a7d
               With gcc seems to be much straighter code than old scan_hex.  */
Packit 7d6a7d
          redo:
Packit 7d6a7d
            if (!overflowed) {
Packit 7d6a7d
                if (value <= max_div_16) {
Packit 7d6a7d
                    value = (value << 4) | ((xdigit - PL_hexdigit) & 15);
Packit 7d6a7d
                    continue;
Packit 7d6a7d
                }
Packit 7d6a7d
                warn("Integer overflow in hexadecimal number");
Packit 7d6a7d
                overflowed = TRUE;
Packit 7d6a7d
                value_nv = (NV) value;
Packit 7d6a7d
            }
Packit 7d6a7d
            value_nv *= 16.0;
Packit 7d6a7d
            /* If an NV has not enough bits in its mantissa to
Packit 7d6a7d
             * represent a UV this summing of small low-order numbers
Packit 7d6a7d
             * is a waste of time (because the NV cannot preserve
Packit 7d6a7d
             * the low-order bits anyway): we could just remember when
Packit 7d6a7d
             * did we overflow and in the end just multiply value_nv by the
Packit 7d6a7d
             * right amount of 16-tuples. */
Packit 7d6a7d
            value_nv += (NV)((xdigit - PL_hexdigit) & 15);
Packit 7d6a7d
            continue;
Packit 7d6a7d
        }
Packit 7d6a7d
        if (*s == '_' && len && allow_underscores && s[1]
Packit 7d6a7d
                && (xdigit = strchr((char *) PL_hexdigit, s[1])))
Packit 7d6a7d
            {
Packit 7d6a7d
                --len;
Packit 7d6a7d
                ++s;
Packit 7d6a7d
                goto redo;
Packit 7d6a7d
            }
Packit 7d6a7d
        if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
Packit 7d6a7d
            warn("Illegal hexadecimal digit '%c' ignored", *s);
Packit 7d6a7d
        break;
Packit 7d6a7d
    }
Packit 7d6a7d
Packit 7d6a7d
    if (   ( overflowed && value_nv > 4294967295.0)
Packit 7d6a7d
#if UVSIZE > 4
Packit 7d6a7d
        || (!overflowed && value > 0xffffffff  )
Packit 7d6a7d
#endif
Packit 7d6a7d
        ) {
Packit 7d6a7d
        warn("Hexadecimal number > 0xffffffff non-portable");
Packit 7d6a7d
    }
Packit 7d6a7d
    *len_p = s - start;
Packit 7d6a7d
    if (!overflowed) {
Packit 7d6a7d
        *flags = 0;
Packit 7d6a7d
        return value;
Packit 7d6a7d
    }
Packit 7d6a7d
    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
Packit 7d6a7d
    if (result)
Packit 7d6a7d
        *result = value_nv;
Packit 7d6a7d
    return UV_MAX;
Packit 7d6a7d
}
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
#ifndef grok_oct
Packit 7d6a7d
#if { NEED grok_oct }
Packit 7d6a7d
UV
Packit 7d6a7d
grok_oct(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
Packit 7d6a7d
{
Packit 7d6a7d
    const char *s = start;
Packit 7d6a7d
    STRLEN len = *len_p;
Packit 7d6a7d
    UV value = 0;
Packit 7d6a7d
    NV value_nv = 0;
Packit 7d6a7d
Packit 7d6a7d
    const UV max_div_8 = UV_MAX / 8;
Packit 7d6a7d
    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
Packit 7d6a7d
    bool overflowed = FALSE;
Packit 7d6a7d
Packit 7d6a7d
    for (; len-- && *s; s++) {
Packit 7d6a7d
         /* gcc 2.95 optimiser not smart enough to figure that this subtraction
Packit 7d6a7d
            out front allows slicker code.  */
Packit 7d6a7d
        int digit = *s - '0';
Packit 7d6a7d
        if (digit >= 0 && digit <= 7) {
Packit 7d6a7d
            /* Write it in this wonky order with a goto to attempt to get the
Packit 7d6a7d
               compiler to make the common case integer-only loop pretty tight.
Packit 7d6a7d
            */
Packit 7d6a7d
          redo:
Packit 7d6a7d
            if (!overflowed) {
Packit 7d6a7d
                if (value <= max_div_8) {
Packit 7d6a7d
                    value = (value << 3) | digit;
Packit 7d6a7d
                    continue;
Packit 7d6a7d
                }
Packit 7d6a7d
                /* Bah. We're just overflowed.  */
Packit 7d6a7d
                warn("Integer overflow in octal number");
Packit 7d6a7d
                overflowed = TRUE;
Packit 7d6a7d
                value_nv = (NV) value;
Packit 7d6a7d
            }
Packit 7d6a7d
            value_nv *= 8.0;
Packit 7d6a7d
            /* If an NV has not enough bits in its mantissa to
Packit 7d6a7d
             * represent a UV this summing of small low-order numbers
Packit 7d6a7d
             * is a waste of time (because the NV cannot preserve
Packit 7d6a7d
             * the low-order bits anyway): we could just remember when
Packit 7d6a7d
             * did we overflow and in the end just multiply value_nv by the
Packit 7d6a7d
             * right amount of 8-tuples. */
Packit 7d6a7d
            value_nv += (NV)digit;
Packit 7d6a7d
            continue;
Packit 7d6a7d
        }
Packit 7d6a7d
        if (digit == ('_' - '0') && len && allow_underscores
Packit 7d6a7d
            && (digit = s[1] - '0') && (digit >= 0 && digit <= 7))
Packit 7d6a7d
            {
Packit 7d6a7d
                --len;
Packit 7d6a7d
                ++s;
Packit 7d6a7d
                goto redo;
Packit 7d6a7d
            }
Packit 7d6a7d
        /* Allow \octal to work the DWIM way (that is, stop scanning
Packit 7d6a7d
         * as soon as non-octal characters are seen, complain only iff
Packit 7d6a7d
         * someone seems to want to use the digits eight and nine). */
Packit 7d6a7d
        if (digit == 8 || digit == 9) {
Packit 7d6a7d
            if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
Packit 7d6a7d
                warn("Illegal octal digit '%c' ignored", *s);
Packit 7d6a7d
        }
Packit 7d6a7d
        break;
Packit 7d6a7d
    }
Packit 7d6a7d
Packit 7d6a7d
    if (   ( overflowed && value_nv > 4294967295.0)
Packit 7d6a7d
#if UVSIZE > 4
Packit 7d6a7d
        || (!overflowed && value > 0xffffffff  )
Packit 7d6a7d
#endif
Packit 7d6a7d
        ) {
Packit 7d6a7d
        warn("Octal number > 037777777777 non-portable");
Packit 7d6a7d
    }
Packit 7d6a7d
    *len_p = s - start;
Packit 7d6a7d
    if (!overflowed) {
Packit 7d6a7d
        *flags = 0;
Packit 7d6a7d
        return value;
Packit 7d6a7d
    }
Packit 7d6a7d
    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
Packit 7d6a7d
    if (result)
Packit 7d6a7d
        *result = value_nv;
Packit 7d6a7d
    return UV_MAX;
Packit 7d6a7d
}
Packit 7d6a7d
#endif
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
=xsinit
Packit 7d6a7d
Packit 7d6a7d
#define NEED_grok_number
Packit 7d6a7d
#define NEED_grok_numeric_radix
Packit 7d6a7d
#define NEED_grok_bin
Packit 7d6a7d
#define NEED_grok_hex
Packit 7d6a7d
#define NEED_grok_oct
Packit 7d6a7d
Packit 7d6a7d
=xsubs
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
grok_number(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                const char *pv;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                if (!grok_number(pv, len, &RETVAL))
Packit 7d6a7d
                  XSRETURN_UNDEF;
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
grok_bin(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = grok_bin(pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
grok_hex(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = grok_hex(pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
grok_oct(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = grok_oct(pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
Perl_grok_number(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                const char *pv;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                if (!Perl_grok_number(aTHX_ pv, len, &RETVAL))
Packit 7d6a7d
                  XSRETURN_UNDEF;
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
Perl_grok_bin(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = Perl_grok_bin(aTHX_ pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
Perl_grok_hex(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = Perl_grok_hex(aTHX_ pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
UV
Packit 7d6a7d
Perl_grok_oct(string)
Packit 7d6a7d
        SV *string
Packit 7d6a7d
        PREINIT:
Packit 7d6a7d
                char *pv;
Packit 7d6a7d
                I32 flags = 0;
Packit 7d6a7d
                STRLEN len;
Packit 7d6a7d
        CODE:
Packit 7d6a7d
                pv = SvPV(string, len);
Packit 7d6a7d
                RETVAL = Perl_grok_oct(aTHX_ pv, &len, &flags, NULL);
Packit 7d6a7d
        OUTPUT:
Packit 7d6a7d
                RETVAL
Packit 7d6a7d
Packit 7d6a7d
=tests plan => 10
Packit 7d6a7d
Packit 7d6a7d
ok(&Devel::PPPort::grok_number("42"), 42);
Packit 7d6a7d
ok(!defined(&Devel::PPPort::grok_number("A")));
Packit 7d6a7d
ok(&Devel::PPPort::grok_bin("10000001"), 129);
Packit 7d6a7d
ok(&Devel::PPPort::grok_hex("deadbeef"), 0xdeadbeef);
Packit 7d6a7d
ok(&Devel::PPPort::grok_oct("377"), 255);
Packit 7d6a7d
Packit 7d6a7d
ok(&Devel::PPPort::Perl_grok_number("42"), 42);
Packit 7d6a7d
ok(!defined(&Devel::PPPort::Perl_grok_number("A")));
Packit 7d6a7d
ok(&Devel::PPPort::Perl_grok_bin("10000001"), 129);
Packit 7d6a7d
ok(&Devel::PPPort::Perl_grok_hex("deadbeef"), 0xdeadbeef);
Packit 7d6a7d
ok(&Devel::PPPort::Perl_grok_oct("377"), 255);