Back to index

php5  5.3.10
collator_is_numeric.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | This source file is subject to version 3.01 of the PHP license,      |
00006    | that is bundled with this package in the file LICENSE, and is        |
00007    | available through the world-wide-web at the following url:           |
00008    | http://www.php.net/license/3_01.txt                                  |
00009    | If you did not receive a copy of the PHP license and are unable to   |
00010    | obtain it through the world-wide-web, please send a note to          |
00011    | license@php.net so we can mail you a copy immediately.               |
00012    +----------------------------------------------------------------------+
00013    | Authors: Vadim Savchuk <vsavchuk@productengine.com>                  |
00014    |          Dmitry Lakhtyuk <dlakhtyuk@productengine.com>               |
00015    +----------------------------------------------------------------------+
00016  */
00017 
00018 #include "collator_is_numeric.h"
00019 
00020 #if ZEND_MODULE_API_NO < 20071006
00021 /* not 5.3 */
00022 #ifndef ALLOCA_FLAG
00023 #define ALLOCA_FLAG(use_heap)
00024 #endif
00025 #define _do_alloca(x, y) do_alloca((x))
00026 #define _free_alloca(x, y) free_alloca((x))
00027 #else
00028 #define _do_alloca do_alloca
00029 #define _free_alloca free_alloca
00030 #endif
00031 /* {{{ collator_u_strtod
00032  * Taken from PHP6:zend_u_strtod()
00033  */
00034 static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
00035 {
00036        const UChar *u = nptr, *nstart;
00037        UChar c = *u;
00038        int any = 0;
00039        ALLOCA_FLAG(use_heap);
00040 
00041        while (u_isspace(c)) {
00042               c = *++u;
00043        }
00044        nstart = u;
00045 
00046        if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
00047               c = *++u;
00048        }
00049 
00050        while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
00051               any = 1;
00052               c = *++u;
00053        }
00054 
00055        if (c == 0x2E /*'.'*/) {
00056               c = *++u;
00057               while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
00058                      any = 1;
00059                      c = *++u;
00060               }
00061        }
00062 
00063        if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
00064               const UChar *e = u;
00065               int any_exp = 0;
00066 
00067               c = *++u;
00068               if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
00069                      c = *++u;
00070               }
00071 
00072               while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
00073                      any_exp = 1;
00074                      c = *++u;
00075               }
00076 
00077               if (!any_exp) {
00078                      u = e;
00079               }
00080        }
00081 
00082        if (any) {
00083               char buf[64], *numbuf, *bufpos;
00084               int length = u - nstart;
00085               double value;
00086 
00087               if (length < sizeof(buf)) {
00088                      numbuf = buf;
00089               } else {
00090                      numbuf = (char *) _do_alloca(length + 1, use_heap);
00091               }
00092 
00093               bufpos = numbuf;
00094 
00095               while (nstart < u) {
00096                      *bufpos++ = (char) *nstart++;
00097               }
00098 
00099               *bufpos = '\0';
00100               value = zend_strtod(numbuf, NULL);
00101 
00102               if (numbuf != buf) {
00103                      _free_alloca(numbuf, use_heap);
00104               }
00105 
00106               if (endptr != NULL) {
00107                      *endptr = (UChar *)u;
00108               }
00109 
00110               return value;
00111        }
00112 
00113        if (endptr != NULL) {
00114               *endptr = (UChar *)nptr;
00115        }
00116 
00117        return 0;
00118 }
00119 /* }}} */
00120 
00121 /* {{{ collator_u_strtol
00122  * Taken from PHP6:zend_u_strtol()
00123  *
00124  * Convert a Unicode string to a long integer.
00125  *
00126  * Ignores `locale' stuff.
00127  */
00128 static long collator_u_strtol(nptr, endptr, base)
00129        const UChar *nptr;
00130        UChar **endptr;
00131        register int base;
00132 {
00133        register const UChar *s = nptr;
00134        register unsigned long acc;
00135        register UChar c;
00136        register unsigned long cutoff;
00137        register int neg = 0, any, cutlim;
00138 
00139        if (s == NULL) {
00140               errno = ERANGE;
00141               if (endptr != NULL) {
00142                      *endptr = NULL;
00143               }
00144               return 0;
00145        }
00146 
00147        /*
00148         * Skip white space and pick up leading +/- sign if any.
00149         * If base is 0, allow 0x for hex and 0 for octal, else
00150         * assume decimal; if base is already 16, allow 0x.
00151         */
00152        do {
00153               c = *s++;
00154        } while (u_isspace(c));
00155        if (c == 0x2D /*'-'*/) {
00156               neg = 1;
00157               c = *s++;
00158        } else if (c == 0x2B /*'+'*/)
00159               c = *s++;
00160        if ((base == 0 || base == 16) &&
00161            (c == 0x30 /*'0'*/)
00162                && (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
00163               c = s[1];
00164               s += 2;
00165               base = 16;
00166        }
00167        if (base == 0)
00168               base = (c == 0x30 /*'0'*/) ? 8 : 10;
00169 
00170        /*
00171         * Compute the cutoff value between legal numbers and illegal
00172         * numbers.  That is the largest legal value, divided by the
00173         * base.  An input number that is greater than this value, if
00174         * followed by a legal input character, is too big.  One that
00175         * is equal to this value may be valid or not; the limit
00176         * between valid and invalid numbers is then based on the last
00177         * digit.  For instance, if the range for longs is
00178         * [-2147483648..2147483647] and the input base is 10,
00179         * cutoff will be set to 214748364 and cutlim to either
00180         * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
00181         * a value > 214748364, or equal but the next digit is > 7 (or 8),
00182         * the number is too big, and we will return a range error.
00183         *
00184         * Set any if any `digits' consumed; make it negative to indicate
00185         * overflow.
00186         */
00187        cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
00188        cutlim = cutoff % (unsigned long)base;
00189        cutoff /= (unsigned long)base;
00190        for (acc = 0, any = 0;; c = *s++) {
00191               if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
00192                      c -= 0x30 /*'0'*/;
00193               else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
00194                      c -= 0x41 /*'A'*/ - 10;
00195               else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
00196                      c -= 0x61 /*'a'*/ - 10;
00197               else
00198                      break;
00199               if (c >= base)
00200                      break;
00201 
00202               if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
00203                      any = -1;
00204               else {
00205                      any = 1;
00206                      acc *= base;
00207                      acc += c;
00208               }
00209        }
00210        if (any < 0) {
00211               acc = neg ? LONG_MIN : LONG_MAX;
00212               errno = ERANGE;
00213        } else if (neg)
00214               acc = -acc;
00215        if (endptr != NULL)
00216               *endptr = (UChar *)(any ? s - 1 : nptr);
00217        return (acc);
00218 }
00219 /* }}} */
00220 
00221 
00222 /* {{{ collator_is_numeric]
00223  * Taken from PHP6:is_numeric_unicode()
00224  */
00225 zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors )
00226 {
00227        long local_lval;
00228        double local_dval;
00229        UChar *end_ptr_long, *end_ptr_double;
00230        int conv_base=10;
00231 
00232        if (!length) {
00233               return 0;
00234        }
00235 
00236        /* handle hex numbers */
00237        if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
00238               conv_base=16;
00239        }
00240 
00241        errno=0;
00242        local_lval = collator_u_strtol(str, &end_ptr_long, conv_base);
00243        if (errno != ERANGE) {
00244               if (end_ptr_long == str+length) { /* integer string */
00245                      if (lval) {
00246                             *lval = local_lval;
00247                      }
00248                      return IS_LONG;
00249               } else if (end_ptr_long == str && *end_ptr_long != '\0' && *str != '.' && *str != '-') { /* ignore partial string matches */
00250                      return 0;
00251               }
00252        } else {
00253               end_ptr_long = NULL;
00254        }
00255 
00256        if (conv_base == 16) { /* hex string, under UNIX strtod() messes it up */
00257               /* UTODO: keep compatibility with is_numeric_string() here? */
00258               return 0;
00259        }
00260 
00261        local_dval = collator_u_strtod(str, &end_ptr_double);
00262        if (local_dval == 0 && end_ptr_double == str) {
00263               end_ptr_double = NULL;
00264        } else {
00265               if (end_ptr_double == str+length) { /* floating point string */
00266                      if (!zend_finite(local_dval)) {
00267                             /* "inf","nan" and maybe other weird ones */
00268                             return 0;
00269                      }
00270 
00271                      if (dval) {
00272                             *dval = local_dval;
00273                      }
00274                      return IS_DOUBLE;
00275               }
00276        }
00277 
00278        if (!allow_errors) {
00279               return 0;
00280        }
00281        if (allow_errors == -1) {
00282               zend_error(E_NOTICE, "A non well formed numeric value encountered");
00283        }
00284 
00285        if (allow_errors) {
00286               if (end_ptr_double > end_ptr_long && dval) {
00287                      *dval = local_dval;
00288                      return IS_DOUBLE;
00289               } else if (end_ptr_long && lval) {
00290                      *lval = local_lval;
00291                      return IS_LONG;
00292               }
00293        }
00294        return 0;
00295 }
00296 /* }}} */
00297 
00298 /*
00299  * Local variables:
00300  * tab-width: 4
00301  * c-basic-offset: 4
00302  * End:
00303  * vim600: noet sw=4 ts=4 fdm=marker
00304  * vim<600: noet sw=4 ts=4
00305  */