diff --git a/config.m4 b/config.m4 index 0c999ea..278553a 100644 --- a/config.m4 +++ b/config.m4 @@ -242,7 +242,7 @@ if test "$PHP_MEMCACHED" != "no"; then PHP_SUBST(MEMCACHED_SHARED_LIBADD) - PHP_MEMCACHED_FILES="php_memcached.c fastlz/fastlz.c" + PHP_MEMCACHED_FILES="php_memcached.c fastlz/fastlz.c g_fmt.c" if test "$PHP_MEMCACHED_SESSION" != "no"; then PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} php_memcached_session.c" diff --git a/g_fmt.c b/g_fmt.c new file mode 100644 index 0000000..c904e65 --- /dev/null +++ b/g_fmt.c @@ -0,0 +1,99 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 1996 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; + * it suffices to declare buf + * char buf[32]; + */ + +/* Modified for use with php in the memcached client extension. + * + * // Teddy Grenman , 2010-05-18. + */ + +#include + +char *php_memcached_g_fmt(register char *b, double x) { + register int i, k; + register char *s; + int decpt, j, sign; + char *b0, *s0, *se; + + b0 = b; +#ifdef IGNORE_ZERO_SIGN + if (!x) { + *b++ = '0'; + *b = 0; + goto done; + } +#endif + + s = s0 = zend_dtoa(x, 0, 0, &decpt, &sign, &se); + if (sign) + *b++ = '-'; + if (decpt == 9999) /* Infinity or Nan */ { + while(*b++ = *s++); + goto done0; + } + if (decpt <= -4 || decpt > se - s + 5) { + *b++ = *s++; + if (*s) { + *b++ = '.'; + while(*b = *s++) + b++; + } + *b++ = 'e'; + /* sprintf(b, "%+.2d", decpt - 1); */ + if (--decpt < 0) { + *b++ = '-'; + decpt = -decpt; + } + else + *b++ = '+'; + for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); + for(;;) { + i = decpt / k; + *b++ = i + '0'; + if (--j <= 0) + break; + decpt -= i*k; + decpt *= 10; + } + *b = 0; + } else if (decpt <= 0) { + *b++ = '.'; + for(; decpt < 0; decpt++) + *b++ = '0'; + while(*b++ = *s++); + } else { + while(*b = *s++) { + b++; + if (--decpt == 0 && *s) + *b++ = '.'; + } + for(; decpt > 0; decpt--) + *b++ = '0'; + *b = 0; + } + + done0: + zend_freedtoa(s0); + done: + return b0; +} diff --git a/g_fmt.h b/g_fmt.h new file mode 100644 index 0000000..75ad8ce --- /dev/null +++ b/g_fmt.h @@ -0,0 +1,34 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 1996 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; + * it suffices to declare buf + * char buf[32]; + */ + +/* Modified for use with php in the memcached client + * extension by Teddy Grenman, 2010. + */ + +#ifndef MEMC_G_FMT_H +#define MEMC_G_FMT_H + +char *php_memcached_g_fmt(register char *b, double x); + +#endif diff --git a/php_memcached.c b/php_memcached.c index 60064af..1bdba72 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -42,9 +42,11 @@ #include #include #include +#include #include #include "php_memcached.h" +#include "g_fmt.h" #ifdef HAVE_MEMCACHED_SESSION # include "php_memcached_session.h" @@ -2480,28 +2482,29 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t break; case IS_LONG: + smart_str_append_long(&buf, Z_LVAL_P(value)); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); + break; + case IS_DOUBLE: - case IS_BOOL: { - zval value_copy; + char dstr[40] = {0}; - value_copy = *value; - zval_copy_ctor(&value_copy); - convert_to_string(&value_copy); - smart_str_appendl(&buf, Z_STRVAL(value_copy), Z_STRLEN(value_copy)); - zval_dtor(&value_copy); - - *flags &= ~MEMC_VAL_COMPRESSED; - if (Z_TYPE_P(value) == IS_LONG) { - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); - } else if (Z_TYPE_P(value) == IS_DOUBLE) { - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); - } else if (Z_TYPE_P(value) == IS_BOOL) { - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); - } + php_memcached_g_fmt(dstr, Z_DVAL_P(value)); + smart_str_appends(&buf, dstr); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); break; } + case IS_BOOL: + if (Z_BVAL_P(value)) { + smart_str_appendc(&buf, '1'); + } else { + smart_str_appendl(&buf, "", 0); + } + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); + break; + default: switch (serializer) { #ifdef HAVE_MEMCACHED_IGBINARY @@ -2690,11 +2693,16 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload } case MEMC_VAL_IS_DOUBLE: - { - double dval = zend_strtod(payload, NULL); - ZVAL_DOUBLE(value, dval); + if (payload_len == 8 && memcmp(payload, "Infinity", 8) == 0) { + ZVAL_DOUBLE(value, php_get_inf()); + } else if (payload_len == 9 && memcmp(payload, "-Infinity", 9) == 0) { + ZVAL_DOUBLE(value, -php_get_inf()); + } else if (payload_len == 3 && memcmp(payload, "NaN", 3) == 0) { + ZVAL_DOUBLE(value, php_get_nan()); + } else { + ZVAL_DOUBLE(value, zend_strtod(payload, NULL)); + } break; - } case MEMC_VAL_IS_BOOL: ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1');