Annotation of embedaddon/php/ext/intl/collator/collator_is_numeric.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | This source file is subject to version 3.01 of the PHP license, |
! 6: | that is bundled with this package in the file LICENSE, and is |
! 7: | available through the world-wide-web at the following url: |
! 8: | http://www.php.net/license/3_01.txt |
! 9: | If you did not receive a copy of the PHP license and are unable to |
! 10: | obtain it through the world-wide-web, please send a note to |
! 11: | license@php.net so we can mail you a copy immediately. |
! 12: +----------------------------------------------------------------------+
! 13: | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
! 14: | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
! 15: +----------------------------------------------------------------------+
! 16: */
! 17:
! 18: #include "collator_is_numeric.h"
! 19:
! 20: #if ZEND_MODULE_API_NO < 20071006
! 21: /* not 5.3 */
! 22: #ifndef ALLOCA_FLAG
! 23: #define ALLOCA_FLAG(use_heap)
! 24: #endif
! 25: #define _do_alloca(x, y) do_alloca((x))
! 26: #define _free_alloca(x, y) free_alloca((x))
! 27: #else
! 28: #define _do_alloca do_alloca
! 29: #define _free_alloca free_alloca
! 30: #endif
! 31: /* {{{ collator_u_strtod
! 32: * Taken from PHP6:zend_u_strtod()
! 33: */
! 34: static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
! 35: {
! 36: const UChar *u = nptr, *nstart;
! 37: UChar c = *u;
! 38: int any = 0;
! 39: ALLOCA_FLAG(use_heap);
! 40:
! 41: while (u_isspace(c)) {
! 42: c = *++u;
! 43: }
! 44: nstart = u;
! 45:
! 46: if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
! 47: c = *++u;
! 48: }
! 49:
! 50: while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
! 51: any = 1;
! 52: c = *++u;
! 53: }
! 54:
! 55: if (c == 0x2E /*'.'*/) {
! 56: c = *++u;
! 57: while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
! 58: any = 1;
! 59: c = *++u;
! 60: }
! 61: }
! 62:
! 63: if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
! 64: const UChar *e = u;
! 65: int any_exp = 0;
! 66:
! 67: c = *++u;
! 68: if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
! 69: c = *++u;
! 70: }
! 71:
! 72: while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
! 73: any_exp = 1;
! 74: c = *++u;
! 75: }
! 76:
! 77: if (!any_exp) {
! 78: u = e;
! 79: }
! 80: }
! 81:
! 82: if (any) {
! 83: char buf[64], *numbuf, *bufpos;
! 84: int length = u - nstart;
! 85: double value;
! 86:
! 87: if (length < sizeof(buf)) {
! 88: numbuf = buf;
! 89: } else {
! 90: numbuf = (char *) _do_alloca(length + 1, use_heap);
! 91: }
! 92:
! 93: bufpos = numbuf;
! 94:
! 95: while (nstart < u) {
! 96: *bufpos++ = (char) *nstart++;
! 97: }
! 98:
! 99: *bufpos = '\0';
! 100: value = zend_strtod(numbuf, NULL);
! 101:
! 102: if (numbuf != buf) {
! 103: _free_alloca(numbuf, use_heap);
! 104: }
! 105:
! 106: if (endptr != NULL) {
! 107: *endptr = (UChar *)u;
! 108: }
! 109:
! 110: return value;
! 111: }
! 112:
! 113: if (endptr != NULL) {
! 114: *endptr = (UChar *)nptr;
! 115: }
! 116:
! 117: return 0;
! 118: }
! 119: /* }}} */
! 120:
! 121: /* {{{ collator_u_strtol
! 122: * Taken from PHP6:zend_u_strtol()
! 123: *
! 124: * Convert a Unicode string to a long integer.
! 125: *
! 126: * Ignores `locale' stuff.
! 127: */
! 128: static long collator_u_strtol(nptr, endptr, base)
! 129: const UChar *nptr;
! 130: UChar **endptr;
! 131: register int base;
! 132: {
! 133: register const UChar *s = nptr;
! 134: register unsigned long acc;
! 135: register UChar c;
! 136: register unsigned long cutoff;
! 137: register int neg = 0, any, cutlim;
! 138:
! 139: if (s == NULL) {
! 140: errno = ERANGE;
! 141: if (endptr != NULL) {
! 142: *endptr = NULL;
! 143: }
! 144: return 0;
! 145: }
! 146:
! 147: /*
! 148: * Skip white space and pick up leading +/- sign if any.
! 149: * If base is 0, allow 0x for hex and 0 for octal, else
! 150: * assume decimal; if base is already 16, allow 0x.
! 151: */
! 152: do {
! 153: c = *s++;
! 154: } while (u_isspace(c));
! 155: if (c == 0x2D /*'-'*/) {
! 156: neg = 1;
! 157: c = *s++;
! 158: } else if (c == 0x2B /*'+'*/)
! 159: c = *s++;
! 160: if ((base == 0 || base == 16) &&
! 161: (c == 0x30 /*'0'*/)
! 162: && (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
! 163: c = s[1];
! 164: s += 2;
! 165: base = 16;
! 166: }
! 167: if (base == 0)
! 168: base = (c == 0x30 /*'0'*/) ? 8 : 10;
! 169:
! 170: /*
! 171: * Compute the cutoff value between legal numbers and illegal
! 172: * numbers. That is the largest legal value, divided by the
! 173: * base. An input number that is greater than this value, if
! 174: * followed by a legal input character, is too big. One that
! 175: * is equal to this value may be valid or not; the limit
! 176: * between valid and invalid numbers is then based on the last
! 177: * digit. For instance, if the range for longs is
! 178: * [-2147483648..2147483647] and the input base is 10,
! 179: * cutoff will be set to 214748364 and cutlim to either
! 180: * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
! 181: * a value > 214748364, or equal but the next digit is > 7 (or 8),
! 182: * the number is too big, and we will return a range error.
! 183: *
! 184: * Set any if any `digits' consumed; make it negative to indicate
! 185: * overflow.
! 186: */
! 187: cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
! 188: cutlim = cutoff % (unsigned long)base;
! 189: cutoff /= (unsigned long)base;
! 190: for (acc = 0, any = 0;; c = *s++) {
! 191: if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
! 192: c -= 0x30 /*'0'*/;
! 193: else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
! 194: c -= 0x41 /*'A'*/ - 10;
! 195: else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
! 196: c -= 0x61 /*'a'*/ - 10;
! 197: else
! 198: break;
! 199: if (c >= base)
! 200: break;
! 201:
! 202: if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
! 203: any = -1;
! 204: else {
! 205: any = 1;
! 206: acc *= base;
! 207: acc += c;
! 208: }
! 209: }
! 210: if (any < 0) {
! 211: acc = neg ? LONG_MIN : LONG_MAX;
! 212: errno = ERANGE;
! 213: } else if (neg)
! 214: acc = -acc;
! 215: if (endptr != NULL)
! 216: *endptr = (UChar *)(any ? s - 1 : nptr);
! 217: return (acc);
! 218: }
! 219: /* }}} */
! 220:
! 221:
! 222: /* {{{ collator_is_numeric]
! 223: * Taken from PHP6:is_numeric_unicode()
! 224: */
! 225: zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors )
! 226: {
! 227: long local_lval;
! 228: double local_dval;
! 229: UChar *end_ptr_long, *end_ptr_double;
! 230: int conv_base=10;
! 231:
! 232: if (!length) {
! 233: return 0;
! 234: }
! 235:
! 236: /* handle hex numbers */
! 237: if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
! 238: conv_base=16;
! 239: }
! 240:
! 241: errno=0;
! 242: local_lval = collator_u_strtol(str, &end_ptr_long, conv_base);
! 243: if (errno != ERANGE) {
! 244: if (end_ptr_long == str+length) { /* integer string */
! 245: if (lval) {
! 246: *lval = local_lval;
! 247: }
! 248: return IS_LONG;
! 249: } else if (end_ptr_long == str && *end_ptr_long != '\0' && *str != '.' && *str != '-') { /* ignore partial string matches */
! 250: return 0;
! 251: }
! 252: } else {
! 253: end_ptr_long = NULL;
! 254: }
! 255:
! 256: if (conv_base == 16) { /* hex string, under UNIX strtod() messes it up */
! 257: /* UTODO: keep compatibility with is_numeric_string() here? */
! 258: return 0;
! 259: }
! 260:
! 261: local_dval = collator_u_strtod(str, &end_ptr_double);
! 262: if (local_dval == 0 && end_ptr_double == str) {
! 263: end_ptr_double = NULL;
! 264: } else {
! 265: if (end_ptr_double == str+length) { /* floating point string */
! 266: if (!zend_finite(local_dval)) {
! 267: /* "inf","nan" and maybe other weird ones */
! 268: return 0;
! 269: }
! 270:
! 271: if (dval) {
! 272: *dval = local_dval;
! 273: }
! 274: return IS_DOUBLE;
! 275: }
! 276: }
! 277:
! 278: if (!allow_errors) {
! 279: return 0;
! 280: }
! 281: if (allow_errors == -1) {
! 282: zend_error(E_NOTICE, "A non well formed numeric value encountered");
! 283: }
! 284:
! 285: if (allow_errors) {
! 286: if (end_ptr_double > end_ptr_long && dval) {
! 287: *dval = local_dval;
! 288: return IS_DOUBLE;
! 289: } else if (end_ptr_long && lval) {
! 290: *lval = local_lval;
! 291: return IS_LONG;
! 292: }
! 293: }
! 294: return 0;
! 295: }
! 296: /* }}} */
! 297:
! 298: /*
! 299: * Local variables:
! 300: * tab-width: 4
! 301: * c-basic-offset: 4
! 302: * End:
! 303: * vim600: noet sw=4 ts=4 fdm=marker
! 304: * vim<600: noet sw=4 ts=4
! 305: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>