xref: /PHP-5.5/Zend/zend_operators.c (revision 41fc3c76)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    +----------------------------------------------------------------------+
18 */
19 
20 /* $Id$ */
21 
22 #include <ctype.h>
23 
24 #include "zend.h"
25 #include "zend_operators.h"
26 #include "zend_variables.h"
27 #include "zend_globals.h"
28 #include "zend_list.h"
29 #include "zend_API.h"
30 #include "zend_strtod.h"
31 #include "zend_exceptions.h"
32 #include "zend_closures.h"
33 
34 #if ZEND_USE_TOLOWER_L
35 #include <locale.h>
36 static _locale_t current_locale = NULL;
37 /* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
38 #define zend_tolower(c) _tolower_l(c, current_locale)
39 #else
40 #define zend_tolower(c) tolower(c)
41 #endif
42 
43 #define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
44 
45 static const unsigned char tolower_map[256] = {
46 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
47 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
48 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
49 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
50 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
51 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
52 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
53 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
54 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
55 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
56 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
57 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
58 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
59 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
60 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
61 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
62 };
63 
64 #define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
65 
66 /**
67  * Functions using locale lowercase:
68  	 	zend_binary_strncasecmp_l
69  	 	zend_binary_strcasecmp_l
70 		zend_binary_zval_strcasecmp
71 		zend_binary_zval_strncasecmp
72 		string_compare_function_ex
73 		string_case_compare_function
74  * Functions using ascii lowercase:
75   		zend_str_tolower_copy
76 		zend_str_tolower_dup
77 		zend_str_tolower
78 		zend_binary_strcasecmp
79 		zend_binary_strncasecmp
80  */
81 
zend_atoi(const char * str,int str_len)82 ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */
83 {
84 	int retval;
85 
86 	if (!str_len) {
87 		str_len = strlen(str);
88 	}
89 	retval = strtol(str, NULL, 0);
90 	if (str_len>0) {
91 		switch (str[str_len-1]) {
92 			case 'g':
93 			case 'G':
94 				retval *= 1024;
95 				/* break intentionally missing */
96 			case 'm':
97 			case 'M':
98 				retval *= 1024;
99 				/* break intentionally missing */
100 			case 'k':
101 			case 'K':
102 				retval *= 1024;
103 				break;
104 		}
105 	}
106 	return retval;
107 }
108 /* }}} */
109 
zend_atol(const char * str,int str_len)110 ZEND_API long zend_atol(const char *str, int str_len) /* {{{ */
111 {
112 	long retval;
113 
114 	if (!str_len) {
115 		str_len = strlen(str);
116 	}
117 	retval = strtol(str, NULL, 0);
118 	if (str_len>0) {
119 		switch (str[str_len-1]) {
120 			case 'g':
121 			case 'G':
122 				retval *= 1024;
123 				/* break intentionally missing */
124 			case 'm':
125 			case 'M':
126 				retval *= 1024;
127 				/* break intentionally missing */
128 			case 'k':
129 			case 'K':
130 				retval *= 1024;
131 				break;
132 		}
133 	}
134 	return retval;
135 }
136 /* }}} */
137 
zend_string_to_double(const char * number,zend_uint length)138 ZEND_API double zend_string_to_double(const char *number, zend_uint length) /* {{{ */
139 {
140 	double divisor = 10.0;
141 	double result = 0.0;
142 	double exponent;
143 	const char *end = number+length;
144 	const char *digit = number;
145 
146 	if (!length) {
147 		return result;
148 	}
149 
150 	while (digit < end) {
151 		if ((*digit <= '9' && *digit >= '0')) {
152 			result *= 10;
153 			result += *digit - '0';
154 		} else if (*digit == '.') {
155 			digit++;
156 			break;
157 		} else if (toupper(*digit) == 'E') {
158 			exponent = (double) atoi(digit+1);
159 			result *= pow(10.0, exponent);
160 			return result;
161 		} else {
162 			return result;
163 		}
164 		digit++;
165 	}
166 
167 	while (digit < end) {
168 		if ((*digit <= '9' && *digit >= '0')) {
169 			result += (*digit - '0') / divisor;
170 			divisor *= 10;
171 		} else if (toupper(*digit) == 'E') {
172 			exponent = (double) atoi(digit+1);
173 			result *= pow(10.0, exponent);
174 			return result;
175 		} else {
176 			return result;
177 		}
178 		digit++;
179 	}
180 	return result;
181 }
182 /* }}} */
183 
convert_scalar_to_number(zval * op TSRMLS_DC)184 ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC) /* {{{ */
185 {
186 	switch (Z_TYPE_P(op)) {
187 		case IS_STRING:
188 			{
189 				char *strval;
190 
191 				strval = Z_STRVAL_P(op);
192 				if ((Z_TYPE_P(op)=is_numeric_string(strval, Z_STRLEN_P(op), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
193 					ZVAL_LONG(op, 0);
194 				}
195 				STR_FREE(strval);
196 				break;
197 			}
198 		case IS_BOOL:
199 			Z_TYPE_P(op) = IS_LONG;
200 			break;
201 		case IS_RESOURCE:
202 			zend_list_delete(Z_LVAL_P(op));
203 			Z_TYPE_P(op) = IS_LONG;
204 			break;
205 		case IS_OBJECT:
206 			convert_to_long_base(op, 10);
207 			break;
208 		case IS_NULL:
209 			ZVAL_LONG(op, 0);
210 			break;
211 	}
212 }
213 /* }}} */
214 
215 /* {{{ zendi_convert_scalar_to_number */
216 #define zendi_convert_scalar_to_number(op, holder, result)			\
217 	if (op==result) {												\
218 		if (Z_TYPE_P(op) != IS_LONG) {								\
219 			convert_scalar_to_number(op TSRMLS_CC);					\
220 		}															\
221 	} else {														\
222 		switch (Z_TYPE_P(op)) {										\
223 			case IS_STRING:											\
224 				{													\
225 					if ((Z_TYPE(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) {	\
226 						ZVAL_LONG(&(holder), 0);							\
227 					}														\
228 					(op) = &(holder);										\
229 					break;													\
230 				}															\
231 			case IS_BOOL:													\
232 			case IS_RESOURCE:												\
233 				ZVAL_LONG(&(holder), Z_LVAL_P(op));							\
234 				(op) = &(holder);											\
235 				break;														\
236 			case IS_NULL:													\
237 				ZVAL_LONG(&(holder), 0);									\
238 				(op) = &(holder);											\
239 				break;														\
240 			case IS_OBJECT:													\
241 				(holder) = (*(op));											\
242 				zval_copy_ctor(&(holder));									\
243 				convert_to_long_base(&(holder), 10);						\
244 				if (Z_TYPE(holder) == IS_LONG) {							\
245 					(op) = &(holder);										\
246 				}															\
247 				break;														\
248 		}																	\
249 	}
250 
251 /* }}} */
252 
253 /* {{{ zendi_convert_to_long */
254 #define zendi_convert_to_long(op, holder, result)					\
255 	if (op == result) {												\
256 		convert_to_long(op);										\
257 	} else if (Z_TYPE_P(op) != IS_LONG) {							\
258 		switch (Z_TYPE_P(op)) {										\
259 			case IS_NULL:											\
260 				Z_LVAL(holder) = 0;									\
261 				break;												\
262 			case IS_DOUBLE:											\
263 				Z_LVAL(holder) = zend_dval_to_lval(Z_DVAL_P(op));	\
264 				break;												\
265 			case IS_STRING:											\
266 				Z_LVAL(holder) = strtol(Z_STRVAL_P(op), NULL, 10);	\
267 				break;												\
268 			case IS_ARRAY:											\
269 				Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);	\
270 				break;												\
271 			case IS_OBJECT:											\
272 				(holder) = (*(op));									\
273 				zval_copy_ctor(&(holder));							\
274 				convert_to_long_base(&(holder), 10);				\
275 				break;												\
276 			case IS_BOOL:											\
277 			case IS_RESOURCE:										\
278 				Z_LVAL(holder) = Z_LVAL_P(op);						\
279 				break;												\
280 			default:												\
281 				zend_error(E_WARNING, "Cannot convert to ordinal value");	\
282 				Z_LVAL(holder) = 0;									\
283 				break;												\
284 		}															\
285 		Z_TYPE(holder) = IS_LONG;									\
286 		(op) = &(holder);											\
287 	}
288 
289 /* }}} */
290 
291 /* {{{ zendi_convert_to_boolean */
292 #define zendi_convert_to_boolean(op, holder, result)				\
293 	if (op==result) {												\
294 		convert_to_boolean(op);										\
295 	} else if (Z_TYPE_P(op) != IS_BOOL) {							\
296 		switch (Z_TYPE_P(op)) {										\
297 			case IS_NULL:											\
298 				Z_LVAL(holder) = 0;									\
299 				break;												\
300 			case IS_RESOURCE:										\
301 			case IS_LONG:											\
302 				Z_LVAL(holder) = (Z_LVAL_P(op) ? 1 : 0);			\
303 				break;												\
304 			case IS_DOUBLE:											\
305 				Z_LVAL(holder) = (Z_DVAL_P(op) ? 1 : 0);			\
306 				break;												\
307 			case IS_STRING:											\
308 				if (Z_STRLEN_P(op) == 0								\
309 					|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {	\
310 					Z_LVAL(holder) = 0;								\
311 				} else {											\
312 					Z_LVAL(holder) = 1;								\
313 				}													\
314 				break;												\
315 			case IS_ARRAY:											\
316 				Z_LVAL(holder) = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);	\
317 				break;												\
318 			case IS_OBJECT:											\
319 				(holder) = (*(op));									\
320 				zval_copy_ctor(&(holder));							\
321 				convert_to_boolean(&(holder));						\
322 				break;												\
323 			default:												\
324 				Z_LVAL(holder) = 0;									\
325 				break;												\
326 		}															\
327 		Z_TYPE(holder) = IS_BOOL;									\
328 		(op) = &(holder);											\
329 	}
330 
331 /* }}} */
332 
333 /* {{{ convert_object_to_type */
334 #define convert_object_to_type(op, ctype, conv_func)										\
335 	if (Z_OBJ_HT_P(op)->cast_object) {														\
336 		zval dst;																			\
337 		if (Z_OBJ_HT_P(op)->cast_object(op, &dst, ctype TSRMLS_CC) == FAILURE) {			\
338 			zend_error(E_RECOVERABLE_ERROR,													\
339 				"Object of class %s could not be converted to %s", Z_OBJCE_P(op)->name,		\
340 			zend_get_type_by_const(ctype));													\
341 		} else {																			\
342 			zval_dtor(op);																	\
343 			Z_TYPE_P(op) = ctype;															\
344 			op->value = dst.value;															\
345 		}																					\
346 	} else {																				\
347 		if (Z_OBJ_HT_P(op)->get) {															\
348 			zval *newop = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);								\
349 			if (Z_TYPE_P(newop) != IS_OBJECT) {												\
350 				/* for safety - avoid loop */												\
351 				zval_dtor(op);																\
352 				*op = *newop;																\
353 				FREE_ZVAL(newop);															\
354 				conv_func(op);																\
355 			}																				\
356 		}																					\
357 	}
358 
359 /* }}} */
360 
convert_to_long(zval * op)361 ZEND_API void convert_to_long(zval *op) /* {{{ */
362 {
363 	if (Z_TYPE_P(op) != IS_LONG) {
364 		convert_to_long_base(op, 10);
365 	}
366 }
367 /* }}} */
368 
convert_to_long_base(zval * op,int base)369 ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
370 {
371 	long tmp;
372 
373 	switch (Z_TYPE_P(op)) {
374 		case IS_NULL:
375 			Z_LVAL_P(op) = 0;
376 			break;
377 		case IS_RESOURCE: {
378 				TSRMLS_FETCH();
379 
380 				zend_list_delete(Z_LVAL_P(op));
381 			}
382 			/* break missing intentionally */
383 		case IS_BOOL:
384 		case IS_LONG:
385 			break;
386 		case IS_DOUBLE:
387 			Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
388 			break;
389 		case IS_STRING:
390 			{
391 				char *strval = Z_STRVAL_P(op);
392 
393 				Z_LVAL_P(op) = strtol(strval, NULL, base);
394 				STR_FREE(strval);
395 			}
396 			break;
397 		case IS_ARRAY:
398 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
399 			zval_dtor(op);
400 			Z_LVAL_P(op) = tmp;
401 			break;
402 		case IS_OBJECT:
403 			{
404 				int retval = 1;
405 				TSRMLS_FETCH();
406 
407 				convert_object_to_type(op, IS_LONG, convert_to_long);
408 
409 				if (Z_TYPE_P(op) == IS_LONG) {
410 					return;
411 				}
412 				zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);
413 
414 				zval_dtor(op);
415 				ZVAL_LONG(op, retval);
416 				return;
417 			}
418 		default:
419 			zend_error(E_WARNING, "Cannot convert to ordinal value");
420 			zval_dtor(op);
421 			Z_LVAL_P(op) = 0;
422 			break;
423 	}
424 
425 	Z_TYPE_P(op) = IS_LONG;
426 }
427 /* }}} */
428 
convert_to_double(zval * op)429 ZEND_API void convert_to_double(zval *op) /* {{{ */
430 {
431 	double tmp;
432 
433 	switch (Z_TYPE_P(op)) {
434 		case IS_NULL:
435 			Z_DVAL_P(op) = 0.0;
436 			break;
437 		case IS_RESOURCE: {
438 				TSRMLS_FETCH();
439 
440 				zend_list_delete(Z_LVAL_P(op));
441 			}
442 			/* break missing intentionally */
443 		case IS_BOOL:
444 		case IS_LONG:
445 			Z_DVAL_P(op) = (double) Z_LVAL_P(op);
446 			break;
447 		case IS_DOUBLE:
448 			break;
449 		case IS_STRING:
450 			{
451 				char *strval = Z_STRVAL_P(op);
452 
453 				Z_DVAL_P(op) = zend_strtod(strval, NULL);
454 				STR_FREE(strval);
455 			}
456 			break;
457 		case IS_ARRAY:
458 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
459 			zval_dtor(op);
460 			Z_DVAL_P(op) = tmp;
461 			break;
462 		case IS_OBJECT:
463 			{
464 				double retval = 1.0;
465 				TSRMLS_FETCH();
466 
467 				convert_object_to_type(op, IS_DOUBLE, convert_to_double);
468 
469 				if (Z_TYPE_P(op) == IS_DOUBLE) {
470 					return;
471 				}
472 				zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name);
473 
474 				zval_dtor(op);
475 				ZVAL_DOUBLE(op, retval);
476 				break;
477 			}
478 		default:
479 			zend_error(E_WARNING, "Cannot convert to real value (type=%d)", Z_TYPE_P(op));
480 			zval_dtor(op);
481 			Z_DVAL_P(op) = 0;
482 			break;
483 	}
484 	Z_TYPE_P(op) = IS_DOUBLE;
485 }
486 /* }}} */
487 
convert_to_null(zval * op)488 ZEND_API void convert_to_null(zval *op) /* {{{ */
489 {
490 	if (Z_TYPE_P(op) == IS_OBJECT) {
491 		if (Z_OBJ_HT_P(op)->cast_object) {
492 			zval *org;
493 			TSRMLS_FETCH();
494 
495 			ALLOC_ZVAL(org);
496 			*org = *op;
497 			if (Z_OBJ_HT_P(op)->cast_object(org, op, IS_NULL TSRMLS_CC) == SUCCESS) {
498 				zval_dtor(org);
499 				return;
500 			}
501 			*op = *org;
502 			FREE_ZVAL(org);
503 		}
504 	}
505 
506 	zval_dtor(op);
507 	Z_TYPE_P(op) = IS_NULL;
508 }
509 /* }}} */
510 
convert_to_boolean(zval * op)511 ZEND_API void convert_to_boolean(zval *op) /* {{{ */
512 {
513 	int tmp;
514 
515 	switch (Z_TYPE_P(op)) {
516 		case IS_BOOL:
517 			break;
518 		case IS_NULL:
519 			Z_LVAL_P(op) = 0;
520 			break;
521 		case IS_RESOURCE: {
522 				TSRMLS_FETCH();
523 
524 				zend_list_delete(Z_LVAL_P(op));
525 			}
526 			/* break missing intentionally */
527 		case IS_LONG:
528 			Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0);
529 			break;
530 		case IS_DOUBLE:
531 			Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0);
532 			break;
533 		case IS_STRING:
534 			{
535 				char *strval = Z_STRVAL_P(op);
536 
537 				if (Z_STRLEN_P(op) == 0
538 					|| (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) {
539 					Z_LVAL_P(op) = 0;
540 				} else {
541 					Z_LVAL_P(op) = 1;
542 				}
543 				STR_FREE(strval);
544 			}
545 			break;
546 		case IS_ARRAY:
547 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
548 			zval_dtor(op);
549 			Z_LVAL_P(op) = tmp;
550 			break;
551 		case IS_OBJECT:
552 			{
553 				zend_bool retval = 1;
554 				TSRMLS_FETCH();
555 
556 				convert_object_to_type(op, IS_BOOL, convert_to_boolean);
557 
558 				if (Z_TYPE_P(op) == IS_BOOL) {
559 					return;
560 				}
561 
562 				zval_dtor(op);
563 				ZVAL_BOOL(op, retval);
564 				break;
565 			}
566 		default:
567 			zval_dtor(op);
568 			Z_LVAL_P(op) = 0;
569 			break;
570 	}
571 	Z_TYPE_P(op) = IS_BOOL;
572 }
573 /* }}} */
574 
_convert_to_cstring(zval * op ZEND_FILE_LINE_DC)575 ZEND_API void _convert_to_cstring(zval *op ZEND_FILE_LINE_DC) /* {{{ */
576 {
577 	double dval;
578 	switch (Z_TYPE_P(op)) {
579 		case IS_DOUBLE: {
580 			TSRMLS_FETCH();
581 			dval = Z_DVAL_P(op);
582 			Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*H", (int) EG(precision), dval);
583 			/* %H already handles removing trailing zeros from the fractional part, yay */
584 			break;
585 		}
586 		default:
587 			_convert_to_string(op ZEND_FILE_LINE_CC);
588 	}
589 	Z_TYPE_P(op) = IS_STRING;
590 }
591 /* }}} */
592 
_convert_to_string(zval * op ZEND_FILE_LINE_DC)593 ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
594 {
595 	long lval;
596 	double dval;
597 
598 	switch (Z_TYPE_P(op)) {
599 		case IS_NULL:
600 			Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
601 			Z_STRLEN_P(op) = 0;
602 			break;
603 		case IS_STRING:
604 			break;
605 		case IS_BOOL:
606 			if (Z_LVAL_P(op)) {
607 				Z_STRVAL_P(op) = estrndup_rel("1", 1);
608 				Z_STRLEN_P(op) = 1;
609 			} else {
610 				Z_STRVAL_P(op) = STR_EMPTY_ALLOC();
611 				Z_STRLEN_P(op) = 0;
612 			}
613 			break;
614 		case IS_RESOURCE: {
615 			long tmp = Z_LVAL_P(op);
616 			TSRMLS_FETCH();
617 
618 			zend_list_delete(Z_LVAL_P(op));
619 			Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "Resource id #%ld", tmp);
620 			break;
621 		}
622 		case IS_LONG:
623 			lval = Z_LVAL_P(op);
624 
625 			Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%ld", lval);
626 			break;
627 		case IS_DOUBLE: {
628 			TSRMLS_FETCH();
629 			dval = Z_DVAL_P(op);
630 			Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), dval);
631 			/* %G already handles removing trailing zeros from the fractional part, yay */
632 			break;
633 		}
634 		case IS_ARRAY:
635 			zend_error(E_NOTICE, "Array to string conversion");
636 			zval_dtor(op);
637 			Z_STRVAL_P(op) = estrndup_rel("Array", sizeof("Array")-1);
638 			Z_STRLEN_P(op) = sizeof("Array")-1;
639 			break;
640 		case IS_OBJECT: {
641 			TSRMLS_FETCH();
642 
643 			convert_object_to_type(op, IS_STRING, convert_to_string);
644 
645 			if (Z_TYPE_P(op) == IS_STRING) {
646 				return;
647 			}
648 
649 			zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name);
650 			zval_dtor(op);
651 			Z_STRVAL_P(op) = estrndup_rel("Object", sizeof("Object")-1);
652 			Z_STRLEN_P(op) = sizeof("Object")-1;
653 			break;
654 		}
655 		default:
656 			zval_dtor(op);
657 			ZVAL_BOOL(op, 0);
658 			break;
659 	}
660 	Z_TYPE_P(op) = IS_STRING;
661 }
662 /* }}} */
663 
convert_scalar_to_array(zval * op,int type TSRMLS_DC)664 static void convert_scalar_to_array(zval *op, int type TSRMLS_DC) /* {{{ */
665 {
666 	zval *entry;
667 
668 	ALLOC_ZVAL(entry);
669 	*entry = *op;
670 	INIT_PZVAL(entry);
671 
672 	switch (type) {
673 		case IS_ARRAY:
674 			ALLOC_HASHTABLE(Z_ARRVAL_P(op));
675 			zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
676 			zend_hash_index_update(Z_ARRVAL_P(op), 0, (void *) &entry, sizeof(zval *), NULL);
677 			Z_TYPE_P(op) = IS_ARRAY;
678 			break;
679 		case IS_OBJECT:
680 			object_init(op);
681 			zend_hash_update(Z_OBJPROP_P(op), "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL);
682 			break;
683 	}
684 }
685 /* }}} */
686 
convert_to_array(zval * op)687 ZEND_API void convert_to_array(zval *op) /* {{{ */
688 {
689 	TSRMLS_FETCH();
690 
691 	switch (Z_TYPE_P(op)) {
692 		case IS_ARRAY:
693 			break;
694 /* OBJECTS_OPTIMIZE */
695 		case IS_OBJECT:
696 			{
697 				zval *tmp;
698 				HashTable *ht;
699 
700 				ALLOC_HASHTABLE(ht);
701 				zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
702 				if (Z_OBJCE_P(op) == zend_ce_closure) {
703 					convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
704 					if (Z_TYPE_P(op) == IS_ARRAY) {
705 						zend_hash_destroy(ht);
706 						FREE_HASHTABLE(ht);
707 						return;
708 					}
709 				} else if (Z_OBJ_HT_P(op)->get_properties) {
710 					HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC);
711 					if (obj_ht) {
712 						zend_hash_copy(ht, obj_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
713 					}
714 				} else {
715 					convert_object_to_type(op, IS_ARRAY, convert_to_array);
716 
717 					if (Z_TYPE_P(op) == IS_ARRAY) {
718 						zend_hash_destroy(ht);
719 						FREE_HASHTABLE(ht);
720 						return;
721 					}
722 				}
723 				zval_dtor(op);
724 				Z_TYPE_P(op) = IS_ARRAY;
725 				Z_ARRVAL_P(op) = ht;
726 			}
727 			break;
728 		case IS_NULL:
729 			ALLOC_HASHTABLE(Z_ARRVAL_P(op));
730 			zend_hash_init(Z_ARRVAL_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
731 			Z_TYPE_P(op) = IS_ARRAY;
732 			break;
733 		default:
734 			convert_scalar_to_array(op, IS_ARRAY TSRMLS_CC);
735 			break;
736 	}
737 }
738 /* }}} */
739 
convert_to_object(zval * op)740 ZEND_API void convert_to_object(zval *op) /* {{{ */
741 {
742 	TSRMLS_FETCH();
743 
744 	switch (Z_TYPE_P(op)) {
745 		case IS_ARRAY:
746 			{
747 				object_and_properties_init(op, zend_standard_class_def, Z_ARRVAL_P(op));
748 				break;
749 			}
750 		case IS_OBJECT:
751 			break;
752 		case IS_NULL:
753 			object_init(op);
754 			break;
755 		default:
756 			convert_scalar_to_array(op, IS_OBJECT TSRMLS_CC);
757 			break;
758 	}
759 }
760 /* }}} */
761 
multi_convert_to_long_ex(int argc,...)762 ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
763 {
764 	zval **arg;
765 	va_list ap;
766 
767 	va_start(ap, argc);
768 
769 	while (argc--) {
770 		arg = va_arg(ap, zval **);
771 		convert_to_long_ex(arg);
772 	}
773 
774 	va_end(ap);
775 }
776 /* }}} */
777 
multi_convert_to_double_ex(int argc,...)778 ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
779 {
780 	zval **arg;
781 	va_list ap;
782 
783 	va_start(ap, argc);
784 
785 	while (argc--) {
786 		arg = va_arg(ap, zval **);
787 		convert_to_double_ex(arg);
788 	}
789 
790 	va_end(ap);
791 }
792 /* }}} */
793 
multi_convert_to_string_ex(int argc,...)794 ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
795 {
796 	zval **arg;
797 	va_list ap;
798 
799 	va_start(ap, argc);
800 
801 	while (argc--) {
802 		arg = va_arg(ap, zval **);
803 		convert_to_string_ex(arg);
804 	}
805 
806 	va_end(ap);
807 }
808 /* }}} */
809 
add_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)810 ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
811 {
812 	zval op1_copy, op2_copy;
813 	int converted = 0;
814 
815 	while (1) {
816 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
817 			case TYPE_PAIR(IS_LONG, IS_LONG): {
818 				long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
819 
820 				/* check for overflow by comparing sign bits */
821 				if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
822 					&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
823 
824 					ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
825 				} else {
826 					ZVAL_LONG(result, lval);
827 				}
828 				return SUCCESS;
829 			}
830 
831 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
832 				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
833 				return SUCCESS;
834 
835 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
836 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
837 				return SUCCESS;
838 
839 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
840 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
841 				return SUCCESS;
842 
843 			case TYPE_PAIR(IS_ARRAY, IS_ARRAY): {
844 				zval *tmp;
845 
846 				if ((result == op1) && (result == op2)) {
847 					/* $a += $a */
848 					return SUCCESS;
849 				}
850 				if (result != op1) {
851 					*result = *op1;
852 					zval_copy_ctor(result);
853 				}
854 				zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
855 				return SUCCESS;
856 			}
857 
858 			default:
859 				if (!converted) {
860 					zendi_convert_scalar_to_number(op1, op1_copy, result);
861 					zendi_convert_scalar_to_number(op2, op2_copy, result);
862 					converted = 1;
863 				} else {
864 					zend_error(E_ERROR, "Unsupported operand types");
865 					return FAILURE; /* unknown datatype */
866 				}
867 		}
868 	}
869 }
870 /* }}} */
871 
sub_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)872 ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
873 {
874 	zval op1_copy, op2_copy;
875 	int converted = 0;
876 
877 	while (1) {
878 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
879 			case TYPE_PAIR(IS_LONG, IS_LONG): {
880 				long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
881 
882 				/* check for overflow by comparing sign bits */
883 				if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
884 					&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
885 
886 					ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
887 				} else {
888 					ZVAL_LONG(result, lval);
889 				}
890 				return SUCCESS;
891 
892 			}
893 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
894 				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
895 				return SUCCESS;
896 
897 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
898 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
899 				return SUCCESS;
900 
901 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
902 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
903 				return SUCCESS;
904 
905 			default:
906 				if (!converted) {
907 					zendi_convert_scalar_to_number(op1, op1_copy, result);
908 					zendi_convert_scalar_to_number(op2, op2_copy, result);
909 					converted = 1;
910 				} else {
911 					zend_error(E_ERROR, "Unsupported operand types");
912 					return FAILURE; /* unknown datatype */
913 				}
914 		}
915 	}
916 }
917 /* }}} */
918 
mul_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)919 ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
920 {
921 	zval op1_copy, op2_copy;
922 	int converted = 0;
923 
924 	while (1) {
925 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
926 			case TYPE_PAIR(IS_LONG, IS_LONG): {
927 				long overflow;
928 
929 				ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
930 				Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
931 				return SUCCESS;
932 
933 			}
934 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
935 				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
936 				return SUCCESS;
937 
938 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
939 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
940 				return SUCCESS;
941 
942 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
943 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
944 				return SUCCESS;
945 
946 			default:
947 				if (!converted) {
948 					zendi_convert_scalar_to_number(op1, op1_copy, result);
949 					zendi_convert_scalar_to_number(op2, op2_copy, result);
950 					converted = 1;
951 				} else {
952 					zend_error(E_ERROR, "Unsupported operand types");
953 					return FAILURE; /* unknown datatype */
954 				}
955 		}
956 	}
957 }
958 /* }}} */
959 
div_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)960 ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
961 {
962 	zval op1_copy, op2_copy;
963 	int converted = 0;
964 
965 	while (1) {
966 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
967 			case TYPE_PAIR(IS_LONG, IS_LONG):
968 				if (Z_LVAL_P(op2) == 0) {
969 					zend_error(E_WARNING, "Division by zero");
970 					ZVAL_BOOL(result, 0);
971 					return FAILURE;			/* division by zero */
972 				} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
973 					/* Prevent overflow error/crash */
974 					ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
975 					return SUCCESS;
976 				}
977 				if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
978 					ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
979 				} else {
980 					ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
981 				}
982 				return SUCCESS;
983 
984 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
985 				if (Z_LVAL_P(op2) == 0) {
986 					zend_error(E_WARNING, "Division by zero");
987 					ZVAL_BOOL(result, 0);
988 					return FAILURE;			/* division by zero */
989 				}
990 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
991 				return SUCCESS;
992 
993 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
994 				if (Z_DVAL_P(op2) == 0) {
995 					zend_error(E_WARNING, "Division by zero");
996 					ZVAL_BOOL(result, 0);
997 					return FAILURE;			/* division by zero */
998 				}
999 				ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1000 				return SUCCESS;
1001 
1002 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1003 				if (Z_DVAL_P(op2) == 0) {
1004 					zend_error(E_WARNING, "Division by zero");
1005 					ZVAL_BOOL(result, 0);
1006 					return FAILURE;			/* division by zero */
1007 				}
1008 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1009 				return SUCCESS;
1010 
1011 			default:
1012 				if (!converted) {
1013 					zendi_convert_scalar_to_number(op1, op1_copy, result);
1014 					zendi_convert_scalar_to_number(op2, op2_copy, result);
1015 					converted = 1;
1016 				} else {
1017 					zend_error(E_ERROR, "Unsupported operand types");
1018 					return FAILURE; /* unknown datatype */
1019 				}
1020 		}
1021 	}
1022 }
1023 /* }}} */
1024 
mod_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1025 ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1026 {
1027 	zval op1_copy, op2_copy;
1028 	long op1_lval;
1029 
1030 	zendi_convert_to_long(op1, op1_copy, result);
1031 	op1_lval = Z_LVAL_P(op1);
1032 	zendi_convert_to_long(op2, op2_copy, result);
1033 
1034 	if (Z_LVAL_P(op2) == 0) {
1035 		zend_error(E_WARNING, "Division by zero");
1036 		ZVAL_BOOL(result, 0);
1037 		return FAILURE;			/* modulus by zero */
1038 	}
1039 
1040 	if (Z_LVAL_P(op2) == -1) {
1041 		/* Prevent overflow error/crash if op1==LONG_MIN */
1042 		ZVAL_LONG(result, 0);
1043 		return SUCCESS;
1044 	}
1045 
1046 	ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
1047 	return SUCCESS;
1048 }
1049 /* }}} */
1050 
boolean_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1051 ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1052 {
1053 	zval op1_copy, op2_copy;
1054 	long op1_lval;
1055 
1056 	zendi_convert_to_boolean(op1, op1_copy, result);
1057 	op1_lval = Z_LVAL_P(op1);
1058 	zendi_convert_to_boolean(op2, op2_copy, result);
1059 	ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1060 	return SUCCESS;
1061 }
1062 /* }}} */
1063 
boolean_not_function(zval * result,zval * op1 TSRMLS_DC)1064 ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1065 {
1066 	zval op1_copy;
1067 
1068 	zendi_convert_to_boolean(op1, op1_copy, result);
1069 	ZVAL_BOOL(result, !Z_LVAL_P(op1));
1070 	return SUCCESS;
1071 }
1072 /* }}} */
1073 
bitwise_not_function(zval * result,zval * op1 TSRMLS_DC)1074 ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1075 {
1076 	zval op1_copy = *op1;
1077 
1078 	op1 = &op1_copy;
1079 
1080 	if (Z_TYPE_P(op1) == IS_LONG) {
1081 		ZVAL_LONG(result, ~Z_LVAL_P(op1));
1082 		return SUCCESS;
1083 	} else if (Z_TYPE_P(op1) == IS_DOUBLE) {
1084 		ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1085 		return SUCCESS;
1086 	} else if (Z_TYPE_P(op1) == IS_STRING) {
1087 		int i;
1088 
1089 		Z_TYPE_P(result) = IS_STRING;
1090 		Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1091 		Z_STRLEN_P(result) = Z_STRLEN_P(op1);
1092 		for (i = 0; i < Z_STRLEN_P(op1); i++) {
1093 			Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1094 		}
1095 		return SUCCESS;
1096 	}
1097 	zend_error(E_ERROR, "Unsupported operand types");
1098 	return FAILURE;				/* unknown datatype */
1099 }
1100 /* }}} */
1101 
bitwise_or_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1102 ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1103 {
1104 	zval op1_copy, op2_copy;
1105 	long op1_lval;
1106 
1107 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1108 		zval *longer, *shorter;
1109 		char *result_str;
1110 		int i, result_len;
1111 
1112 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1113 			longer = op1;
1114 			shorter = op2;
1115 		} else {
1116 			longer = op2;
1117 			shorter = op1;
1118 		}
1119 
1120 		Z_TYPE_P(result) = IS_STRING;
1121 		result_len = Z_STRLEN_P(longer);
1122 		result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1123 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1124 			result_str[i] |= Z_STRVAL_P(shorter)[i];
1125 		}
1126 		if (result==op1) {
1127 			STR_FREE(Z_STRVAL_P(result));
1128 		}
1129 		Z_STRVAL_P(result) = result_str;
1130 		Z_STRLEN_P(result) = result_len;
1131 		return SUCCESS;
1132 	}
1133 	zendi_convert_to_long(op1, op1_copy, result);
1134 	op1_lval = Z_LVAL_P(op1);
1135 	zendi_convert_to_long(op2, op2_copy, result);
1136 
1137 	ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1138 	return SUCCESS;
1139 }
1140 /* }}} */
1141 
bitwise_and_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1142 ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1143 {
1144 	zval op1_copy, op2_copy;
1145 	long op1_lval;
1146 
1147 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1148 		zval *longer, *shorter;
1149 		char *result_str;
1150 		int i, result_len;
1151 
1152 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1153 			longer = op1;
1154 			shorter = op2;
1155 		} else {
1156 			longer = op2;
1157 			shorter = op1;
1158 		}
1159 
1160 		Z_TYPE_P(result) = IS_STRING;
1161 		result_len = Z_STRLEN_P(shorter);
1162 		result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1163 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1164 			result_str[i] &= Z_STRVAL_P(longer)[i];
1165 		}
1166 		if (result==op1) {
1167 			STR_FREE(Z_STRVAL_P(result));
1168 		}
1169 		Z_STRVAL_P(result) = result_str;
1170 		Z_STRLEN_P(result) = result_len;
1171 		return SUCCESS;
1172 	}
1173 
1174 
1175 	zendi_convert_to_long(op1, op1_copy, result);
1176 	op1_lval = Z_LVAL_P(op1);
1177 	zendi_convert_to_long(op2, op2_copy, result);
1178 
1179 	ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1180 	return SUCCESS;
1181 }
1182 /* }}} */
1183 
bitwise_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1184 ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1185 {
1186 	zval op1_copy, op2_copy;
1187 	long op1_lval;
1188 
1189 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1190 		zval *longer, *shorter;
1191 		char *result_str;
1192 		int i, result_len;
1193 
1194 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1195 			longer = op1;
1196 			shorter = op2;
1197 		} else {
1198 			longer = op2;
1199 			shorter = op1;
1200 		}
1201 
1202 		Z_TYPE_P(result) = IS_STRING;
1203 		result_len = Z_STRLEN_P(shorter);
1204 		result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1205 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1206 			result_str[i] ^= Z_STRVAL_P(longer)[i];
1207 		}
1208 		if (result==op1) {
1209 			STR_FREE(Z_STRVAL_P(result));
1210 		}
1211 		Z_STRVAL_P(result) = result_str;
1212 		Z_STRLEN_P(result) = result_len;
1213 		return SUCCESS;
1214 	}
1215 
1216 	zendi_convert_to_long(op1, op1_copy, result);
1217 	op1_lval = Z_LVAL_P(op1);
1218 	zendi_convert_to_long(op2, op2_copy, result);
1219 
1220 	ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1221 	return SUCCESS;
1222 }
1223 /* }}} */
1224 
shift_left_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1225 ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1226 {
1227 	zval op1_copy, op2_copy;
1228 	long op1_lval;
1229 
1230 	zendi_convert_to_long(op1, op1_copy, result);
1231 	op1_lval = Z_LVAL_P(op1);
1232 	zendi_convert_to_long(op2, op2_copy, result);
1233 	ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1234 	return SUCCESS;
1235 }
1236 /* }}} */
1237 
shift_right_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1238 ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1239 {
1240 	zval op1_copy, op2_copy;
1241 	long op1_lval;
1242 
1243 	zendi_convert_to_long(op1, op1_copy, result);
1244 	op1_lval = Z_LVAL_P(op1);
1245 	zendi_convert_to_long(op2, op2_copy, result);
1246 	ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1247 	return SUCCESS;
1248 }
1249 /* }}} */
1250 
1251 /* must support result==op1 */
add_char_to_string(zval * result,const zval * op1,const zval * op2)1252 ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1253 {
1254 	int length = Z_STRLEN_P(op1) + 1;
1255 	char *buf;
1256 
1257 	if (UNEXPECTED(length < 0)) {
1258 		zend_error(E_ERROR, "String size overflow");
1259 	}
1260 
1261 	if (IS_INTERNED(Z_STRVAL_P(op1))) {
1262 		buf = (char *) emalloc(length + 1);
1263 		memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1264 	} else {
1265 		buf = (char *) erealloc(Z_STRVAL_P(op1), length + 1);
1266 	}
1267 	buf[length - 1] = (char) Z_LVAL_P(op2);
1268 	buf[length] = 0;
1269 	ZVAL_STRINGL(result, buf, length, 0);
1270 	return SUCCESS;
1271 }
1272 /* }}} */
1273 
1274 /* must support result==op1 */
add_string_to_string(zval * result,const zval * op1,const zval * op2)1275 ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1276 {
1277 	int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1278 	char *buf;
1279 
1280 	if (UNEXPECTED(length < 0)) {
1281 		zend_error(E_ERROR, "String size overflow");
1282 	}
1283 	if (IS_INTERNED(Z_STRVAL_P(op1))) {
1284 		buf = (char *) emalloc(length+1);
1285 		memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1286 	} else {
1287 		buf = (char *) erealloc(Z_STRVAL_P(op1), length+1);
1288 	}
1289 	memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1290 	buf[length] = 0;
1291 	ZVAL_STRINGL(result, buf, length, 0);
1292 	return SUCCESS;
1293 }
1294 /* }}} */
1295 
concat_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1296 ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1297 {
1298 	zval op1_copy, op2_copy;
1299 	int use_copy1 = 0, use_copy2 = 0;
1300 
1301 	if (Z_TYPE_P(op1) != IS_STRING) {
1302 		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1303 	}
1304 	if (Z_TYPE_P(op2) != IS_STRING) {
1305 		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1306 	}
1307 
1308 	if (use_copy1) {
1309 		/* We have created a converted copy of op1. Therefore, op1 won't become the result so
1310 		 * we have to free it.
1311 		 */
1312 		if (result == op1) {
1313 			zval_dtor(op1);
1314 		}
1315 		op1 = &op1_copy;
1316 	}
1317 	if (use_copy2) {
1318 		op2 = &op2_copy;
1319 	}
1320 	if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) {	/* special case, perform operations on result */
1321 		uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1322 
1323 		if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1324 			efree(Z_STRVAL_P(result));
1325 			ZVAL_EMPTY_STRING(result);
1326 			zend_error(E_ERROR, "String size overflow");
1327 		}
1328 
1329 		Z_STRVAL_P(result) = safe_erealloc(Z_STRVAL_P(result), res_len, 1, 1);
1330 
1331 		memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1332 		Z_STRVAL_P(result)[res_len]=0;
1333 		Z_STRLEN_P(result) = res_len;
1334 	} else {
1335 		int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1336 		char *buf;
1337 
1338 		if (Z_STRLEN_P(op1) < 0 || Z_STRLEN_P(op2) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1339 			zend_error(E_ERROR, "String size overflow");
1340 		}
1341 		buf = (char *) safe_emalloc(length, 1, 1);
1342 
1343 		memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1344 		memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1345 		buf[length] = 0;
1346 		ZVAL_STRINGL(result, buf, length, 0);
1347 	}
1348 	if (use_copy1) {
1349 		zval_dtor(op1);
1350 	}
1351 	if (use_copy2) {
1352 		zval_dtor(op2);
1353 	}
1354 	return SUCCESS;
1355 }
1356 /* }}} */
1357 
string_compare_function_ex(zval * result,zval * op1,zval * op2,zend_bool case_insensitive TSRMLS_DC)1358 ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1359 {
1360 	zval op1_copy, op2_copy;
1361 	int use_copy1 = 0, use_copy2 = 0;
1362 
1363 	if (Z_TYPE_P(op1) != IS_STRING) {
1364 		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1365 	}
1366 	if (Z_TYPE_P(op2) != IS_STRING) {
1367 		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1368 	}
1369 
1370 	if (use_copy1) {
1371 		op1 = &op1_copy;
1372 	}
1373 	if (use_copy2) {
1374 		op2 = &op2_copy;
1375 	}
1376 
1377 	if (case_insensitive) {
1378 		ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1379 	} else {
1380 		ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1381 	}
1382 
1383 	if (use_copy1) {
1384 		zval_dtor(op1);
1385 	}
1386 	if (use_copy2) {
1387 		zval_dtor(op2);
1388 	}
1389 	return SUCCESS;
1390 }
1391 /* }}} */
1392 
string_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1393 ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1394 {
1395 	return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1396 }
1397 /* }}} */
1398 
string_case_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1399 ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1400 {
1401 	return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1402 }
1403 /* }}} */
1404 
1405 #if HAVE_STRCOLL
string_locale_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1406 ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1407 {
1408 	zval op1_copy, op2_copy;
1409 	int use_copy1 = 0, use_copy2 = 0;
1410 
1411 	if (Z_TYPE_P(op1) != IS_STRING) {
1412 		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1413 	}
1414 	if (Z_TYPE_P(op2) != IS_STRING) {
1415 		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1416 	}
1417 
1418 	if (use_copy1) {
1419 		op1 = &op1_copy;
1420 	}
1421 	if (use_copy2) {
1422 		op2 = &op2_copy;
1423 	}
1424 
1425 	ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1426 
1427 	if (use_copy1) {
1428 		zval_dtor(op1);
1429 	}
1430 	if (use_copy2) {
1431 		zval_dtor(op2);
1432 	}
1433 	return SUCCESS;
1434 }
1435 /* }}} */
1436 #endif
1437 
numeric_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1438 ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1439 {
1440 	zval op1_copy, op2_copy;
1441 
1442 	op1_copy = *op1;
1443 	zval_copy_ctor(&op1_copy);
1444 
1445 	op2_copy = *op2;
1446 	zval_copy_ctor(&op2_copy);
1447 
1448 	convert_to_double(&op1_copy);
1449 	convert_to_double(&op2_copy);
1450 
1451 	ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1452 
1453 	return SUCCESS;
1454 }
1455 /* }}} */
1456 
zend_free_obj_get_result(zval * op TSRMLS_DC)1457 static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1458 {
1459 	if (Z_REFCOUNT_P(op) == 0) {
1460 		GC_REMOVE_ZVAL_FROM_BUFFER(op);
1461 		zval_dtor(op);
1462 		FREE_ZVAL(op);
1463 	} else {
1464 		zval_ptr_dtor(&op);
1465 	}
1466 }
1467 /* }}} */
1468 
compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1469 ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1470 {
1471 	int ret;
1472 	int converted = 0;
1473 	zval op1_copy, op2_copy;
1474 	zval *op_free;
1475 
1476 	while (1) {
1477 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1478 			case TYPE_PAIR(IS_LONG, IS_LONG):
1479 				ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1480 				return SUCCESS;
1481 
1482 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1483 				Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1484 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1485 				return SUCCESS;
1486 
1487 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1488 				Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1489 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1490 				return SUCCESS;
1491 
1492 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1493 				if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1494 					ZVAL_LONG(result, 0);
1495 				} else {
1496 					Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1497 					ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1498 				}
1499 				return SUCCESS;
1500 
1501 			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1502 				zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1503 				return SUCCESS;
1504 
1505 			case TYPE_PAIR(IS_NULL, IS_NULL):
1506 				ZVAL_LONG(result, 0);
1507 				return SUCCESS;
1508 
1509 			case TYPE_PAIR(IS_NULL, IS_BOOL):
1510 				ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1511 				return SUCCESS;
1512 
1513 			case TYPE_PAIR(IS_BOOL, IS_NULL):
1514 				ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1515 				return SUCCESS;
1516 
1517 			case TYPE_PAIR(IS_BOOL, IS_BOOL):
1518 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1519 				return SUCCESS;
1520 
1521 			case TYPE_PAIR(IS_STRING, IS_STRING):
1522 				zendi_smart_strcmp(result, op1, op2);
1523 				return SUCCESS;
1524 
1525 			case TYPE_PAIR(IS_NULL, IS_STRING):
1526 				ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1527 				return SUCCESS;
1528 
1529 			case TYPE_PAIR(IS_STRING, IS_NULL):
1530 				ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1531 				return SUCCESS;
1532 
1533 			case TYPE_PAIR(IS_OBJECT, IS_NULL):
1534 				ZVAL_LONG(result, 1);
1535 				return SUCCESS;
1536 
1537 			case TYPE_PAIR(IS_NULL, IS_OBJECT):
1538 				ZVAL_LONG(result, -1);
1539 				return SUCCESS;
1540 
1541 			case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
1542 				/* If both are objects sharing the same comparision handler then use is */
1543 				if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {
1544 					if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1545 						/* object handles are identical, apparently this is the same object */
1546 						ZVAL_LONG(result, 0);
1547 						return SUCCESS;
1548 					}
1549 					ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
1550 					return SUCCESS;
1551 				}
1552 				/* break missing intentionally */
1553 
1554 			default:
1555 				if (Z_TYPE_P(op1) == IS_OBJECT) {
1556 					if (Z_OBJ_HT_P(op1)->get) {
1557 						op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1558 						ret = compare_function(result, op_free, op2 TSRMLS_CC);
1559 						zend_free_obj_get_result(op_free TSRMLS_CC);
1560 						return ret;
1561 					} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1562 						ALLOC_INIT_ZVAL(op_free);
1563 						if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1564 							ZVAL_LONG(result, 1);
1565 							zend_free_obj_get_result(op_free TSRMLS_CC);
1566 							return SUCCESS;
1567 						}
1568 						ret = compare_function(result, op_free, op2 TSRMLS_CC);
1569 						zend_free_obj_get_result(op_free TSRMLS_CC);
1570 						return ret;
1571 					}
1572 				}
1573 				if (Z_TYPE_P(op2) == IS_OBJECT) {
1574 					if (Z_OBJ_HT_P(op2)->get) {
1575 						op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1576 						ret = compare_function(result, op1, op_free TSRMLS_CC);
1577 						zend_free_obj_get_result(op_free TSRMLS_CC);
1578 						return ret;
1579 					} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1580 						ALLOC_INIT_ZVAL(op_free);
1581 						if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1582 							ZVAL_LONG(result, -1);
1583 							zend_free_obj_get_result(op_free TSRMLS_CC);
1584 							return SUCCESS;
1585 						}
1586 						ret = compare_function(result, op1, op_free TSRMLS_CC);
1587 						zend_free_obj_get_result(op_free TSRMLS_CC);
1588 						return ret;
1589 					} else if (Z_TYPE_P(op1) == IS_OBJECT) {
1590 						ZVAL_LONG(result, 1);
1591 						return SUCCESS;
1592 					}
1593 				}
1594 				if (!converted) {
1595 					if (Z_TYPE_P(op1) == IS_NULL) {
1596 						zendi_convert_to_boolean(op2, op2_copy, result);
1597 						ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1598 						return SUCCESS;
1599 					} else if (Z_TYPE_P(op2) == IS_NULL) {
1600 						zendi_convert_to_boolean(op1, op1_copy, result);
1601 						ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1602 						return SUCCESS;
1603 					} else if (Z_TYPE_P(op1) == IS_BOOL) {
1604 						zendi_convert_to_boolean(op2, op2_copy, result);
1605 						ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1606 						return SUCCESS;
1607 					} else if (Z_TYPE_P(op2) == IS_BOOL) {
1608 						zendi_convert_to_boolean(op1, op1_copy, result);
1609 						ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1610 						return SUCCESS;
1611 					} else {
1612 						zendi_convert_scalar_to_number(op1, op1_copy, result);
1613 						zendi_convert_scalar_to_number(op2, op2_copy, result);
1614 						converted = 1;
1615 					}
1616 				} else if (Z_TYPE_P(op1)==IS_ARRAY) {
1617 					ZVAL_LONG(result, 1);
1618 					return SUCCESS;
1619 				} else if (Z_TYPE_P(op2)==IS_ARRAY) {
1620 					ZVAL_LONG(result, -1);
1621 					return SUCCESS;
1622 				} else if (Z_TYPE_P(op1)==IS_OBJECT) {
1623 					ZVAL_LONG(result, 1);
1624 					return SUCCESS;
1625 				} else if (Z_TYPE_P(op2)==IS_OBJECT) {
1626 					ZVAL_LONG(result, -1);
1627 					return SUCCESS;
1628 				} else {
1629 					ZVAL_LONG(result, 0);
1630 					return FAILURE;
1631 				}
1632 		}
1633 	}
1634 }
1635 /* }}} */
1636 
hash_zval_identical_function(const zval ** z1,const zval ** z2)1637 static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1638 {
1639 	zval result;
1640 	TSRMLS_FETCH();
1641 
1642 	/* is_identical_function() returns 1 in case of identity and 0 in case
1643 	 * of a difference;
1644 	 * whereas this comparison function is expected to return 0 on identity,
1645 	 * and non zero otherwise.
1646 	 */
1647 	if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1648 		return 1;
1649 	}
1650 	return !Z_LVAL(result);
1651 }
1652 /* }}} */
1653 
is_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1654 ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1655 {
1656 	Z_TYPE_P(result) = IS_BOOL;
1657 	if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1658 		Z_LVAL_P(result) = 0;
1659 		return SUCCESS;
1660 	}
1661 	switch (Z_TYPE_P(op1)) {
1662 		case IS_NULL:
1663 			Z_LVAL_P(result) = 1;
1664 			break;
1665 		case IS_BOOL:
1666 		case IS_LONG:
1667 		case IS_RESOURCE:
1668 			Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1669 			break;
1670 		case IS_DOUBLE:
1671 			Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1672 			break;
1673 		case IS_STRING:
1674 			Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1675 				&& (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1676 			break;
1677 		case IS_ARRAY:
1678 			Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1679 				zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1680 			break;
1681 		case IS_OBJECT:
1682 			if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1683 				Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1684 			} else {
1685 				Z_LVAL_P(result) = 0;
1686 			}
1687 			break;
1688 		default:
1689 			Z_LVAL_P(result) = 0;
1690 			return FAILURE;
1691 	}
1692 	return SUCCESS;
1693 }
1694 /* }}} */
1695 
is_not_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1696 ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1697 {
1698 	if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1699 		return FAILURE;
1700 	}
1701 	Z_LVAL_P(result) = !Z_LVAL_P(result);
1702 	return SUCCESS;
1703 }
1704 /* }}} */
1705 
is_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1706 ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1707 {
1708 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1709 		return FAILURE;
1710 	}
1711 	ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1712 	return SUCCESS;
1713 }
1714 /* }}} */
1715 
is_not_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1716 ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1717 {
1718 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1719 		return FAILURE;
1720 	}
1721 	ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1722 	return SUCCESS;
1723 }
1724 /* }}} */
1725 
is_smaller_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1726 ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1727 {
1728 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1729 		return FAILURE;
1730 	}
1731 	ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1732 	return SUCCESS;
1733 }
1734 /* }}} */
1735 
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1736 ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1737 {
1738 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1739 		return FAILURE;
1740 	}
1741 	ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1742 	return SUCCESS;
1743 }
1744 /* }}} */
1745 
instanceof_function_ex(const zend_class_entry * instance_ce,const zend_class_entry * ce,zend_bool interfaces_only TSRMLS_DC)1746 ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1747 {
1748 	zend_uint i;
1749 
1750 	for (i=0; i<instance_ce->num_interfaces; i++) {
1751 		if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1752 			return 1;
1753 		}
1754 	}
1755 	if (!interfaces_only) {
1756 		while (instance_ce) {
1757 			if (instance_ce == ce) {
1758 				return 1;
1759 			}
1760 			instance_ce = instance_ce->parent;
1761 		}
1762 	}
1763 
1764 	return 0;
1765 }
1766 /* }}} */
1767 
instanceof_function(const zend_class_entry * instance_ce,const zend_class_entry * ce TSRMLS_DC)1768 ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1769 {
1770 	return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1771 }
1772 /* }}} */
1773 
1774 #define LOWER_CASE 1
1775 #define UPPER_CASE 2
1776 #define NUMERIC 3
1777 
increment_string(zval * str)1778 static void increment_string(zval *str) /* {{{ */
1779 {
1780 	int carry=0;
1781 	int pos=Z_STRLEN_P(str)-1;
1782 	char *s=Z_STRVAL_P(str);
1783 	char *t;
1784 	int last=0; /* Shut up the compiler warning */
1785 	int ch;
1786 
1787 	if (Z_STRLEN_P(str) == 0) {
1788 		STR_FREE(Z_STRVAL_P(str));
1789 		Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1790 		Z_STRLEN_P(str) = 1;
1791 		return;
1792 	}
1793 
1794 	if (IS_INTERNED(s)) {
1795 		s = (char*) emalloc(Z_STRLEN_P(str) + 1);
1796 		memcpy(s, Z_STRVAL_P(str), Z_STRLEN_P(str) + 1);
1797 		Z_STRVAL_P(str) = s;
1798 	}
1799 
1800 	while (pos >= 0) {
1801 		ch = s[pos];
1802 		if (ch >= 'a' && ch <= 'z') {
1803 			if (ch == 'z') {
1804 				s[pos] = 'a';
1805 				carry=1;
1806 			} else {
1807 				s[pos]++;
1808 				carry=0;
1809 			}
1810 			last=LOWER_CASE;
1811 		} else if (ch >= 'A' && ch <= 'Z') {
1812 			if (ch == 'Z') {
1813 				s[pos] = 'A';
1814 				carry=1;
1815 			} else {
1816 				s[pos]++;
1817 				carry=0;
1818 			}
1819 			last=UPPER_CASE;
1820 		} else if (ch >= '0' && ch <= '9') {
1821 			if (ch == '9') {
1822 				s[pos] = '0';
1823 				carry=1;
1824 			} else {
1825 				s[pos]++;
1826 				carry=0;
1827 			}
1828 			last = NUMERIC;
1829 		} else {
1830 			carry=0;
1831 			break;
1832 		}
1833 		if (carry == 0) {
1834 			break;
1835 		}
1836 		pos--;
1837 	}
1838 
1839 	if (carry) {
1840 		t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1841 		memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1842 		Z_STRLEN_P(str)++;
1843 		t[Z_STRLEN_P(str)] = '\0';
1844 		switch (last) {
1845 			case NUMERIC:
1846 				t[0] = '1';
1847 				break;
1848 			case UPPER_CASE:
1849 				t[0] = 'A';
1850 				break;
1851 			case LOWER_CASE:
1852 				t[0] = 'a';
1853 				break;
1854 		}
1855 		STR_FREE(Z_STRVAL_P(str));
1856 		Z_STRVAL_P(str) = t;
1857 	}
1858 }
1859 /* }}} */
1860 
increment_function(zval * op1)1861 ZEND_API int increment_function(zval *op1) /* {{{ */
1862 {
1863 	switch (Z_TYPE_P(op1)) {
1864 		case IS_LONG:
1865 			if (Z_LVAL_P(op1) == LONG_MAX) {
1866 				/* switch to double */
1867 				double d = (double)Z_LVAL_P(op1);
1868 				ZVAL_DOUBLE(op1, d+1);
1869 			} else {
1870 			Z_LVAL_P(op1)++;
1871 			}
1872 			break;
1873 		case IS_DOUBLE:
1874 			Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
1875 			break;
1876 		case IS_NULL:
1877 			ZVAL_LONG(op1, 1);
1878 			break;
1879 		case IS_STRING: {
1880 				long lval;
1881 				double dval;
1882 
1883 				switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1884 					case IS_LONG:
1885 						str_efree(Z_STRVAL_P(op1));
1886 						if (lval == LONG_MAX) {
1887 							/* switch to double */
1888 							double d = (double)lval;
1889 							ZVAL_DOUBLE(op1, d+1);
1890 						} else {
1891 							ZVAL_LONG(op1, lval+1);
1892 						}
1893 						break;
1894 					case IS_DOUBLE:
1895 						str_efree(Z_STRVAL_P(op1));
1896 						ZVAL_DOUBLE(op1, dval+1);
1897 						break;
1898 					default:
1899 						/* Perl style string increment */
1900 						increment_string(op1);
1901 						break;
1902 				}
1903 			}
1904 			break;
1905 		default:
1906 			return FAILURE;
1907 	}
1908 	return SUCCESS;
1909 }
1910 /* }}} */
1911 
decrement_function(zval * op1)1912 ZEND_API int decrement_function(zval *op1) /* {{{ */
1913 {
1914 	long lval;
1915 	double dval;
1916 
1917 	switch (Z_TYPE_P(op1)) {
1918 		case IS_LONG:
1919 			if (Z_LVAL_P(op1) == LONG_MIN) {
1920 				double d = (double)Z_LVAL_P(op1);
1921 				ZVAL_DOUBLE(op1, d-1);
1922 			} else {
1923 			Z_LVAL_P(op1)--;
1924 			}
1925 			break;
1926 		case IS_DOUBLE:
1927 			Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
1928 			break;
1929 		case IS_STRING:		/* Like perl we only support string increment */
1930 			if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
1931 				STR_FREE(Z_STRVAL_P(op1));
1932 				ZVAL_LONG(op1, -1);
1933 				break;
1934 			}
1935 			switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
1936 				case IS_LONG:
1937 					STR_FREE(Z_STRVAL_P(op1));
1938 					if (lval == LONG_MIN) {
1939 						double d = (double)lval;
1940 						ZVAL_DOUBLE(op1, d-1);
1941 					} else {
1942 						ZVAL_LONG(op1, lval-1);
1943 					}
1944 					break;
1945 				case IS_DOUBLE:
1946 					STR_FREE(Z_STRVAL_P(op1));
1947 					ZVAL_DOUBLE(op1, dval - 1);
1948 					break;
1949 			}
1950 			break;
1951 		default:
1952 			return FAILURE;
1953 	}
1954 
1955 	return SUCCESS;
1956 }
1957 /* }}} */
1958 
zval_is_true(zval * op)1959 ZEND_API int zval_is_true(zval *op) /* {{{ */
1960 {
1961 	convert_to_boolean(op);
1962 	return (Z_LVAL_P(op) ? 1 : 0);
1963 }
1964 /* }}} */
1965 
1966 #ifdef ZEND_USE_TOLOWER_L
zend_update_current_locale(void)1967 ZEND_API void zend_update_current_locale(void) /* {{{ */
1968 {
1969 	current_locale = _get_current_locale();
1970 }
1971 /* }}} */
1972 #endif
1973 
zend_str_tolower_copy(char * dest,const char * source,unsigned int length)1974 ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
1975 {
1976 	register unsigned char *str = (unsigned char*)source;
1977 	register unsigned char *result = (unsigned char*)dest;
1978 	register unsigned char *end = str + length;
1979 
1980 	while (str < end) {
1981 		*result++ = zend_tolower_ascii(*str++);
1982 	}
1983 	*result = '\0';
1984 
1985 	return dest;
1986 }
1987 /* }}} */
1988 
zend_str_tolower_dup(const char * source,unsigned int length)1989 ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
1990 {
1991 	return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
1992 }
1993 /* }}} */
1994 
zend_str_tolower(char * str,unsigned int length)1995 ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
1996 {
1997 	register unsigned char *p = (unsigned char*)str;
1998 	register unsigned char *end = p + length;
1999 
2000 	while (p < end) {
2001 		*p = zend_tolower_ascii(*p);
2002 		p++;
2003 	}
2004 }
2005 /* }}} */
2006 
zend_binary_strcmp(const char * s1,uint len1,const char * s2,uint len2)2007 ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2008 {
2009 	int retval;
2010 
2011 	if (s1 == s2) {
2012 		return 0;
2013 	}
2014 	retval = memcmp(s1, s2, MIN(len1, len2));
2015 	if (!retval) {
2016 		return (len1 - len2);
2017 	} else {
2018 		return retval;
2019 	}
2020 }
2021 /* }}} */
2022 
zend_binary_strncmp(const char * s1,uint len1,const char * s2,uint len2,uint length)2023 ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2024 {
2025 	int retval;
2026 
2027 	if (s1 == s2) {
2028 		return 0;
2029 	}
2030 	retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2031 	if (!retval) {
2032 		return (MIN(length, len1) - MIN(length, len2));
2033 	} else {
2034 		return retval;
2035 	}
2036 }
2037 /* }}} */
2038 
zend_binary_strcasecmp(const char * s1,uint len1,const char * s2,uint len2)2039 ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2040 {
2041 	int len;
2042 	int c1, c2;
2043 
2044 	if (s1 == s2) {
2045 		return 0;
2046 	}
2047 
2048 	len = MIN(len1, len2);
2049 	while (len--) {
2050 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2051 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2052 		if (c1 != c2) {
2053 			return c1 - c2;
2054 		}
2055 	}
2056 
2057 	return len1 - len2;
2058 }
2059 /* }}} */
2060 
zend_binary_strncasecmp(const char * s1,uint len1,const char * s2,uint len2,uint length)2061 ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2062 {
2063 	int len;
2064 	int c1, c2;
2065 
2066 	if (s1 == s2) {
2067 		return 0;
2068 	}
2069 	len = MIN(length, MIN(len1, len2));
2070 	while (len--) {
2071 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2072 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2073 		if (c1 != c2) {
2074 			return c1 - c2;
2075 		}
2076 	}
2077 
2078 	return MIN(length, len1) - MIN(length, len2);
2079 }
2080 /* }}} */
2081 
zend_binary_strcasecmp_l(const char * s1,uint len1,const char * s2,uint len2)2082 ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2083 {
2084 	int len;
2085 	int c1, c2;
2086 
2087 	if (s1 == s2) {
2088 		return 0;
2089 	}
2090 
2091 	len = MIN(len1, len2);
2092 	while (len--) {
2093 		c1 = zend_tolower((int)*(unsigned char *)s1++);
2094 		c2 = zend_tolower((int)*(unsigned char *)s2++);
2095 		if (c1 != c2) {
2096 			return c1 - c2;
2097 		}
2098 	}
2099 
2100 	return len1 - len2;
2101 }
2102 /* }}} */
2103 
zend_binary_strncasecmp_l(const char * s1,uint len1,const char * s2,uint len2,uint length)2104 ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2105 {
2106 	int len;
2107 	int c1, c2;
2108 
2109 	if (s1 == s2) {
2110 		return 0;
2111 	}
2112 	len = MIN(length, MIN(len1, len2));
2113 	while (len--) {
2114 		c1 = zend_tolower((int)*(unsigned char *)s1++);
2115 		c2 = zend_tolower((int)*(unsigned char *)s2++);
2116 		if (c1 != c2) {
2117 			return c1 - c2;
2118 		}
2119 	}
2120 
2121 	return MIN(length, len1) - MIN(length, len2);
2122 }
2123 /* }}} */
2124 
zend_binary_zval_strcmp(zval * s1,zval * s2)2125 ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2126 {
2127 	return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2128 }
2129 /* }}} */
2130 
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)2131 ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2132 {
2133 	return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2134 }
2135 /* }}} */
2136 
zend_binary_zval_strcasecmp(zval * s1,zval * s2)2137 ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2138 {
2139 	return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2140 }
2141 /* }}} */
2142 
zend_binary_zval_strncasecmp(zval * s1,zval * s2,zval * s3)2143 ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2144 {
2145 	return zend_binary_strncasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2146 }
2147 /* }}} */
2148 
zendi_smart_strcmp(zval * result,zval * s1,zval * s2)2149 ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2150 {
2151 	int ret1, ret2;
2152 	int oflow1, oflow2;
2153 	long lval1 = 0, lval2 = 0;
2154 	double dval1 = 0.0, dval2 = 0.0;
2155 
2156 	if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2157 		(ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2158 #if ULONG_MAX == 0xFFFFFFFF
2159 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2160 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2161 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
2162 #else
2163 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2164 #endif
2165 			/* both values are integers overflown to the same side, and the
2166 			 * double comparison may have resulted in crucial accuracy lost */
2167 			goto string_cmp;
2168 		}
2169 		if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2170 			if (ret1!=IS_DOUBLE) {
2171 				if (oflow2) {
2172 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2173 					ZVAL_LONG(result, -1 * oflow2);
2174 					return;
2175 				}
2176 				dval1 = (double) lval1;
2177 			} else if (ret2!=IS_DOUBLE) {
2178 				if (oflow1) {
2179 					ZVAL_LONG(result, oflow1);
2180 					return;
2181 				}
2182 				dval2 = (double) lval2;
2183 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
2184 				/* Both values overflowed and have the same sign,
2185 				 * so a numeric comparison would be inaccurate */
2186 				goto string_cmp;
2187 			}
2188 			Z_DVAL_P(result) = dval1 - dval2;
2189 			ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2190 		} else { /* they both have to be long's */
2191 			ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2192 		}
2193 	} else {
2194 string_cmp:
2195 		Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2196 		ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2197 	}
2198 }
2199 /* }}} */
2200 
2201 static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2202 {
2203 	zval result;
2204 
2205 	if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2206 		return 1;
2207 	}
2208 	return Z_LVAL(result);
2209 }
2210 /* }}} */
2211 
2212 ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2213 {
2214 	return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2215 }
2216 /* }}} */
2217 
2218 ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2219 {
2220 	ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2221 }
2222 /* }}} */
2223 
2224 ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2225 {
2226 	zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2227 }
2228 /* }}} */
2229 
2230 ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2231 {
2232 	Z_TYPE_P(result) = IS_LONG;
2233 
2234 	if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2235 		Z_LVAL_P(result) = 0;
2236 		return;
2237 	}
2238 
2239 	if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2240 		Z_LVAL_P(result) = 1;
2241 	} else {
2242 		Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2243 	}
2244 }
2245 /* }}} */
2246 
2247 ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2248 {
2249 	TSRMLS_FETCH();
2250 
2251 	Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2252 }
2253 /* }}} */
2254 
2255 /*
2256  * Local variables:
2257  * tab-width: 4
2258  * c-basic-offset: 4
2259  * indent-tabs-mode: t
2260  * End:
2261  */
2262