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