Re: pragma/locale.t #107
Hugo van der Sanden [Sun, 10 Jun 2001 11:23:30 +0000 (12:23 +0100)]
Message-Id: <200106101023.LAA32085@crypt.compulink.co.uk>

Encapsulate the scan of the decimal radix separator.

p4raw-id: //depot/perl@10495

embed.h
embed.pl
proto.h
sv.c

diff --git a/embed.h b/embed.h
index 36f2728..80500da 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define gv_share               S_gv_share
 #  endif
 #define grok_number            S_grok_number
+#define grok_numeric_radix     S_grok_numeric_radix
 #endif
 #if defined(PERL_IN_TOKE_C) || defined(PERL_DECL_PROT)
 #define check_uni              S_check_uni
 #define gv_share(a)            S_gv_share(aTHX_ a)
 #  endif
 #define grok_number(a,b,c)     S_grok_number(aTHX_ a,b,c)
+#define grok_numeric_radix(a,b)        S_grok_numeric_radix(aTHX_ a,b)
 #endif
 #if defined(PERL_IN_TOKE_C) || defined(PERL_DECL_PROT)
 #define check_uni()            S_check_uni(aTHX)
 #  endif
 #define S_grok_number          CPerlObj::S_grok_number
 #define grok_number            S_grok_number
+#define S_grok_numeric_radix   CPerlObj::S_grok_numeric_radix
+#define grok_numeric_radix     S_grok_numeric_radix
 #endif
 #if defined(PERL_IN_TOKE_C) || defined(PERL_DECL_PROT)
 #define S_check_uni            CPerlObj::S_check_uni
index 67e142a..5557eab 100755 (executable)
--- a/embed.pl
+++ b/embed.pl
@@ -2522,6 +2522,7 @@ s |I32    |expect_number  |char** pattern
 s      |SV*    |gv_share       |SV *sv
 #  endif
 s      |int    |grok_number    |const char *pv|STRLEN len|UV *valuep
+s      |bool   |grok_numeric_radix|const char **sp|const char *send
 #endif
 
 #if defined(PERL_IN_TOKE_C) || defined(PERL_DECL_PROT)
diff --git a/proto.h b/proto.h
index 5005708..f4706ed 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -1246,6 +1246,7 @@ STATIC I32        S_expect_number(pTHX_ char** pattern);
 STATIC SV*     S_gv_share(pTHX_ SV *sv);
 #  endif
 STATIC int     S_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep);
+STATIC int     S_grok_numeric_radix(pTHX_ const char **sp, const char *send);
 #endif
 
 #if defined(PERL_IN_TOKE_C) || defined(PERL_DECL_PROT)
diff --git a/sv.c b/sv.c
index 2a843e6..4b86aab 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1494,6 +1494,30 @@ S_not_a_number(pTHX_ SV *sv)
 #define IS_NUMBER_NEG                0x08 /* leading minus sign */
 #define IS_NUMBER_INFINITY           0x10 /* this is big */
 
