xref: /PHP-5.6/Zend/zend_operators.c (revision 41fc3c76)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2016 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_efree(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_efree(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_efree(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_efree(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 					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
861 
862 					zendi_convert_scalar_to_number(op1, op1_copy, result);
863 					zendi_convert_scalar_to_number(op2, op2_copy, result);
864 					converted = 1;
865 				} else {
866 					zend_error(E_ERROR, "Unsupported operand types");
867 					return FAILURE; /* unknown datatype */
868 				}
869 		}
870 	}
871 }
872 /* }}} */
873 
sub_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)874 ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
875 {
876 	zval op1_copy, op2_copy;
877 	int converted = 0;
878 
879 	while (1) {
880 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
881 			case TYPE_PAIR(IS_LONG, IS_LONG): {
882 				long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
883 
884 				/* check for overflow by comparing sign bits */
885 				if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
886 					&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
887 
888 					ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
889 				} else {
890 					ZVAL_LONG(result, lval);
891 				}
892 				return SUCCESS;
893 
894 			}
895 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
896 				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
897 				return SUCCESS;
898 
899 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
900 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
901 				return SUCCESS;
902 
903 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
904 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
905 				return SUCCESS;
906 
907 			default:
908 				if (!converted) {
909 					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
910 
911 					zendi_convert_scalar_to_number(op1, op1_copy, result);
912 					zendi_convert_scalar_to_number(op2, op2_copy, result);
913 					converted = 1;
914 				} else {
915 					zend_error(E_ERROR, "Unsupported operand types");
916 					return FAILURE; /* unknown datatype */
917 				}
918 		}
919 	}
920 }
921 /* }}} */
922 
mul_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)923 ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
924 {
925 	zval op1_copy, op2_copy;
926 	int converted = 0;
927 
928 	while (1) {
929 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
930 			case TYPE_PAIR(IS_LONG, IS_LONG): {
931 				long overflow;
932 
933 				ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
934 				Z_TYPE_P(result) = overflow ? IS_DOUBLE : IS_LONG;
935 				return SUCCESS;
936 
937 			}
938 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
939 				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
940 				return SUCCESS;
941 
942 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
943 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
944 				return SUCCESS;
945 
946 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
947 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
948 				return SUCCESS;
949 
950 			default:
951 				if (!converted) {
952 					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
953 
954 					zendi_convert_scalar_to_number(op1, op1_copy, result);
955 					zendi_convert_scalar_to_number(op2, op2_copy, result);
956 					converted = 1;
957 				} else {
958 					zend_error(E_ERROR, "Unsupported operand types");
959 					return FAILURE; /* unknown datatype */
960 				}
961 		}
962 	}
963 }
964 /* }}} */
965 
pow_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)966 ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
967 {
968 	zval op1_copy, op2_copy;
969 	int converted = 0;
970 
971 	while (1) {
972 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
973 			case TYPE_PAIR(IS_LONG, IS_LONG):
974 				if (Z_LVAL_P(op2) >= 0) {
975 					long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
976 
977 					if (i == 0) {
978 						ZVAL_LONG(result, 1L);
979 						return SUCCESS;
980 					} else if (l2 == 0) {
981 						ZVAL_LONG(result, 0);
982 						return SUCCESS;
983 					}
984 
985 					while (i >= 1) {
986 						long overflow;
987 						double dval = 0.0;
988 
989 						if (i % 2) {
990 							--i;
991 							ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
992 							if (overflow) {
993 								ZVAL_DOUBLE(result, dval * pow(l2, i));
994 								return SUCCESS;
995 							}
996 						} else {
997 							i /= 2;
998 							ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
999 							if (overflow) {
1000 								ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1001 								return SUCCESS;
1002 							}
1003 						}
1004 					}
1005 					/* i == 0 */
1006 					ZVAL_LONG(result, l1);
1007 				} else {
1008 					ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1009 				}
1010 				return SUCCESS;
1011 
1012 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1013 				ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1014 				return SUCCESS;
1015 
1016 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1017 				ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1018 				return SUCCESS;
1019 
1020 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1021 				ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1022 				return SUCCESS;
1023 
1024 			default:
1025 				if (!converted) {
1026 					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW);
1027 
1028 					if (Z_TYPE_P(op1) == IS_ARRAY) {
1029 						ZVAL_LONG(result, 0);
1030 						return SUCCESS;
1031 					} else {
1032 						zendi_convert_scalar_to_number(op1, op1_copy, result);
1033 					}
1034 					if (Z_TYPE_P(op2) == IS_ARRAY) {
1035 						ZVAL_LONG(result, 1L);
1036 						return SUCCESS;
1037 					} else {
1038 						zendi_convert_scalar_to_number(op2, op2_copy, result);
1039 					}
1040 					converted = 1;
1041 				} else {
1042 					zend_error(E_ERROR, "Unsupported operand types");
1043 					return FAILURE;
1044 				}
1045 		}
1046 	}
1047 }
1048 /* }}} */
1049 
div_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1050 ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1051 {
1052 	zval op1_copy, op2_copy;
1053 	int converted = 0;
1054 
1055 	while (1) {
1056 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1057 			case TYPE_PAIR(IS_LONG, IS_LONG):
1058 				if (Z_LVAL_P(op2) == 0) {
1059 					zend_error(E_WARNING, "Division by zero");
1060 					ZVAL_BOOL(result, 0);
1061 					return FAILURE;			/* division by zero */
1062 				} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
1063 					/* Prevent overflow error/crash */
1064 					ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
1065 					return SUCCESS;
1066 				}
1067 				if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1068 					ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1069 				} else {
1070 					ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1071 				}
1072 				return SUCCESS;
1073 
1074 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1075 				if (Z_LVAL_P(op2) == 0) {
1076 					zend_error(E_WARNING, "Division by zero");
1077 					ZVAL_BOOL(result, 0);
1078 					return FAILURE;			/* division by zero */
1079 				}
1080 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1081 				return SUCCESS;
1082 
1083 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1084 				if (Z_DVAL_P(op2) == 0) {
1085 					zend_error(E_WARNING, "Division by zero");
1086 					ZVAL_BOOL(result, 0);
1087 					return FAILURE;			/* division by zero */
1088 				}
1089 				ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1090 				return SUCCESS;
1091 
1092 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1093 				if (Z_DVAL_P(op2) == 0) {
1094 					zend_error(E_WARNING, "Division by zero");
1095 					ZVAL_BOOL(result, 0);
1096 					return FAILURE;			/* division by zero */
1097 				}
1098 				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1099 				return SUCCESS;
1100 
1101 			default:
1102 				if (!converted) {
1103 					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1104 
1105 					zendi_convert_scalar_to_number(op1, op1_copy, result);
1106 					zendi_convert_scalar_to_number(op2, op2_copy, result);
1107 					converted = 1;
1108 				} else {
1109 					zend_error(E_ERROR, "Unsupported operand types");
1110 					return FAILURE; /* unknown datatype */
1111 				}
1112 		}
1113 	}
1114 }
1115 /* }}} */
1116 
mod_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1117 ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1118 {
1119 	zval op1_copy, op2_copy;
1120 	long op1_lval;
1121 
1122 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1123 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD);
1124 
1125 		zendi_convert_to_long(op1, op1_copy, result);
1126 		op1_lval = Z_LVAL_P(op1);
1127 		zendi_convert_to_long(op2, op2_copy, result);
1128 	} else {
1129 		op1_lval = Z_LVAL_P(op1);
1130 	}
1131 
1132 	if (Z_LVAL_P(op2) == 0) {
1133 		zend_error(E_WARNING, "Division by zero");
1134 		ZVAL_BOOL(result, 0);
1135 		return FAILURE;			/* modulus by zero */
1136 	}
1137 
1138 	if (Z_LVAL_P(op2) == -1) {
1139 		/* Prevent overflow error/crash if op1==LONG_MIN */
1140 		ZVAL_LONG(result, 0);
1141 		return SUCCESS;
1142 	}
1143 
1144 	ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
1145 	return SUCCESS;
1146 }
1147 /* }}} */
1148 
boolean_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1149 ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1150 {
1151 	zval op1_copy, op2_copy;
1152 	long op1_lval;
1153 
1154 	if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) {
1155 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR);
1156 
1157 		zendi_convert_to_boolean(op1, op1_copy, result);
1158 		op1_lval = Z_LVAL_P(op1);
1159 		zendi_convert_to_boolean(op2, op2_copy, result);
1160 	} else {
1161 		op1_lval = Z_LVAL_P(op1);
1162 	}
1163 
1164 	ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1165 	return SUCCESS;
1166 }
1167 /* }}} */
1168 
boolean_not_function(zval * result,zval * op1 TSRMLS_DC)1169 ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1170 {
1171 	zval op1_copy;
1172 
1173 	if (Z_TYPE_P(op1) != IS_BOOL) {
1174 		ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1175 
1176 		zendi_convert_to_boolean(op1, op1_copy, result);
1177 	}
1178 
1179 	ZVAL_BOOL(result, !Z_LVAL_P(op1));
1180 	return SUCCESS;
1181 }
1182 /* }}} */
1183 
bitwise_not_function(zval * result,zval * op1 TSRMLS_DC)1184 ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1185 {
1186 
1187 	switch (Z_TYPE_P(op1)) {
1188 		case IS_LONG:
1189 			ZVAL_LONG(result, ~Z_LVAL_P(op1));
1190 			return SUCCESS;
1191 		case IS_DOUBLE:
1192 			ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1193 			return SUCCESS;
1194 		case IS_STRING: {
1195 			int i;
1196 			zval op1_copy = *op1;
1197 
1198 			Z_TYPE_P(result) = IS_STRING;
1199 			Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy));
1200 			Z_STRLEN_P(result) = Z_STRLEN(op1_copy);
1201 			for (i = 0; i < Z_STRLEN(op1_copy); i++) {
1202 				Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i];
1203 			}
1204 			return SUCCESS;
1205 		}
1206 		default:
1207 			ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1208 
1209 			zend_error(E_ERROR, "Unsupported operand types");
1210 			return FAILURE;
1211 	}
1212 }
1213 /* }}} */
1214 
bitwise_or_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1215 ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1216 {
1217 	zval op1_copy, op2_copy;
1218 	long op1_lval;
1219 
1220 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1221 		zval *longer, *shorter;
1222 		char *result_str;
1223 		int i, result_len;
1224 
1225 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1226 			longer = op1;
1227 			shorter = op2;
1228 		} else {
1229 			longer = op2;
1230 			shorter = op1;
1231 		}
1232 
1233 		Z_TYPE_P(result) = IS_STRING;
1234 		result_len = Z_STRLEN_P(longer);
1235 		result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1236 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1237 			result_str[i] |= Z_STRVAL_P(shorter)[i];
1238 		}
1239 		if (result==op1) {
1240 			str_efree(Z_STRVAL_P(result));
1241 		}
1242 		Z_STRVAL_P(result) = result_str;
1243 		Z_STRLEN_P(result) = result_len;
1244 		return SUCCESS;
1245 	}
1246 
1247 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1248 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR);
1249 
1250 		zendi_convert_to_long(op1, op1_copy, result);
1251 		op1_lval = Z_LVAL_P(op1);
1252 		zendi_convert_to_long(op2, op2_copy, result);
1253 	} else {
1254 		op1_lval = Z_LVAL_P(op1);
1255 	}
1256 
1257 	ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1258 	return SUCCESS;
1259 }
1260 /* }}} */
1261 
bitwise_and_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1262 ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1263 {
1264 	zval op1_copy, op2_copy;
1265 	long op1_lval;
1266 
1267 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1268 		zval *longer, *shorter;
1269 		char *result_str;
1270 		int i, result_len;
1271 
1272 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1273 			longer = op1;
1274 			shorter = op2;
1275 		} else {
1276 			longer = op2;
1277 			shorter = op1;
1278 		}
1279 
1280 		Z_TYPE_P(result) = IS_STRING;
1281 		result_len = Z_STRLEN_P(shorter);
1282 		result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1283 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1284 			result_str[i] &= Z_STRVAL_P(longer)[i];
1285 		}
1286 		if (result==op1) {
1287 			str_efree(Z_STRVAL_P(result));
1288 		}
1289 		Z_STRVAL_P(result) = result_str;
1290 		Z_STRLEN_P(result) = result_len;
1291 		return SUCCESS;
1292 	}
1293 
1294 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1295 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND);
1296 
1297 		zendi_convert_to_long(op1, op1_copy, result);
1298 		op1_lval = Z_LVAL_P(op1);
1299 		zendi_convert_to_long(op2, op2_copy, result);
1300 	} else {
1301 		op1_lval = Z_LVAL_P(op1);
1302 	}
1303 
1304 	ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1305 	return SUCCESS;
1306 }
1307 /* }}} */
1308 
bitwise_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1309 ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1310 {
1311 	zval op1_copy, op2_copy;
1312 	long op1_lval;
1313 
1314 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1315 		zval *longer, *shorter;
1316 		char *result_str;
1317 		int i, result_len;
1318 
1319 		if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1320 			longer = op1;
1321 			shorter = op2;
1322 		} else {
1323 			longer = op2;
1324 			shorter = op1;
1325 		}
1326 
1327 		Z_TYPE_P(result) = IS_STRING;
1328 		result_len = Z_STRLEN_P(shorter);
1329 		result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1330 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1331 			result_str[i] ^= Z_STRVAL_P(longer)[i];
1332 		}
1333 		if (result==op1) {
1334 			str_efree(Z_STRVAL_P(result));
1335 		}
1336 		Z_STRVAL_P(result) = result_str;
1337 		Z_STRLEN_P(result) = result_len;
1338 		return SUCCESS;
1339 	}
1340 
1341 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1342 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR);
1343 
1344 		zendi_convert_to_long(op1, op1_copy, result);
1345 		op1_lval = Z_LVAL_P(op1);
1346 		zendi_convert_to_long(op2, op2_copy, result);
1347 	} else {
1348 		op1_lval = Z_LVAL_P(op1);
1349 	}
1350 
1351 	ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1352 	return SUCCESS;
1353 }
1354 /* }}} */
1355 
shift_left_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1356 ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1357 {
1358 	zval op1_copy, op2_copy;
1359 	long op1_lval;
1360 
1361 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1362 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL);
1363 
1364 		zendi_convert_to_long(op1, op1_copy, result);
1365 		op1_lval = Z_LVAL_P(op1);
1366 		zendi_convert_to_long(op2, op2_copy, result);
1367 	} else {
1368 		op1_lval = Z_LVAL_P(op1);
1369 	}
1370 
1371 	ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1372 	return SUCCESS;
1373 }
1374 /* }}} */
1375 
shift_right_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1376 ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1377 {
1378 	zval op1_copy, op2_copy;
1379 	long op1_lval;
1380 
1381 	if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1382 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR);
1383 
1384 		zendi_convert_to_long(op1, op1_copy, result);
1385 		op1_lval = Z_LVAL_P(op1);
1386 		zendi_convert_to_long(op2, op2_copy, result);
1387 	} else {
1388 		op1_lval = Z_LVAL_P(op1);
1389 	}
1390 
1391 	ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1392 	return SUCCESS;
1393 }
1394 /* }}} */
1395 
1396 /* must support result==op1 */
add_char_to_string(zval * result,const zval * op1,const zval * op2)1397 ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1398 {
1399 	int length = Z_STRLEN_P(op1) + 1;
1400 	char *buf;
1401 
1402 	if (UNEXPECTED(length < 0)) {
1403 		zend_error(E_ERROR, "String size overflow");
1404 	}
1405 
1406 	buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1407 
1408 	buf[length - 1] = (char) Z_LVAL_P(op2);
1409 	buf[length] = 0;
1410 	ZVAL_STRINGL(result, buf, length, 0);
1411 	return SUCCESS;
1412 }
1413 /* }}} */
1414 
1415 /* must support result==op1 */
add_string_to_string(zval * result,const zval * op1,const zval * op2)1416 ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1417 {
1418 	int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1419 	char *buf;
1420 
1421 	if (UNEXPECTED(length < 0)) {
1422 		zend_error(E_ERROR, "String size overflow");
1423 	}
1424 
1425 	buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1426 
1427 	memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1428 	buf[length] = 0;
1429 	ZVAL_STRINGL(result, buf, length, 0);
1430 	return SUCCESS;
1431 }
1432 /* }}} */
1433 
concat_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1434 ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1435 {
1436 	zval op1_copy, op2_copy;
1437 	int use_copy1 = 0, use_copy2 = 0;
1438 
1439 	if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) {
1440 		ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1441 
1442 		if (Z_TYPE_P(op1) != IS_STRING) {
1443 			zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1444 		}
1445 		if (Z_TYPE_P(op2) != IS_STRING) {
1446 			zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1447 		}
1448 	}
1449 
1450 	if (use_copy1) {
1451 		/* We have created a converted copy of op1. Therefore, op1 won't become the result so
1452 		 * we have to free it.
1453 		 */
1454 		if (result == op1) {
1455 			zval_dtor(op1);
1456 		}
1457 		op1 = &op1_copy;
1458 	}
1459 	if (use_copy2) {
1460 		op2 = &op2_copy;
1461 	}
1462 	if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) {	/* special case, perform operations on result */
1463 		uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1464 
1465 		if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1466 			efree(Z_STRVAL_P(result));
1467 			ZVAL_EMPTY_STRING(result);
1468 			zend_error(E_ERROR, "String size overflow");
1469 		}
1470 
1471 		Z_STRVAL_P(result) = safe_erealloc(Z_STRVAL_P(result), res_len, 1, 1);
1472 
1473 		memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1474 		Z_STRVAL_P(result)[res_len]=0;
1475 		Z_STRLEN_P(result) = res_len;
1476 	} else {
1477 		int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1478 		char *buf;
1479 
1480 		if (Z_STRLEN_P(op1) < 0 || Z_STRLEN_P(op2) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1481 			zend_error(E_ERROR, "String size overflow");
1482 		}
1483 		buf = (char *) safe_emalloc(length, 1, 1);
1484 
1485 		memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1486 		memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1487 		buf[length] = 0;
1488 		ZVAL_STRINGL(result, buf, length, 0);
1489 	}
1490 	if (use_copy1) {
1491 		zval_dtor(op1);
1492 	}
1493 	if (use_copy2) {
1494 		zval_dtor(op2);
1495 	}
1496 	return SUCCESS;
1497 }
1498 /* }}} */
1499 
string_compare_function_ex(zval * result,zval * op1,zval * op2,zend_bool case_insensitive TSRMLS_DC)1500 ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1501 {
1502 	zval op1_copy, op2_copy;
1503 	int use_copy1 = 0, use_copy2 = 0;
1504 
1505 	if (Z_TYPE_P(op1) != IS_STRING) {
1506 		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1507 	}
1508 	if (Z_TYPE_P(op2) != IS_STRING) {
1509 		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1510 	}
1511 
1512 	if (use_copy1) {
1513 		op1 = &op1_copy;
1514 	}
1515 	if (use_copy2) {
1516 		op2 = &op2_copy;
1517 	}
1518 
1519 	if (case_insensitive) {
1520 		ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1521 	} else {
1522 		ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1523 	}
1524 
1525 	if (use_copy1) {
1526 		zval_dtor(op1);
1527 	}
1528 	if (use_copy2) {
1529 		zval_dtor(op2);
1530 	}
1531 	return SUCCESS;
1532 }
1533 /* }}} */
1534 
string_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1535 ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1536 {
1537 	return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1538 }
1539 /* }}} */
1540 
string_case_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1541 ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1542 {
1543 	return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1544 }
1545 /* }}} */
1546 
1547 #if HAVE_STRCOLL
string_locale_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1548 ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1549 {
1550 	zval op1_copy, op2_copy;
1551 	int use_copy1 = 0, use_copy2 = 0;
1552 
1553 	if (Z_TYPE_P(op1) != IS_STRING) {
1554 		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1555 	}
1556 	if (Z_TYPE_P(op2) != IS_STRING) {
1557 		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1558 	}
1559 
1560 	if (use_copy1) {
1561 		op1 = &op1_copy;
1562 	}
1563 	if (use_copy2) {
1564 		op2 = &op2_copy;
1565 	}
1566 
1567 	ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1568 
1569 	if (use_copy1) {
1570 		zval_dtor(op1);
1571 	}
1572 	if (use_copy2) {
1573 		zval_dtor(op2);
1574 	}
1575 	return SUCCESS;
1576 }
1577 /* }}} */
1578 #endif
1579 
numeric_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1580 ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1581 {
1582 	zval op1_copy, op2_copy;
1583 
1584 	op1_copy = *op1;
1585 	zval_copy_ctor(&op1_copy);
1586 
1587 	op2_copy = *op2;
1588 	zval_copy_ctor(&op2_copy);
1589 
1590 	convert_to_double(&op1_copy);
1591 	convert_to_double(&op2_copy);
1592 
1593 	ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1594 
1595 	return SUCCESS;
1596 }
1597 /* }}} */
1598 
zend_free_obj_get_result(zval * op TSRMLS_DC)1599 static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1600 {
1601 	if (Z_REFCOUNT_P(op) == 0) {
1602 		GC_REMOVE_ZVAL_FROM_BUFFER(op);
1603 		zval_dtor(op);
1604 		FREE_ZVAL(op);
1605 	} else {
1606 		zval_ptr_dtor(&op);
1607 	}
1608 }
1609 /* }}} */
1610 
compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1611 ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1612 {
1613 	int ret;
1614 	int converted = 0;
1615 	zval op1_copy, op2_copy;
1616 	zval *op_free;
1617 
1618 	while (1) {
1619 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1620 			case TYPE_PAIR(IS_LONG, IS_LONG):
1621 				ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1622 				return SUCCESS;
1623 
1624 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1625 				Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1626 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1627 				return SUCCESS;
1628 
1629 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1630 				Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1631 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1632 				return SUCCESS;
1633 
1634 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1635 				if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1636 					ZVAL_LONG(result, 0);
1637 				} else {
1638 					Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1639 					ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1640 				}
1641 				return SUCCESS;
1642 
1643 			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1644 				zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1645 				return SUCCESS;
1646 
1647 			case TYPE_PAIR(IS_NULL, IS_NULL):
1648 				ZVAL_LONG(result, 0);
1649 				return SUCCESS;
1650 
1651 			case TYPE_PAIR(IS_NULL, IS_BOOL):
1652 				ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1653 				return SUCCESS;
1654 
1655 			case TYPE_PAIR(IS_BOOL, IS_NULL):
1656 				ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1657 				return SUCCESS;
1658 
1659 			case TYPE_PAIR(IS_BOOL, IS_BOOL):
1660 				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1661 				return SUCCESS;
1662 
1663 			case TYPE_PAIR(IS_STRING, IS_STRING):
1664 				zendi_smart_strcmp(result, op1, op2);
1665 				return SUCCESS;
1666 
1667 			case TYPE_PAIR(IS_NULL, IS_STRING):
1668 				ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1669 				return SUCCESS;
1670 
1671 			case TYPE_PAIR(IS_STRING, IS_NULL):
1672 				ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1673 				return SUCCESS;
1674 
1675 			case TYPE_PAIR(IS_OBJECT, IS_NULL):
1676 				ZVAL_LONG(result, 1);
1677 				return SUCCESS;
1678 
1679 			case TYPE_PAIR(IS_NULL, IS_OBJECT):
1680 				ZVAL_LONG(result, -1);
1681 				return SUCCESS;
1682 
1683 			default:
1684 				if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1685 					return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
1686 				} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1687 					return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
1688 				}
1689 
1690 				if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1691 					if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1692 						/* object handles are identical, apparently this is the same object */
1693 						ZVAL_LONG(result, 0);
1694 						return SUCCESS;
1695 					}
1696 					if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1697 						ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
1698 						return SUCCESS;
1699 					}
1700 				}
1701 				if (Z_TYPE_P(op1) == IS_OBJECT) {
1702 					if (Z_OBJ_HT_P(op1)->get) {
1703 						op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1704 						ret = compare_function(result, op_free, op2 TSRMLS_CC);
1705 						zend_free_obj_get_result(op_free TSRMLS_CC);
1706 						return ret;
1707 					} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1708 						ALLOC_INIT_ZVAL(op_free);
1709 						if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1710 							ZVAL_LONG(result, 1);
1711 							zend_free_obj_get_result(op_free TSRMLS_CC);
1712 							return SUCCESS;
1713 						}
1714 						ret = compare_function(result, op_free, op2 TSRMLS_CC);
1715 						zend_free_obj_get_result(op_free TSRMLS_CC);
1716 						return ret;
1717 					}
1718 				}
1719 				if (Z_TYPE_P(op2) == IS_OBJECT) {
1720 					if (Z_OBJ_HT_P(op2)->get) {
1721 						op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1722 						ret = compare_function(result, op1, op_free TSRMLS_CC);
1723 						zend_free_obj_get_result(op_free TSRMLS_CC);
1724 						return ret;
1725 					} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1726 						ALLOC_INIT_ZVAL(op_free);
1727 						if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {
1728 							ZVAL_LONG(result, -1);
1729 							zend_free_obj_get_result(op_free TSRMLS_CC);
1730 							return SUCCESS;
1731 						}
1732 						ret = compare_function(result, op1, op_free TSRMLS_CC);
1733 						zend_free_obj_get_result(op_free TSRMLS_CC);
1734 						return ret;
1735 					} else if (Z_TYPE_P(op1) == IS_OBJECT) {
1736 						ZVAL_LONG(result, 1);
1737 						return SUCCESS;
1738 					}
1739 				}
1740 				if (!converted) {
1741 					if (Z_TYPE_P(op1) == IS_NULL) {
1742 						zendi_convert_to_boolean(op2, op2_copy, result);
1743 						ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1744 						return SUCCESS;
1745 					} else if (Z_TYPE_P(op2) == IS_NULL) {
1746 						zendi_convert_to_boolean(op1, op1_copy, result);
1747 						ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1748 						return SUCCESS;
1749 					} else if (Z_TYPE_P(op1) == IS_BOOL) {
1750 						zendi_convert_to_boolean(op2, op2_copy, result);
1751 						ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1752 						return SUCCESS;
1753 					} else if (Z_TYPE_P(op2) == IS_BOOL) {
1754 						zendi_convert_to_boolean(op1, op1_copy, result);
1755 						ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1756 						return SUCCESS;
1757 					} else {
1758 						zendi_convert_scalar_to_number(op1, op1_copy, result);
1759 						zendi_convert_scalar_to_number(op2, op2_copy, result);
1760 						converted = 1;
1761 					}
1762 				} else if (Z_TYPE_P(op1)==IS_ARRAY) {
1763 					ZVAL_LONG(result, 1);
1764 					return SUCCESS;
1765 				} else if (Z_TYPE_P(op2)==IS_ARRAY) {
1766 					ZVAL_LONG(result, -1);
1767 					return SUCCESS;
1768 				} else if (Z_TYPE_P(op1)==IS_OBJECT) {
1769 					ZVAL_LONG(result, 1);
1770 					return SUCCESS;
1771 				} else if (Z_TYPE_P(op2)==IS_OBJECT) {
1772 					ZVAL_LONG(result, -1);
1773 					return SUCCESS;
1774 				} else {
1775 					ZVAL_LONG(result, 0);
1776 					return FAILURE;
1777 				}
1778 		}
1779 	}
1780 }
1781 /* }}} */
1782 
hash_zval_identical_function(const zval ** z1,const zval ** z2)1783 static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1784 {
1785 	zval result;
1786 	TSRMLS_FETCH();
1787 
1788 	/* is_identical_function() returns 1 in case of identity and 0 in case
1789 	 * of a difference;
1790 	 * whereas this comparison function is expected to return 0 on identity,
1791 	 * and non zero otherwise.
1792 	 */
1793 	if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1794 		return 1;
1795 	}
1796 	return !Z_LVAL(result);
1797 }
1798 /* }}} */
1799 
is_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1800 ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1801 {
1802 	Z_TYPE_P(result) = IS_BOOL;
1803 	if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1804 		Z_LVAL_P(result) = 0;
1805 		return SUCCESS;
1806 	}
1807 	switch (Z_TYPE_P(op1)) {
1808 		case IS_NULL:
1809 			Z_LVAL_P(result) = 1;
1810 			break;
1811 		case IS_BOOL:
1812 		case IS_LONG:
1813 		case IS_RESOURCE:
1814 			Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1815 			break;
1816 		case IS_DOUBLE:
1817 			Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1818 			break;
1819 		case IS_STRING:
1820 			Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1821 				&& (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1822 			break;
1823 		case IS_ARRAY:
1824 			Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1825 				zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1826 			break;
1827 		case IS_OBJECT:
1828 			if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1829 				Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1830 			} else {
1831 				Z_LVAL_P(result) = 0;
1832 			}
1833 			break;
1834 		default:
1835 			Z_LVAL_P(result) = 0;
1836 			return FAILURE;
1837 	}
1838 	return SUCCESS;
1839 }
1840 /* }}} */
1841 
is_not_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1842 ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1843 {
1844 	if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1845 		return FAILURE;
1846 	}
1847 	Z_LVAL_P(result) = !Z_LVAL_P(result);
1848 	return SUCCESS;
1849 }
1850 /* }}} */
1851 
is_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1852 ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1853 {
1854 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1855 		return FAILURE;
1856 	}
1857 	ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1858 	return SUCCESS;
1859 }
1860 /* }}} */
1861 
is_not_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1862 ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1863 {
1864 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1865 		return FAILURE;
1866 	}
1867 	ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1868 	return SUCCESS;
1869 }
1870 /* }}} */
1871 
is_smaller_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1872 ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1873 {
1874 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1875 		return FAILURE;
1876 	}
1877 	ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1878 	return SUCCESS;
1879 }
1880 /* }}} */
1881 
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1882 ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1883 {
1884 	if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1885 		return FAILURE;
1886 	}
1887 	ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1888 	return SUCCESS;
1889 }
1890 /* }}} */
1891 
instanceof_function_ex(const zend_class_entry * instance_ce,const zend_class_entry * ce,zend_bool interfaces_only TSRMLS_DC)1892 ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1893 {
1894 	zend_uint i;
1895 
1896 	for (i=0; i<instance_ce->num_interfaces; i++) {
1897 		if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1898 			return 1;
1899 		}
1900 	}
1901 	if (!interfaces_only) {
1902 		while (instance_ce) {
1903 			if (instance_ce == ce) {
1904 				return 1;
1905 			}
1906 			instance_ce = instance_ce->parent;
1907 		}
1908 	}
1909 
1910 	return 0;
1911 }
1912 /* }}} */
1913 
instanceof_function(const zend_class_entry * instance_ce,const zend_class_entry * ce TSRMLS_DC)1914 ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1915 {
1916 	return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1917 }
1918 /* }}} */
1919 
1920 #define LOWER_CASE 1
1921 #define UPPER_CASE 2
1922 #define NUMERIC 3
1923 
increment_string(zval * str)1924 static void increment_string(zval *str) /* {{{ */
1925 {
1926 	int carry=0;
1927 	int pos=Z_STRLEN_P(str)-1;
1928 	char *s=Z_STRVAL_P(str);
1929 	char *t;
1930 	int last=0; /* Shut up the compiler warning */
1931 	int ch;
1932 
1933 	if (Z_STRLEN_P(str) == 0) {
1934 		str_efree(Z_STRVAL_P(str));
1935 		Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1936 		Z_STRLEN_P(str) = 1;
1937 		return;
1938 	}
1939 
1940 	if (IS_INTERNED(s)) {
1941 		Z_STRVAL_P(str) = s = estrndup(s, Z_STRLEN_P(str));
1942 	}
1943 
1944 	while (pos >= 0) {
1945 		ch = s[pos];
1946 		if (ch >= 'a' && ch <= 'z') {
1947 			if (ch == 'z') {
1948 				s[pos] = 'a';
1949 				carry=1;
1950 			} else {
1951 				s[pos]++;
1952 				carry=0;
1953 			}
1954 			last=LOWER_CASE;
1955 		} else if (ch >= 'A' && ch <= 'Z') {
1956 			if (ch == 'Z') {
1957 				s[pos] = 'A';
1958 				carry=1;
1959 			} else {
1960 				s[pos]++;
1961 				carry=0;
1962 			}
1963 			last=UPPER_CASE;
1964 		} else if (ch >= '0' && ch <= '9') {
1965 			if (ch == '9') {
1966 				s[pos] = '0';
1967 				carry=1;
1968 			} else {
1969 				s[pos]++;
1970 				carry=0;
1971 			}
1972 			last = NUMERIC;
1973 		} else {
1974 			carry=0;
1975 			break;
1976 		}
1977 		if (carry == 0) {
1978 			break;
1979 		}
1980 		pos--;
1981 	}
1982 
1983 	if (carry) {
1984 		t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1985 		memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1986 		Z_STRLEN_P(str)++;
1987 		t[Z_STRLEN_P(str)] = '\0';
1988 		switch (last) {
1989 			case NUMERIC:
1990 				t[0] = '1';
1991 				break;
1992 			case UPPER_CASE:
1993 				t[0] = 'A';
1994 				break;
1995 			case LOWER_CASE:
1996 				t[0] = 'a';
1997 				break;
1998 		}
1999 		str_efree(Z_STRVAL_P(str));
2000 		Z_STRVAL_P(str) = t;
2001 	}
2002 }
2003 /* }}} */
2004 
increment_function(zval * op1)2005 ZEND_API int increment_function(zval *op1) /* {{{ */
2006 {
2007 	switch (Z_TYPE_P(op1)) {
2008 		case IS_LONG:
2009 			if (Z_LVAL_P(op1) == LONG_MAX) {
2010 				/* switch to double */
2011 				double d = (double)Z_LVAL_P(op1);
2012 				ZVAL_DOUBLE(op1, d+1);
2013 			} else {
2014 			Z_LVAL_P(op1)++;
2015 			}
2016 			break;
2017 		case IS_DOUBLE:
2018 			Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2019 			break;
2020 		case IS_NULL:
2021 			ZVAL_LONG(op1, 1);
2022 			break;
2023 		case IS_STRING: {
2024 				long lval;
2025 				double dval;
2026 
2027 				switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2028 					case IS_LONG:
2029 						str_efree(Z_STRVAL_P(op1));
2030 						if (lval == LONG_MAX) {
2031 							/* switch to double */
2032 							double d = (double)lval;
2033 							ZVAL_DOUBLE(op1, d+1);
2034 						} else {
2035 							ZVAL_LONG(op1, lval+1);
2036 						}
2037 						break;
2038 					case IS_DOUBLE:
2039 						str_efree(Z_STRVAL_P(op1));
2040 						ZVAL_DOUBLE(op1, dval+1);
2041 						break;
2042 					default:
2043 						/* Perl style string increment */
2044 						increment_string(op1);
2045 						break;
2046 				}
2047 			}
2048 			break;
2049 		case IS_OBJECT:
2050 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2051 				zval *op2;
2052 				int res;
2053 				TSRMLS_FETCH();
2054 
2055 				MAKE_STD_ZVAL(op2);
2056 				ZVAL_LONG(op2, 1);
2057 				res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
2058 				zval_ptr_dtor(&op2);
2059 
2060 				return res;
2061 			}
2062 			return FAILURE;
2063 		default:
2064 			return FAILURE;
2065 	}
2066 	return SUCCESS;
2067 }
2068 /* }}} */
2069 
decrement_function(zval * op1)2070 ZEND_API int decrement_function(zval *op1) /* {{{ */
2071 {
2072 	long lval;
2073 	double dval;
2074 
2075 	switch (Z_TYPE_P(op1)) {
2076 		case IS_LONG:
2077 			if (Z_LVAL_P(op1) == LONG_MIN) {
2078 				double d = (double)Z_LVAL_P(op1);
2079 				ZVAL_DOUBLE(op1, d-1);
2080 			} else {
2081 			Z_LVAL_P(op1)--;
2082 			}
2083 			break;
2084 		case IS_DOUBLE:
2085 			Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2086 			break;
2087 		case IS_STRING:		/* Like perl we only support string increment */
2088 			if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2089 				str_efree(Z_STRVAL_P(op1));
2090 				ZVAL_LONG(op1, -1);
2091 				break;
2092 			}
2093 			switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2094 				case IS_LONG:
2095 					str_efree(Z_STRVAL_P(op1));
2096 					if (lval == LONG_MIN) {
2097 						double d = (double)lval;
2098 						ZVAL_DOUBLE(op1, d-1);
2099 					} else {
2100 						ZVAL_LONG(op1, lval-1);
2101 					}
2102 					break;
2103 				case IS_DOUBLE:
2104 					str_efree(Z_STRVAL_P(op1));
2105 					ZVAL_DOUBLE(op1, dval - 1);
2106 					break;
2107 			}
2108 			break;
2109 		case IS_OBJECT:
2110 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2111 				zval *op2;
2112 				int res;
2113 				TSRMLS_FETCH();
2114 
2115 				MAKE_STD_ZVAL(op2);
2116 				ZVAL_LONG(op2, 1);
2117 				res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
2118 				zval_ptr_dtor(&op2);
2119 
2120 				return res;
2121 			}
2122 			return FAILURE;
2123 		default:
2124 			return FAILURE;
2125 	}
2126 
2127 	return SUCCESS;
2128 }
2129 /* }}} */
2130 
zval_is_true(zval * op)2131 ZEND_API int zval_is_true(zval *op) /* {{{ */
2132 {
2133 	convert_to_boolean(op);
2134 	return (Z_LVAL_P(op) ? 1 : 0);
2135 }
2136 /* }}} */
2137 
2138 #ifdef ZEND_USE_TOLOWER_L
zend_update_current_locale(void)2139 ZEND_API void zend_update_current_locale(void) /* {{{ */
2140 {
2141 	current_locale = _get_current_locale();
2142 }
2143 /* }}} */
2144 #endif
2145 
zend_str_tolower_copy(char * dest,const char * source,unsigned int length)2146 ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
2147 {
2148 	register unsigned char *str = (unsigned char*)source;
2149 	register unsigned char *result = (unsigned char*)dest;
2150 	register unsigned char *end = str + length;
2151 
2152 	while (str < end) {
2153 		*result++ = zend_tolower_ascii(*str++);
2154 	}
2155 	*result = '\0';
2156 
2157 	return dest;
2158 }
2159 /* }}} */
2160 
zend_str_tolower_dup(const char * source,unsigned int length)2161 ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
2162 {
2163 	return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2164 }
2165 /* }}} */
2166 
zend_str_tolower(char * str,unsigned int length)2167 ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
2168 {
2169 	register unsigned char *p = (unsigned char*)str;
2170 	register unsigned char *end = p + length;
2171 
2172 	while (p < end) {
2173 		*p = zend_tolower_ascii(*p);
2174 		p++;
2175 	}
2176 }
2177 /* }}} */
2178 
zend_binary_strcmp(const char * s1,uint len1,const char * s2,uint len2)2179 ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2180 {
2181 	int retval;
2182 
2183 	if (s1 == s2) {
2184 		return 0;
2185 	}
2186 	retval = memcmp(s1, s2, MIN(len1, len2));
2187 	if (!retval) {
2188 		return (len1 - len2);
2189 	} else {
2190 		return retval;
2191 	}
2192 }
2193 /* }}} */
2194 
zend_binary_strncmp(const char * s1,uint len1,const char * s2,uint len2,uint length)2195 ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2196 {
2197 	int retval;
2198 
2199 	if (s1 == s2) {
2200 		return 0;
2201 	}
2202 	retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2203 	if (!retval) {
2204 		return (MIN(length, len1) - MIN(length, len2));
2205 	} else {
2206 		return retval;
2207 	}
2208 }
2209 /* }}} */
2210 
zend_binary_strcasecmp(const char * s1,uint len1,const char * s2,uint len2)2211 ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2212 {
2213 	int len;
2214 	int c1, c2;
2215 
2216 	if (s1 == s2) {
2217 		return 0;
2218 	}
2219 
2220 	len = MIN(len1, len2);
2221 	while (len--) {
2222 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2223 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2224 		if (c1 != c2) {
2225 			return c1 - c2;
2226 		}
2227 	}
2228 
2229 	return len1 - len2;
2230 }
2231 /* }}} */
2232 
zend_binary_strncasecmp(const char * s1,uint len1,const char * s2,uint len2,uint length)2233 ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2234 {
2235 	int len;
2236 	int c1, c2;
2237 
2238 	if (s1 == s2) {
2239 		return 0;
2240 	}
2241 	len = MIN(length, MIN(len1, len2));
2242 	while (len--) {
2243 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2244 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2245 		if (c1 != c2) {
2246 			return c1 - c2;
2247 		}
2248 	}
2249 
2250 	return MIN(length, len1) - MIN(length, len2);
2251 }
2252 /* }}} */
2253 
zend_binary_strcasecmp_l(const char * s1,uint len1,const char * s2,uint len2)2254 ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2255 {
2256 	int len;
2257 	int c1, c2;
2258 
2259 	if (s1 == s2) {
2260 		return 0;
2261 	}
2262 
2263 	len = MIN(len1, len2);
2264 	while (len--) {
2265 		c1 = zend_tolower((int)*(unsigned char *)s1++);
2266 		c2 = zend_tolower((int)*(unsigned char *)s2++);
2267 		if (c1 != c2) {
2268 			return c1 - c2;
2269 		}
2270 	}
2271 
2272 	return len1 - len2;
2273 }
2274 /* }}} */
2275 
zend_binary_strncasecmp_l(const char * s1,uint len1,const char * s2,uint len2,uint length)2276 ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2277 {
2278 	int len;
2279 	int c1, c2;
2280 
2281 	if (s1 == s2) {
2282 		return 0;
2283 	}
2284 	len = MIN(length, MIN(len1, len2));
2285 	while (len--) {
2286 		c1 = zend_tolower((int)*(unsigned char *)s1++);
2287 		c2 = zend_tolower((int)*(unsigned char *)s2++);
2288 		if (c1 != c2) {
2289 			return c1 - c2;
2290 		}
2291 	}
2292 
2293 	return MIN(length, len1) - MIN(length, len2);
2294 }
2295 /* }}} */
2296 
zend_binary_zval_strcmp(zval * s1,zval * s2)2297 ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2298 {
2299 	return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2300 }
2301 /* }}} */
2302 
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)2303 ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2304 {
2305 	return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2306 }
2307 /* }}} */
2308 
zend_binary_zval_strcasecmp(zval * s1,zval * s2)2309 ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2310 {
2311 	return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2312 }
2313 /* }}} */
2314 
zend_binary_zval_strncasecmp(zval * s1,zval * s2,zval * s3)2315 ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2316 {
2317 	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));
2318 }
2319 /* }}} */
2320 
zendi_smart_strcmp(zval * result,zval * s1,zval * s2)2321 ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2322 {
2323 	int ret1, ret2;
2324 	int oflow1, oflow2;
2325 	long lval1 = 0, lval2 = 0;
2326 	double dval1 = 0.0, dval2 = 0.0;
2327 
2328 	if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2329 		(ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2330 #if ULONG_MAX == 0xFFFFFFFF
2331 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2332 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2333 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
2334 #else
2335 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2336 #endif
2337 			/* both values are integers overflown to the same side, and the
2338 			 * double comparison may have resulted in crucial accuracy lost */
2339 			goto string_cmp;
2340 		}
2341 		if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2342 			if (ret1!=IS_DOUBLE) {
2343 				if (oflow2) {
2344 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2345 					ZVAL_LONG(result, -1 * oflow2);
2346 					return;
2347 				}
2348 				dval1 = (double) lval1;
2349 			} else if (ret2!=IS_DOUBLE) {
2350 				if (oflow1) {
2351 					ZVAL_LONG(result, oflow1);
2352 					return;
2353 				}
2354 				dval2 = (double) lval2;
2355 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
2356 				/* Both values overflowed and have the same sign,
2357 				 * so a numeric comparison would be inaccurate */
2358 				goto string_cmp;
2359 			}
2360 			Z_DVAL_P(result) = dval1 - dval2;
2361 			ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2362 		} else { /* they both have to be long's */
2363 			ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2364 		}
2365 	} else {
2366 string_cmp:
2367 		Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2368 		ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2369 	}
2370 }
2371 /* }}} */
2372 
2373 static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2374 {
2375 	zval result;
2376 
2377 	if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2378 		return 1;
2379 	}
2380 	return Z_LVAL(result);
2381 }
2382 /* }}} */
2383 
2384 ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2385 {
2386 	return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2387 }
2388 /* }}} */
2389 
2390 ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2391 {
2392 	ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2393 }
2394 /* }}} */
2395 
2396 ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2397 {
2398 	zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2399 }
2400 /* }}} */
2401 
2402 ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2403 {
2404 	Z_TYPE_P(result) = IS_LONG;
2405 
2406 	if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2407 		Z_LVAL_P(result) = 0;
2408 		return;
2409 	}
2410 
2411 	if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2412 		Z_LVAL_P(result) = 1;
2413 	} else {
2414 		Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2415 	}
2416 }
2417 /* }}} */
2418 
2419 ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2420 {
2421 	TSRMLS_FETCH();
2422 
2423 	Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2424 }
2425 /* }}} */
2426 
2427 /*
2428  * Local variables:
2429  * tab-width: 4
2430  * c-basic-offset: 4
2431  * indent-tabs-mode: t
2432  * End:
2433  */
2434