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