From: Sascha Schumann Date: Thu, 20 Sep 2001 08:22:44 +0000 (+0000) Subject: Rework some string-to-number and vice-versa functions to work smarter X-Git-Tag: PRE_SUBST_Z_MACROS~42 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f45555e62f578854b5862e6a3b84c0a21a053850;p=php Rework some string-to-number and vice-versa functions to work smarter (e.g. without using functions that use slow locales, without allocating extra memory and with fewer integer/float operations) --- diff --git a/ext/standard/math.c b/ext/standard/math.c index 28ca255721..805a4e1e06 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -664,7 +664,7 @@ PHP_FUNCTION(rad2deg) */ PHPAPI long _php_math_basetolong(zval *arg, int base) { - long mult = 1, num = 0, digit; + long num = 0, digit, onum; int i; char c, *s; @@ -674,23 +674,25 @@ _php_math_basetolong(zval *arg, int base) { s = Z_STRVAL_P(arg); - for (i = Z_STRLEN_P(arg) - 1; i >= 0; i--, mult *= base) { - c = toupper(s[i]); - if (c >= '0' && c <= '9') { - digit = (c - '0'); - } else if (c >= 'A' && c <= 'Z') { - digit = (c - 'A' + 10); - } else { - continue; - } + for (i = Z_STRLEN_P(arg); i > 0; i--) { + c = *s++; + + digit = (c >= '0' && c <= '9') ? c - '0' + : (c >= 'A' && c <= 'Z') ? c - 'A' + 10 + : (c >= 'a' && c <= 'z') ? c - 'a' + 10 + : base; + if (digit >= base) { continue; } - if(!mult || digit > LONG_MAX/mult || num > LONG_MAX-mult*digit) { - php_error(E_WARNING, "base_to_long: number '%s' is too big to fit in long", s); - return LONG_MAX; - } - num += mult * digit; + + onum = num; + num = num * base + digit; + if (num > onum) + continue; + + php_error(E_WARNING, "base_to_long: number '%s' is too big to fit in long", s); + return LONG_MAX; } return num; @@ -764,8 +766,8 @@ PHPAPI char * _php_math_longtobase(zval *arg, int base) { static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - char *result, *ptr, *ret; - int len, digit; + char buf[(sizeof(unsigned long) << 3) + 1]; + char *ptr, *end; unsigned long value; if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) { @@ -774,25 +776,16 @@ _php_math_longtobase(zval *arg, int base) value = Z_LVAL_P(arg); - /* allocates space for the longest possible result with the lowest base */ - len = (sizeof(Z_LVAL_P(arg)) * 8) + 1; - result = emalloc((sizeof(Z_LVAL_P(arg)) * 8) + 1); - - ptr = result + len - 1; - *ptr-- = '\0'; + end = ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; do { - digit = value % base; - *ptr = digits[digit]; + *--ptr = digits[value % base]; value /= base; - } - while (ptr-- > result && value); - ptr++; - ret = estrdup(ptr); - efree(result); + } while (ptr > buf && value); - return ret; -} + return estrndup(ptr, end - ptr); +} /* }}} */ /* {{{ _php_math_zvaltobase */ @@ -805,49 +798,28 @@ PHPAPI char * _php_math_zvaltobase(zval *arg, int base) { static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - char *result, *ptr, *ret; - int len, digit; - unsigned long value; - double fvalue; - int f_mode; if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) { return empty_string; } - f_mode = (Z_TYPE_P(arg) == IS_DOUBLE); - - if(f_mode) { - fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */ - } else { - value = Z_LVAL_P(arg); - } + if (Z_TYPE_P(arg) == IS_DOUBLE) { + double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */ + char *ptr, *end; + char buf[(sizeof(double) << 3) + 1]; - /* allocates space for the longest possible result with the lowest base */ - len = (sizeof(Z_DVAL_P(arg)) * 8) + 1; - result = emalloc((sizeof(Z_DVAL_P(arg)) * 8) + 1); + end = ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; - ptr = result + len - 1; - *ptr-- = '\0'; + do { + *--ptr = digits[(int) fmod(fvalue, base)]; + fvalue /= base; + } while (ptr > buf && fabs(fvalue) >= 1); - do { - if(f_mode) { - double d = floor(fvalue/base); - digit = (int)ceil(fvalue - d*base); - *ptr = digits[digit]; - fvalue = d; - } else { - digit = value % base; - *ptr = digits[digit]; - value /= base; - } + return estrndup(ptr, end - ptr); } - while (ptr-- > result && (f_mode?(fabs(fvalue)>=1):value)); - ptr++; - ret = estrdup(ptr); - efree(result); - - return ret; + + return _php_math_longtobase(arg, base); } /* }}} */