Annotation of embedaddon/php/ext/intl/collator/collator_is_numeric.c, revision 1.1.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>