+static bool
+S_grok_numeric_radix(pTHX_ const char **sp, const char *send)
+{
+#ifdef USE_LOCALE_NUMERIC
+    if (PL_numeric_radix_sv && IN_LOCALE) { 
+        STRLEN len;
+        char* radix = SvPV(PL_numeric_radix_sv, len);
+        if (*sp + len <= send && memEQ(*sp, radix, len)) {
+            *sp += len;
+            return TRUE; 
+        }
+    }
+    /* always try "." if numeric radix didn't match because
+     * we may have data from different locales mixed */
+#endif
+    if (*sp < send && **sp == '.') {
+        ++*sp;
+        return TRUE;
+    }
+    return FALSE;
+}
+
+#define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send)
+
 static int
 S_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
 {
@@ -1503,9 +1527,6 @@ S_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
     const char max_mod_10 = UV_MAX % 10 + '0';
     int numtype = 0;
     int sawinf = 0;
-    char* radix = ".";
-    STRLEN radixlen = 1;
-    bool radixfound;
 
     while (isSPACE(*s))
        s++;
@@ -1516,11 +1537,6 @@ S_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
     else if (*s == '+')
        s++;
 
-#ifdef USE_LOCALE_NUMERIC
-    if (PL_numeric_radix_sv && IN_LOCALE)
-        radix = SvPV(PL_numeric_radix_sv, radixlen);
-#endif
-
     /* next must be digit or the radix separator or beginning of infinity */
     if (isDIGIT(*s)) {
        /* UVs are at least 32 bits, so the first 9 decimal digits cannot
@@ -1589,64 +1605,42 @@ S_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
            *valuep = value;
 
       skip_value:
-       if (s + radixlen <= send && memEQ(s, radix, radixlen))
-           radixfound = TRUE;
-#ifdef USE_LOCALE_NUMERIC
-       /* if we did change the radix and the radix is not the "."
-        * retry with the "." (in case of mixed data) */
-       else if (IN_LOCALE && !(*radix == '.' && radixlen == 1) && *s == '.') {
-           radixlen = 1;
-           radixfound = TRUE;
-       }
-#endif
-       if (radixfound) {
-           s += radixlen;
+       if (GROK_NUMERIC_RADIX(&s, send)) {
            numtype |= IS_NUMBER_NOT_INT;
            while (isDIGIT(*s))  /* optional digits after the radix */
                s++;
        }
     }
-    else {
-        if (s + radixlen <= send && memEQ(s, radix, radixlen))
-           radixfound = TRUE;
-#ifdef USE_LOCALE_NUMERIC
-       else if (IN_LOCALE && !(*radix == '.' && radixlen == 1) && *s == '.') {
-           radixlen = 1;
-           radixfound = TRUE;
+    else if (GROK_NUMERIC_RADIX(&s, send)) {
+        numtype |= IS_NUMBER_NOT_INT;
+       /* no digits before the radix means we need digits after it */
+       if (isDIGIT(*s)) {
+           do {
+               s++;
+           } while (isDIGIT(*s));
+           numtype |= IS_NUMBER_IN_UV;
+           if (valuep) {
+               /* integer approximation is valid - it's 0.  */
+               *valuep = 0;
+           }
        }
-#endif
-       if (radixfound) {
-         s += radixlen;
-         numtype |= IS_NUMBER_NOT_INT;
-         /* no digits before the radix means we need digits after it */
-         if (isDIGIT(*s)) {
-             do {
-                 s++;
-             } while (isDIGIT(*s));
-             numtype |= IS_NUMBER_IN_UV;
-             if (valuep) {
-                 /* integer approximation is valid - it's 0.  */
-               *valuep = 0;
-             }
-         }
-         else
+       else
            return 0;
-       }
-       else if (*s == 'I' || *s == 'i') {
+    }
+    else if (*s == 'I' || *s == 'i') {
+        s++; if (*s != 'N' && *s != 'n') return 0;
+       s++; if (*s != 'F' && *s != 'f') return 0;
+       s++; if (*s == 'I' || *s == 'i') {
            s++; if (*s != 'N' && *s != 'n') return 0;
-           s++; if (*s != 'F' && *s != 'f') return 0;
-           s++; if (*s == 'I' || *s == 'i') {
-               s++; if (*s != 'N' && *s != 'n') return 0;
-               s++; if (*s != 'I' && *s != 'i') return 0;
-               s++; if (*s != 'T' && *s != 't') return 0;
-               s++; if (*s != 'Y' && *s != 'y') return 0;
-               s++;
-           }
-           sawinf = 1;
+           s++; if (*s != 'I' && *s != 'i') return 0;
+           s++; if (*s != 'T' && *s != 't') return 0;
+           s++; if (*s != 'Y' && *s != 'y') return 0;
+           s++;
        }
-       else /* Add test for NaN here.  */
-           return 0;
+       sawinf = 1;
     }
+    else /* Add test for NaN here.  */
+        return 0;
 
     if (sawinf) {
        numtype &= IS_NUMBER_NEG; /* Keep track of sign  */