1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   |          Dmitry Stogov <dmitry@zend.com>                             |
18   +----------------------------------------------------------------------+
19*/
20
21/* $Id$ */
22
23#include <ctype.h>
24
25#include "zend.h"
26#include "zend_operators.h"
27#include "zend_variables.h"
28#include "zend_globals.h"
29#include "zend_list.h"
30#include "zend_API.h"
31#include "zend_strtod.h"
32#include "zend_exceptions.h"
33#include "zend_closures.h"
34
35#if ZEND_USE_TOLOWER_L
36#include <locale.h>
37static _locale_t current_locale = NULL;
38/* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
39#define zend_tolower(c) _tolower_l(c, current_locale)
40#else
41#define zend_tolower(c) tolower(c)
42#endif
43
44#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
45
46static const unsigned char tolower_map[256] = {
470x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
480x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
490x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
500x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
510x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
520x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
530x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
540x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
550x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
560x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
570xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
580xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
590xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
600xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
610xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
620xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
63};
64
65#define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
66
67/**
68 * Functions using locale lowercase:
69 	 	zend_binary_strncasecmp_l
70 	 	zend_binary_strcasecmp_l
71		zend_binary_zval_strcasecmp
72		zend_binary_zval_strncasecmp
73		string_compare_function_ex
74		string_case_compare_function
75 * Functions using ascii lowercase:
76  		zend_str_tolower_copy
77		zend_str_tolower_dup
78		zend_str_tolower
79		zend_binary_strcasecmp
80		zend_binary_strncasecmp
81 */
82
83ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, int str_len) /* {{{ */
84{
85	int retval;
86
87	if (!str_len) {
88		str_len = (int)strlen(str);
89	}
90	retval = ZEND_STRTOL(str, NULL, 0);
91	if (str_len>0) {
92		switch (str[str_len-1]) {
93			case 'g':
94			case 'G':
95				retval *= 1024;
96				/* break intentionally missing */
97			case 'm':
98			case 'M':
99				retval *= 1024;
100				/* break intentionally missing */
101			case 'k':
102			case 'K':
103				retval *= 1024;
104				break;
105		}
106	}
107	return retval;
108}
109/* }}} */
110
111ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, int str_len) /* {{{ */
112{
113	zend_long retval;
114
115	if (!str_len) {
116		str_len = (int)strlen(str);
117	}
118	retval = ZEND_STRTOL(str, NULL, 0);
119	if (str_len>0) {
120		switch (str[str_len-1]) {
121			case 'g':
122			case 'G':
123				retval *= 1024;
124				/* break intentionally missing */
125			case 'm':
126			case 'M':
127				retval *= 1024;
128				/* break intentionally missing */
129			case 'k':
130			case 'K':
131				retval *= 1024;
132				break;
133		}
134	}
135	return retval;
136}
137/* }}} */
138
139void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent) /* {{{ */
140{
141try_again:
142	switch (Z_TYPE_P(op)) {
143		case IS_REFERENCE:
144			zend_unwrap_reference(op);
145			goto try_again;
146		case IS_STRING:
147			{
148				zend_string *str;
149
150				str = Z_STR_P(op);
151				if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), silent ? 1 : -1)) == 0) {
152					ZVAL_LONG(op, 0);
153					if (!silent) {
154						zend_error(E_WARNING, "A non-numeric value encountered");
155					}
156				}
157				zend_string_release(str);
158				break;
159			}
160		case IS_NULL:
161		case IS_FALSE:
162			ZVAL_LONG(op, 0);
163			break;
164		case IS_TRUE:
165			ZVAL_LONG(op, 1);
166			break;
167		case IS_RESOURCE:
168			{
169				zend_long l = Z_RES_HANDLE_P(op);
170				zval_ptr_dtor(op);
171				ZVAL_LONG(op, l);
172			}
173			break;
174		case IS_OBJECT:
175			convert_to_long_base(op, 10);
176			break;
177	}
178}
179/* }}} */
180
181ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
182{
183	_convert_scalar_to_number(op, 1);
184}
185/* }}} */
186
187/* {{{ zendi_convert_scalar_to_number */
188#define zendi_convert_scalar_to_number(op, holder, result, silent)	\
189	if (op==result) {												\
190		if (Z_TYPE_P(op) != IS_LONG) {								\
191			_convert_scalar_to_number(op, silent);				\
192		}															\
193	} else {														\
194		switch (Z_TYPE_P(op)) {										\
195			case IS_STRING:											\
196				{													\
197					if ((Z_TYPE_INFO(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), silent ? 1 : -1)) == 0) {	\
198						ZVAL_LONG(&(holder), 0);							\
199						if (!silent) {										\
200							zend_error(E_WARNING, "A non-numeric value encountered");	\
201						}													\
202					}														\
203					(op) = &(holder);										\
204					break;													\
205				}															\
206			case IS_NULL:													\
207			case IS_FALSE:													\
208				ZVAL_LONG(&(holder), 0);									\
209				(op) = &(holder);											\
210				break;														\
211			case IS_TRUE:													\
212				ZVAL_LONG(&(holder), 1);									\
213				(op) = &(holder);											\
214				break;														\
215			case IS_RESOURCE:												\
216				ZVAL_LONG(&(holder), Z_RES_HANDLE_P(op));					\
217				(op) = &(holder);											\
218				break;														\
219			case IS_OBJECT:													\
220				ZVAL_COPY(&(holder), op);										\
221				convert_to_long_base(&(holder), 10);						\
222				if (Z_TYPE(holder) == IS_LONG) {							\
223					(op) = &(holder);										\
224				}															\
225				break;														\
226		}																	\
227	}
228
229/* }}} */
230
231/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
232#define convert_object_to_type(op, dst, ctype, conv_func)									\
233	ZVAL_UNDEF(dst);																		\
234	if (Z_OBJ_HT_P(op)->cast_object) {														\
235		if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) {				\
236			zend_error(E_RECOVERABLE_ERROR,													\
237				"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
238			zend_get_type_by_const(ctype));													\
239		} 																					\
240	} else if (Z_OBJ_HT_P(op)->get) {														\
241		zval *newop = Z_OBJ_HT_P(op)->get(op, dst);								\
242		if (Z_TYPE_P(newop) != IS_OBJECT) {													\
243			/* for safety - avoid loop */													\
244			ZVAL_COPY_VALUE(dst, newop);													\
245			conv_func(dst);																	\
246		}																					\
247	}
248
249/* }}} */
250
251#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, op, op_func) \
252	do {																\
253		if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {						\
254			if (Z_ISREF_P(op1)) {										\
255				op1 = Z_REFVAL_P(op1);									\
256				if (Z_TYPE_P(op1) == IS_LONG) {							\
257					op1_lval = Z_LVAL_P(op1);							\
258					break;												\
259				}														\
260			}															\
261			ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(op, op_func);			\
262			op1_lval = _zval_get_long_func_noisy(op1);					\
263		} else {														\
264			op1_lval = Z_LVAL_P(op1);									\
265		}																\
266	} while (0);														\
267	do {																\
268		if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {						\
269			if (Z_ISREF_P(op2)) {										\
270				op2 = Z_REFVAL_P(op2);									\
271				if (Z_TYPE_P(op2) == IS_LONG) {							\
272					op2_lval = Z_LVAL_P(op2);							\
273					break;												\
274				}														\
275			}															\
276			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(op);					\
277			op2_lval = _zval_get_long_func_noisy(op2);					\
278		} else {														\
279			op2_lval = Z_LVAL_P(op2);									\
280		}																\
281	} while (0);
282
283ZEND_API void ZEND_FASTCALL convert_to_long(zval *op) /* {{{ */
284{
285	if (Z_TYPE_P(op) != IS_LONG) {
286		convert_to_long_base(op, 10);
287	}
288}
289/* }}} */
290
291ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
292{
293	zend_long tmp;
294
295try_again:
296	switch (Z_TYPE_P(op)) {
297		case IS_NULL:
298		case IS_FALSE:
299			ZVAL_LONG(op, 0);
300			break;
301		case IS_TRUE:
302			ZVAL_LONG(op, 1);
303			break;
304		case IS_RESOURCE:
305			tmp = Z_RES_HANDLE_P(op);
306			zval_ptr_dtor(op);
307			ZVAL_LONG(op, tmp);
308			break;
309		case IS_LONG:
310			break;
311		case IS_DOUBLE:
312			ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op)));
313			break;
314		case IS_STRING:
315			{
316				zend_string *str = Z_STR_P(op);
317				if (base == 10) {
318					ZVAL_LONG(op, zval_get_long(op));
319				} else {
320					ZVAL_LONG(op, ZEND_STRTOL(ZSTR_VAL(str), NULL, base));
321				}
322				zend_string_release(str);
323			}
324			break;
325		case IS_ARRAY:
326			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
327			zval_ptr_dtor(op);
328			ZVAL_LONG(op, tmp);
329			break;
330		case IS_OBJECT:
331			{
332				zval dst;
333
334				convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
335				zval_dtor(op);
336
337				if (Z_TYPE(dst) == IS_LONG) {
338					ZVAL_COPY_VALUE(op, &dst);
339				} else {
340
341					ZVAL_LONG(op, 1);
342				}
343				return;
344			}
345		case IS_REFERENCE:
346			zend_unwrap_reference(op);
347			goto try_again;
348		EMPTY_SWITCH_DEFAULT_CASE()
349	}
350}
351/* }}} */
352
353ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
354{
355	double tmp;
356
357try_again:
358	switch (Z_TYPE_P(op)) {
359		case IS_NULL:
360		case IS_FALSE:
361			ZVAL_DOUBLE(op, 0.0);
362			break;
363		case IS_TRUE:
364			ZVAL_DOUBLE(op, 1.0);
365			break;
366		case IS_RESOURCE: {
367				double d = (double) Z_RES_HANDLE_P(op);
368				zval_ptr_dtor(op);
369				ZVAL_DOUBLE(op, d);
370			}
371			break;
372		case IS_LONG:
373			ZVAL_DOUBLE(op, (double) Z_LVAL_P(op));
374			break;
375		case IS_DOUBLE:
376			break;
377		case IS_STRING:
378			{
379				zend_string *str = Z_STR_P(op);
380
381				ZVAL_DOUBLE(op, zend_strtod(ZSTR_VAL(str), NULL));
382				zend_string_release(str);
383			}
384			break;
385		case IS_ARRAY:
386			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
387			zval_ptr_dtor(op);
388			ZVAL_DOUBLE(op, tmp);
389			break;
390		case IS_OBJECT:
391			{
392				zval dst;
393
394				convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
395				zval_dtor(op);
396
397				if (Z_TYPE(dst) == IS_DOUBLE) {
398					ZVAL_COPY_VALUE(op, &dst);
399				} else {
400					ZVAL_DOUBLE(op, 1.0);
401				}
402				break;
403			}
404		case IS_REFERENCE:
405			zend_unwrap_reference(op);
406			goto try_again;
407		EMPTY_SWITCH_DEFAULT_CASE()
408	}
409}
410/* }}} */
411
412ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
413{
414	if (Z_TYPE_P(op) == IS_OBJECT) {
415		if (Z_OBJ_HT_P(op)->cast_object) {
416			zval org;
417
418			ZVAL_COPY_VALUE(&org, op);
419			if (Z_OBJ_HT_P(op)->cast_object(&org, op, IS_NULL) == SUCCESS) {
420				zval_dtor(&org);
421				return;
422			}
423			ZVAL_COPY_VALUE(op, &org);
424		}
425	}
426
427	zval_ptr_dtor(op);
428	ZVAL_NULL(op);
429}
430/* }}} */
431
432ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
433{
434	int tmp;
435
436try_again:
437	switch (Z_TYPE_P(op)) {
438		case IS_FALSE:
439		case IS_TRUE:
440			break;
441		case IS_NULL:
442			ZVAL_FALSE(op);
443			break;
444		case IS_RESOURCE: {
445				zend_long l = (Z_RES_HANDLE_P(op) ? 1 : 0);
446
447				zval_ptr_dtor(op);
448				ZVAL_BOOL(op, l);
449			}
450			break;
451		case IS_LONG:
452			ZVAL_BOOL(op, Z_LVAL_P(op) ? 1 : 0);
453			break;
454		case IS_DOUBLE:
455			ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0);
456			break;
457		case IS_STRING:
458			{
459				zend_string *str = Z_STR_P(op);
460
461				if (ZSTR_LEN(str) == 0
462					|| (ZSTR_LEN(str) == 1 && ZSTR_VAL(str)[0] == '0')) {
463					ZVAL_FALSE(op);
464				} else {
465					ZVAL_TRUE(op);
466				}
467				zend_string_release(str);
468			}
469			break;
470		case IS_ARRAY:
471			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
472			zval_ptr_dtor(op);
473			ZVAL_BOOL(op, tmp);
474			break;
475		case IS_OBJECT:
476			{
477				zval dst;
478
479				convert_object_to_type(op, &dst, _IS_BOOL, convert_to_boolean);
480				zval_dtor(op);
481
482				if (Z_TYPE(dst) == IS_FALSE || Z_TYPE(dst) == IS_TRUE) {
483					ZVAL_COPY_VALUE(op, &dst);
484				} else {
485					ZVAL_TRUE(op);
486				}
487				break;
488			}
489		case IS_REFERENCE:
490			zend_unwrap_reference(op);
491			goto try_again;
492		EMPTY_SWITCH_DEFAULT_CASE()
493	}
494}
495/* }}} */
496
497ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op ZEND_FILE_LINE_DC) /* {{{ */
498{
499	if (Z_TYPE_P(op) == IS_DOUBLE) {
500		zend_string *str;
501		double dval = Z_DVAL_P(op);
502
503		str = zend_strpprintf(0, "%.*H", (int) EG(precision), dval);
504		ZVAL_NEW_STR(op, str);
505	} else {
506		_convert_to_string(op ZEND_FILE_LINE_CC);
507	}
508}
509/* }}} */
510
511ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
512{
513try_again:
514	switch (Z_TYPE_P(op)) {
515		case IS_UNDEF:
516		case IS_NULL:
517		case IS_FALSE: {
518			ZVAL_EMPTY_STRING(op);
519			break;
520		}
521		case IS_TRUE:
522			if (CG(one_char_string)['1']) {
523				ZVAL_INTERNED_STR(op, CG(one_char_string)['1']);
524			} else {
525				ZVAL_NEW_STR(op, zend_string_init("1", 1, 0));
526			}
527			break;
528		case IS_STRING:
529			break;
530		case IS_RESOURCE: {
531			char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
532			int len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
533			zval_ptr_dtor(op);
534			ZVAL_NEW_STR(op, zend_string_init(buf, len, 0));
535			break;
536		}
537		case IS_LONG: {
538			ZVAL_NEW_STR(op, zend_long_to_str(Z_LVAL_P(op)));
539			break;
540		}
541		case IS_DOUBLE: {
542			zend_string *str;
543			double dval = Z_DVAL_P(op);
544
545			str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
546			/* %G already handles removing trailing zeros from the fractional part, yay */
547			ZVAL_NEW_STR(op, str);
548			break;
549		}
550		case IS_ARRAY:
551			zend_error(E_NOTICE, "Array to string conversion");
552			zval_ptr_dtor(op);
553			ZVAL_NEW_STR(op, zend_string_init("Array", sizeof("Array")-1, 0));
554			break;
555		case IS_OBJECT: {
556			zval dst;
557
558			convert_object_to_type(op, &dst, IS_STRING, convert_to_string);
559			zval_dtor(op);
560
561			if (Z_TYPE(dst) == IS_STRING) {
562				ZVAL_COPY_VALUE(op, &dst);
563			} else {
564				ZVAL_NEW_STR(op, zend_string_init("Object", sizeof("Object")-1, 0));
565			}
566			break;
567		}
568		case IS_REFERENCE:
569			zend_unwrap_reference(op);
570			goto try_again;
571		EMPTY_SWITCH_DEFAULT_CASE()
572	}
573}
574/* }}} */
575
576static void convert_scalar_to_array(zval *op) /* {{{ */
577{
578	zval entry;
579
580	ZVAL_COPY_VALUE(&entry, op);
581
582	ZVAL_NEW_ARR(op);
583	zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0);
584	zend_hash_index_add_new(Z_ARRVAL_P(op), 0, &entry);
585}
586/* }}} */
587
588ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
589{
590try_again:
591	switch (Z_TYPE_P(op)) {
592		case IS_ARRAY:
593			break;
594/* OBJECTS_OPTIMIZE */
595		case IS_OBJECT:
596			if (Z_OBJCE_P(op) == zend_ce_closure) {
597				convert_scalar_to_array(op);
598			} else {
599				if (Z_OBJ_HT_P(op)->get_properties) {
600					HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op);
601					if (obj_ht) {
602						zend_array *arr;
603
604						if (!Z_OBJCE_P(op)->default_properties_count &&
605							obj_ht == Z_OBJ_P(op)->properties &&
606							!ZEND_HASH_GET_APPLY_COUNT(Z_OBJ_P(op)->properties)) {
607							/* fast copy */
608							if (EXPECTED(Z_OBJ_P(op)->handlers == &std_object_handlers)) {
609								arr = obj_ht;
610								if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(op)->properties) & IS_ARRAY_IMMUTABLE))) {
611									GC_REFCOUNT(Z_OBJ_P(op)->properties)++;
612								}
613							} else {
614								arr = zend_array_dup(obj_ht);
615							}
616							zval_dtor(op);
617							ZVAL_ARR(op, arr);
618						} else {
619							arr = zend_array_dup(obj_ht);
620							zval_dtor(op);
621							ZVAL_ARR(op, arr);
622						}
623						return;
624					}
625				} else {
626					zval dst;
627					convert_object_to_type(op, &dst, IS_ARRAY, convert_to_array);
628
629					if (Z_TYPE(dst) == IS_ARRAY) {
630						zval_dtor(op);
631						ZVAL_COPY_VALUE(op, &dst);
632						return;
633					}
634				}
635
636				zval_dtor(op);
637				array_init(op);
638			}
639			break;
640		case IS_NULL:
641			ZVAL_NEW_ARR(op);
642			zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0);
643			break;
644		case IS_REFERENCE:
645			zend_unwrap_reference(op);
646			goto try_again;
647		default:
648			convert_scalar_to_array(op);
649			break;
650	}
651}
652/* }}} */
653
654ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
655{
656try_again:
657	switch (Z_TYPE_P(op)) {
658		case IS_ARRAY:
659			{
660				HashTable *ht = Z_ARR_P(op);
661				if (Z_IMMUTABLE_P(op)) {
662					/* TODO: try not to duplicate immutable arrays as well ??? */
663					ht = zend_array_dup(ht);
664				}
665				object_and_properties_init(op, zend_standard_class_def, ht);
666				break;
667			}
668		case IS_OBJECT:
669			break;
670		case IS_NULL:
671			object_init(op);
672			break;
673		case IS_REFERENCE:
674			zend_unwrap_reference(op);
675			goto try_again;
676		default: {
677			zval tmp;
678			ZVAL_COPY_VALUE(&tmp, op);
679			object_init(op);
680			zend_hash_add_new(Z_OBJPROP_P(op), CG(known_strings)[ZEND_STR_SCALAR], &tmp);
681			break;
682		}
683	}
684}
685/* }}} */
686
687ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
688{
689	zval *arg;
690	va_list ap;
691
692	va_start(ap, argc);
693
694	while (argc--) {
695		arg = va_arg(ap, zval *);
696		convert_to_long_ex(arg);
697	}
698
699	va_end(ap);
700}
701/* }}} */
702
703ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
704{
705	zval *arg;
706	va_list ap;
707
708	va_start(ap, argc);
709
710	while (argc--) {
711		arg = va_arg(ap, zval *);
712		convert_to_double_ex(arg);
713	}
714
715	va_end(ap);
716}
717/* }}} */
718
719ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
720{
721	zval *arg;
722	va_list ap;
723
724	va_start(ap, argc);
725
726	while (argc--) {
727		arg = va_arg(ap, zval *);
728		convert_to_string_ex(arg);
729	}
730
731	va_end(ap);
732}
733/* }}} */
734
735static zend_always_inline zend_long ZEND_FASTCALL _zval_get_long_func_ex(zval *op, zend_bool silent) /* {{{ */
736{
737try_again:
738	switch (Z_TYPE_P(op)) {
739		case IS_UNDEF:
740		case IS_NULL:
741		case IS_FALSE:
742			return 0;
743		case IS_TRUE:
744			return 1;
745		case IS_RESOURCE:
746			return Z_RES_HANDLE_P(op);
747		case IS_LONG:
748			return Z_LVAL_P(op);
749		case IS_DOUBLE:
750			return zend_dval_to_lval(Z_DVAL_P(op));
751		case IS_STRING:
752			{
753				zend_uchar type;
754				zend_long lval;
755				double dval;
756				if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, silent ? 1 : -1))) {
757					if (!silent) {
758						zend_error(E_WARNING, "A non-numeric value encountered");
759					}
760					return 0;
761				} else if (EXPECTED(type == IS_LONG)) {
762					return lval;
763				} else {
764					/* Previously we used strtol here, not is_numeric_string,
765					 * and strtol gives you LONG_MAX/_MIN on overflow.
766					 * We use use saturating conversion to emulate strtol()'s
767					 * behaviour.
768					 */
769					 return zend_dval_to_lval_cap(dval);
770				}
771			}
772		case IS_ARRAY:
773			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
774		case IS_OBJECT:
775			{
776				zval dst;
777				convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
778				if (Z_TYPE(dst) == IS_LONG) {
779					return Z_LVAL(dst);
780				} else {
781					return 1;
782				}
783			}
784		case IS_REFERENCE:
785			op = Z_REFVAL_P(op);
786			goto try_again;
787		EMPTY_SWITCH_DEFAULT_CASE()
788	}
789	return 0;
790}
791/* }}} */
792
793ZEND_API zend_long ZEND_FASTCALL _zval_get_long_func(zval *op) /* {{{ */
794{
795	return _zval_get_long_func_ex(op, 1);
796}
797/* }}} */
798
799static zend_long ZEND_FASTCALL _zval_get_long_func_noisy(zval *op) /* {{{ */
800{
801	return _zval_get_long_func_ex(op, 0);
802}
803/* }}} */
804
805ZEND_API double ZEND_FASTCALL _zval_get_double_func(zval *op) /* {{{ */
806{
807try_again:
808	switch (Z_TYPE_P(op)) {
809		case IS_NULL:
810		case IS_FALSE:
811			return 0.0;
812		case IS_TRUE:
813			return 1.0;
814		case IS_RESOURCE:
815			return (double) Z_RES_HANDLE_P(op);
816		case IS_LONG:
817			return (double) Z_LVAL_P(op);
818		case IS_DOUBLE:
819			return Z_DVAL_P(op);
820		case IS_STRING:
821			return zend_strtod(Z_STRVAL_P(op), NULL);
822		case IS_ARRAY:
823			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
824		case IS_OBJECT:
825			{
826				zval dst;
827				convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
828
829				if (Z_TYPE(dst) == IS_DOUBLE) {
830					return Z_DVAL(dst);
831				} else {
832					return 1.0;
833				}
834			}
835		case IS_REFERENCE:
836			op = Z_REFVAL_P(op);
837			goto try_again;
838		EMPTY_SWITCH_DEFAULT_CASE()
839	}
840	return 0.0;
841}
842/* }}} */
843
844ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op) /* {{{ */
845{
846try_again:
847	switch (Z_TYPE_P(op)) {
848		case IS_UNDEF:
849		case IS_NULL:
850		case IS_FALSE:
851			return ZSTR_EMPTY_ALLOC();
852		case IS_TRUE:
853			if (CG(one_char_string)['1']) {
854				return CG(one_char_string)['1'];
855			} else {
856				return zend_string_init("1", 1, 0);
857			}
858		case IS_RESOURCE: {
859			char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
860			int len;
861
862			len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
863			return zend_string_init(buf, len, 0);
864		}
865		case IS_LONG: {
866			return zend_long_to_str(Z_LVAL_P(op));
867		}
868		case IS_DOUBLE: {
869			return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
870		}
871		case IS_ARRAY:
872			zend_error(E_NOTICE, "Array to string conversion");
873			return zend_string_init("Array", sizeof("Array")-1, 0);
874		case IS_OBJECT: {
875			zval tmp;
876			if (Z_OBJ_HT_P(op)->cast_object) {
877				if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
878					return Z_STR(tmp);
879				}
880			} else if (Z_OBJ_HT_P(op)->get) {
881				zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
882				if (Z_TYPE_P(z) != IS_OBJECT) {
883					zend_string *str = zval_get_string(z);
884					zval_ptr_dtor(z);
885					return str;
886				}
887				zval_ptr_dtor(z);
888			}
889			zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
890			return ZSTR_EMPTY_ALLOC();
891		}
892		case IS_REFERENCE:
893			op = Z_REFVAL_P(op);
894			goto try_again;
895		case IS_STRING:
896			return zend_string_copy(Z_STR_P(op));
897		EMPTY_SWITCH_DEFAULT_CASE()
898	}
899	return NULL;
900}
901/* }}} */
902
903ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
904{
905	zval op1_copy, op2_copy;
906	int converted = 0;
907
908	while (1) {
909		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
910			case TYPE_PAIR(IS_LONG, IS_LONG): {
911				zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
912
913				/* check for overflow by comparing sign bits */
914				if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
915					&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
916
917					ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
918				} else {
919					ZVAL_LONG(result, lval);
920				}
921				return SUCCESS;
922			}
923
924			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
925				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
926				return SUCCESS;
927
928			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
929				ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
930				return SUCCESS;
931
932			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
933				ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
934				return SUCCESS;
935
936			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
937				if ((result == op1) && (result == op2)) {
938					/* $a += $a */
939					return SUCCESS;
940				}
941				if (result != op1) {
942					ZVAL_DUP(result, op1);
943				}
944				zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
945				return SUCCESS;
946
947			default:
948				if (Z_ISREF_P(op1)) {
949					op1 = Z_REFVAL_P(op1);
950				} else if (Z_ISREF_P(op2)) {
951					op2 = Z_REFVAL_P(op2);
952				} else if (!converted) {
953					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
954
955					zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
956					zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
957					converted = 1;
958				} else {
959					zend_throw_error(NULL, "Unsupported operand types");
960					return FAILURE; /* unknown datatype */
961				}
962		}
963	}
964}
965/* }}} */
966
967ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
968{
969	zval op1_copy, op2_copy;
970	int converted = 0;
971
972	while (1) {
973		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
974			case TYPE_PAIR(IS_LONG, IS_LONG): {
975				zend_long lval = Z_LVAL_P(op1) - Z_LVAL_P(op2);
976
977				/* check for overflow by comparing sign bits */
978				if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK)
979					&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
980
981					ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
982				} else {
983					ZVAL_LONG(result, lval);
984				}
985				return SUCCESS;
986
987			}
988			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
989				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
990				return SUCCESS;
991
992			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
993				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
994				return SUCCESS;
995
996			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
997				ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
998				return SUCCESS;
999
1000			default:
1001				if (Z_ISREF_P(op1)) {
1002					op1 = Z_REFVAL_P(op1);
1003				} else if (Z_ISREF_P(op2)) {
1004					op2 = Z_REFVAL_P(op2);
1005				} else if (!converted) {
1006					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
1007
1008					zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
1009					zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
1010					converted = 1;
1011				} else {
1012					zend_throw_error(NULL, "Unsupported operand types");
1013					return FAILURE; /* unknown datatype */
1014				}
1015		}
1016	}
1017}
1018/* }}} */
1019
1020ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1021{
1022	zval op1_copy, op2_copy;
1023	int converted = 0;
1024
1025	while (1) {
1026		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1027			case TYPE_PAIR(IS_LONG, IS_LONG): {
1028				zend_long overflow;
1029
1030				ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
1031				Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
1032				return SUCCESS;
1033
1034			}
1035			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1036				ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
1037				return SUCCESS;
1038
1039			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1040				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
1041				return SUCCESS;
1042
1043			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1044				ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
1045				return SUCCESS;
1046
1047			default:
1048				if (Z_ISREF_P(op1)) {
1049					op1 = Z_REFVAL_P(op1);
1050				} else if (Z_ISREF_P(op2)) {
1051					op2 = Z_REFVAL_P(op2);
1052				} else if (!converted) {
1053					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
1054
1055					zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
1056					zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
1057					converted = 1;
1058				} else {
1059					zend_throw_error(NULL, "Unsupported operand types");
1060					return FAILURE; /* unknown datatype */
1061				}
1062		}
1063	}
1064}
1065/* }}} */
1066
1067ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
1068{
1069	zval op1_copy, op2_copy;
1070	int converted = 0;
1071
1072	while (1) {
1073		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1074			case TYPE_PAIR(IS_LONG, IS_LONG):
1075				if (Z_LVAL_P(op2) >= 0) {
1076					zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
1077
1078					if (i == 0) {
1079						ZVAL_LONG(result, 1L);
1080						return SUCCESS;
1081					} else if (l2 == 0) {
1082						ZVAL_LONG(result, 0);
1083						return SUCCESS;
1084					}
1085
1086					while (i >= 1) {
1087						zend_long overflow;
1088						double dval = 0.0;
1089
1090						if (i % 2) {
1091							--i;
1092							ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1093							if (overflow) {
1094								ZVAL_DOUBLE(result, dval * pow(l2, i));
1095								return SUCCESS;
1096							}
1097						} else {
1098							i /= 2;
1099							ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1100							if (overflow) {
1101								ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1102								return SUCCESS;
1103							}
1104						}
1105					}
1106					/* i == 0 */
1107					ZVAL_LONG(result, l1);
1108				} else {
1109					ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1110				}
1111				return SUCCESS;
1112
1113			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1114				ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1115				return SUCCESS;
1116
1117			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1118				ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1119				return SUCCESS;
1120
1121			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1122				ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1123				return SUCCESS;
1124
1125			default:
1126				if (Z_ISREF_P(op1)) {
1127					op1 = Z_REFVAL_P(op1);
1128				} else if (Z_ISREF_P(op2)) {
1129					op2 = Z_REFVAL_P(op2);
1130				} else if (!converted) {
1131					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
1132
1133					if (Z_TYPE_P(op1) == IS_ARRAY) {
1134						ZVAL_LONG(result, 0);
1135						return SUCCESS;
1136					} else {
1137						zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
1138					}
1139					if (Z_TYPE_P(op2) == IS_ARRAY) {
1140						ZVAL_LONG(result, 1L);
1141						return SUCCESS;
1142					} else {
1143						zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
1144					}
1145					converted = 1;
1146				} else {
1147					zend_throw_error(NULL, "Unsupported operand types");
1148					return FAILURE;
1149				}
1150		}
1151	}
1152}
1153/* }}} */
1154
1155ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1156{
1157	zval op1_copy, op2_copy;
1158	int converted = 0;
1159
1160	while (1) {
1161		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1162			case TYPE_PAIR(IS_LONG, IS_LONG):
1163				if (Z_LVAL_P(op2) == 0) {
1164					zend_error(E_WARNING, "Division by zero");
1165					ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
1166					return SUCCESS;
1167				} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1168					/* Prevent overflow error/crash */
1169					ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1170					return SUCCESS;
1171				}
1172				if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1173					ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1174				} else {
1175					ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1176				}
1177				return SUCCESS;
1178
1179			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1180				if (Z_LVAL_P(op2) == 0) {
1181					zend_error(E_WARNING, "Division by zero");
1182				}
1183				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1184				return SUCCESS;
1185
1186			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1187				if (Z_DVAL_P(op2) == 0) {
1188					zend_error(E_WARNING, "Division by zero");
1189				}
1190				ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1191				return SUCCESS;
1192
1193			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1194				if (Z_DVAL_P(op2) == 0) {
1195					zend_error(E_WARNING, "Division by zero");
1196				}
1197				ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1198				return SUCCESS;
1199
1200			default:
1201				if (Z_ISREF_P(op1)) {
1202					op1 = Z_REFVAL_P(op1);
1203				} else if (Z_ISREF_P(op2)) {
1204					op2 = Z_REFVAL_P(op2);
1205				} else if (!converted) {
1206					ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
1207
1208					zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
1209					zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
1210					converted = 1;
1211				} else {
1212					zend_throw_error(NULL, "Unsupported operand types");
1213					return FAILURE; /* unknown datatype */
1214				}
1215		}
1216	}
1217}
1218/* }}} */
1219
1220ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1221{
1222	zend_long op1_lval, op2_lval;
1223
1224	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_MOD, mod_function);
1225
1226	if (op1 == result) {
1227		zval_dtor(result);
1228	}
1229
1230	if (op2_lval == 0) {
1231		/* modulus by zero */
1232		if (EG(current_execute_data) && !CG(in_compilation)) {
1233			zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1234		} else {
1235			zend_error_noreturn(E_ERROR, "Modulo by zero");
1236		}
1237		ZVAL_UNDEF(result);
1238		return FAILURE;
1239	}
1240
1241	if (op2_lval == -1) {
1242		/* Prevent overflow error/crash if op1==LONG_MIN */
1243		ZVAL_LONG(result, 0);
1244		return SUCCESS;
1245	}
1246
1247	ZVAL_LONG(result, op1_lval % op2_lval);
1248	return SUCCESS;
1249}
1250/* }}} */
1251
1252ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1253{
1254	int op1_val, op2_val;
1255
1256	do {
1257		if (Z_TYPE_P(op1) == IS_FALSE) {
1258			op1_val = 0;
1259		} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1260			op1_val = 1;
1261		} else {
1262			if (Z_ISREF_P(op1)) {
1263				op1 = Z_REFVAL_P(op1);
1264				if (Z_TYPE_P(op1) == IS_FALSE) {
1265					op1_val = 0;
1266					break;
1267				} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1268					op1_val = 1;
1269					break;
1270				}
1271			}
1272			ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function);
1273			op1_val = zval_is_true(op1);
1274		}
1275	} while (0);
1276	do {
1277		if (Z_TYPE_P(op2) == IS_FALSE) {
1278			op2_val = 0;
1279		} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1280			op2_val = 1;
1281		} else {
1282			if (Z_ISREF_P(op2)) {
1283				op2 = Z_REFVAL_P(op2);
1284				if (Z_TYPE_P(op2) == IS_FALSE) {
1285					op2_val = 0;
1286					break;
1287				} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1288					op2_val = 1;
1289					break;
1290				}
1291			}
1292			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1293			op2_val = zval_is_true(op2);
1294		}
1295	} while (0);
1296
1297	ZVAL_BOOL(result, op1_val ^ op2_val);
1298	return SUCCESS;
1299}
1300/* }}} */
1301
1302ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1303{
1304	if (Z_TYPE_P(op1) < IS_TRUE) {
1305		ZVAL_TRUE(result);
1306	} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1307		ZVAL_FALSE(result);
1308	} else {
1309		if (Z_ISREF_P(op1)) {
1310			op1 = Z_REFVAL_P(op1);
1311			if (Z_TYPE_P(op1) < IS_TRUE) {
1312				ZVAL_TRUE(result);
1313				return SUCCESS;
1314			} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1315				ZVAL_FALSE(result);
1316				return SUCCESS;
1317			}
1318		}
1319		ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1320
1321		ZVAL_BOOL(result, !zval_is_true(op1));
1322	}
1323	return SUCCESS;
1324}
1325/* }}} */
1326
1327ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1328{
1329try_again:
1330	switch (Z_TYPE_P(op1)) {
1331		case IS_LONG:
1332			ZVAL_LONG(result, ~Z_LVAL_P(op1));
1333			return SUCCESS;
1334		case IS_DOUBLE:
1335			ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1336			return SUCCESS;
1337		case IS_STRING: {
1338			size_t i;
1339
1340			if (Z_STRLEN_P(op1) == 1) {
1341				zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
1342				if (CG(one_char_string)[not]) {
1343					ZVAL_INTERNED_STR(result, CG(one_char_string)[not]);
1344				} else {
1345					ZVAL_NEW_STR(result, zend_string_init((char *) &not, 1, 0));
1346				}
1347			} else {
1348				ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1349				for (i = 0; i < Z_STRLEN_P(op1); i++) {
1350					Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1351				}
1352				Z_STRVAL_P(result)[i] = 0;
1353			}
1354			return SUCCESS;
1355		}
1356		case IS_REFERENCE:
1357			op1 = Z_REFVAL_P(op1);
1358			goto try_again;
1359		default:
1360			ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1361
1362			zend_throw_error(NULL, "Unsupported operand types");
1363			return FAILURE;
1364	}
1365}
1366/* }}} */
1367
1368ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1369{
1370	zend_long op1_lval, op2_lval;
1371
1372	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1373		ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1374		return SUCCESS;
1375	}
1376
1377	ZVAL_DEREF(op1);
1378	ZVAL_DEREF(op2);
1379
1380	if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1381		zval *longer, *shorter;
1382		zend_string *str;
1383		size_t i;
1384
1385		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1386			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1387				zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
1388				if (CG(one_char_string)[or]) {
1389					ZVAL_INTERNED_STR(result, CG(one_char_string)[or]);
1390				} else {
1391					ZVAL_NEW_STR(result, zend_string_init((char *) &or, 1, 0));
1392				}
1393				return SUCCESS;
1394			}
1395			longer = op1;
1396			shorter = op2;
1397		} else {
1398			longer = op2;
1399			shorter = op1;
1400		}
1401
1402		str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1403		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1404			ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1405		}
1406		memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1407		if (result==op1) {
1408			zend_string_release(Z_STR_P(result));
1409		}
1410		ZVAL_NEW_STR(result, str);
1411		return SUCCESS;
1412	}
1413
1414	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1415		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
1416		op1_lval = _zval_get_long_func_noisy(op1);
1417	} else {
1418		op1_lval = Z_LVAL_P(op1);
1419	}
1420	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1421		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1422		op2_lval = _zval_get_long_func_noisy(op2);
1423	} else {
1424		op2_lval = Z_LVAL_P(op2);
1425	}
1426
1427	if (op1 == result) {
1428		zval_dtor(result);
1429	}
1430	ZVAL_LONG(result, op1_lval | op2_lval);
1431	return SUCCESS;
1432}
1433/* }}} */
1434
1435ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1436{
1437	zend_long op1_lval, op2_lval;
1438
1439	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1440		ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1441		return SUCCESS;
1442	}
1443
1444	ZVAL_DEREF(op1);
1445	ZVAL_DEREF(op2);
1446
1447	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1448		zval *longer, *shorter;
1449		zend_string *str;
1450		size_t i;
1451
1452		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1453			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1454				zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
1455				if (CG(one_char_string)[and]) {
1456					ZVAL_INTERNED_STR(result, CG(one_char_string)[and]);
1457				} else {
1458					ZVAL_NEW_STR(result, zend_string_init((char *) &and, 1, 0));
1459				}
1460				return SUCCESS;
1461			}
1462			longer = op1;
1463			shorter = op2;
1464		} else {
1465			longer = op2;
1466			shorter = op1;
1467		}
1468
1469		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1470		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1471			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1472		}
1473		ZSTR_VAL(str)[i] = 0;
1474		if (result==op1) {
1475			zend_string_release(Z_STR_P(result));
1476		}
1477		ZVAL_NEW_STR(result, str);
1478		return SUCCESS;
1479	}
1480
1481	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1482		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function);
1483		op1_lval = _zval_get_long_func_noisy(op1);
1484	} else {
1485		op1_lval = Z_LVAL_P(op1);
1486	}
1487	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1488		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1489		op2_lval = _zval_get_long_func_noisy(op2);
1490	} else {
1491		op2_lval = Z_LVAL_P(op2);
1492	}
1493
1494	if (op1 == result) {
1495		zval_dtor(result);
1496	}
1497	ZVAL_LONG(result, op1_lval & op2_lval);
1498	return SUCCESS;
1499}
1500/* }}} */
1501
1502ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1503{
1504	zend_long op1_lval, op2_lval;
1505
1506	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1507		ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1508		return SUCCESS;
1509	}
1510
1511	ZVAL_DEREF(op1);
1512	ZVAL_DEREF(op2);
1513
1514	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1515		zval *longer, *shorter;
1516		zend_string *str;
1517		size_t i;
1518
1519		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1520			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1521				zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
1522				if (CG(one_char_string)[xor]) {
1523					ZVAL_INTERNED_STR(result, CG(one_char_string)[xor]);
1524				} else {
1525					ZVAL_NEW_STR(result, zend_string_init((char *) &xor, 1, 0));
1526				}
1527				return SUCCESS;
1528			}
1529			longer = op1;
1530			shorter = op2;
1531		} else {
1532			longer = op2;
1533			shorter = op1;
1534		}
1535
1536		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1537		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1538			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1539		}
1540		ZSTR_VAL(str)[i] = 0;
1541		if (result==op1) {
1542			zend_string_release(Z_STR_P(result));
1543		}
1544		ZVAL_NEW_STR(result, str);
1545		return SUCCESS;
1546	}
1547
1548	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1549		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function);
1550		op1_lval = _zval_get_long_func_noisy(op1);
1551	} else {
1552		op1_lval = Z_LVAL_P(op1);
1553	}
1554	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1555		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1556		op2_lval = _zval_get_long_func_noisy(op2);
1557	} else {
1558		op2_lval = Z_LVAL_P(op2);
1559	}
1560
1561	if (op1 == result) {
1562		zval_dtor(result);
1563	}
1564	ZVAL_LONG(result, op1_lval ^ op2_lval);
1565	return SUCCESS;
1566}
1567/* }}} */
1568
1569ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1570{
1571	zend_long op1_lval, op2_lval;
1572
1573	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SL, shift_left_function);
1574
1575	if (op1 == result) {
1576		zval_dtor(result);
1577	}
1578
1579	/* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1580	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1581		if (EXPECTED(op2_lval > 0)) {
1582			ZVAL_LONG(result, 0);
1583			return SUCCESS;
1584		} else {
1585			if (EG(current_execute_data) && !CG(in_compilation)) {
1586				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1587			} else {
1588				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1589			}
1590			ZVAL_UNDEF(result);
1591			return FAILURE;
1592		}
1593	}
1594
1595	ZVAL_LONG(result, op1_lval << op2_lval);
1596	return SUCCESS;
1597}
1598/* }}} */
1599
1600ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1601{
1602	zend_long op1_lval, op2_lval;
1603
1604	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, ZEND_SR, shift_right_function);
1605
1606	if (op1 == result) {
1607		zval_dtor(result);
1608	}
1609
1610	/* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1611	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1612		if (EXPECTED(op2_lval > 0)) {
1613			ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1614			return SUCCESS;
1615		} else {
1616			if (EG(current_execute_data) && !CG(in_compilation)) {
1617				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1618			} else {
1619				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1620			}
1621			ZVAL_UNDEF(result);
1622			return FAILURE;
1623		}
1624	}
1625
1626	ZVAL_LONG(result, op1_lval >> op2_lval);
1627	return SUCCESS;
1628}
1629/* }}} */
1630
1631ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1632{
1633	zval op1_copy, op2_copy;
1634	int use_copy1 = 0, use_copy2 = 0;
1635
1636	do {
1637	 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
1638	 		if (Z_ISREF_P(op1)) {
1639	 			op1 = Z_REFVAL_P(op1);
1640	 			if (Z_TYPE_P(op1) == IS_STRING) break;
1641	 		}
1642			ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
1643			use_copy1 = zend_make_printable_zval(op1, &op1_copy);
1644			if (use_copy1) {
1645				/* We have created a converted copy of op1. Therefore, op1 won't become the result so
1646				 * we have to free it.
1647				 */
1648				if (result == op1) {
1649					zval_dtor(op1);
1650					if (UNEXPECTED(op1 == op2)) {
1651						op2 = &op1_copy;
1652					}
1653				}
1654				op1 = &op1_copy;
1655			}
1656		}
1657	} while (0);
1658	do {
1659		if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
1660	 		if (Z_ISREF_P(op2)) {
1661	 			op2 = Z_REFVAL_P(op2);
1662	 			if (Z_TYPE_P(op2) == IS_STRING) break;
1663	 		}
1664			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
1665			use_copy2 = zend_make_printable_zval(op2, &op2_copy);
1666			if (use_copy2) {
1667				op2 = &op2_copy;
1668			}
1669		}
1670	} while (0);
1671
1672	{
1673		size_t op1_len = Z_STRLEN_P(op1);
1674		size_t op2_len = Z_STRLEN_P(op2);
1675		size_t result_len = op1_len + op2_len;
1676		zend_string *result_str;
1677
1678		if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
1679			zend_throw_error(NULL, "String size overflow");
1680			ZVAL_FALSE(result);
1681			return FAILURE;
1682		}
1683
1684		if (result == op1 && Z_REFCOUNTED_P(result)) {
1685			/* special case, perform operations on result */
1686			result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
1687		} else {
1688			result_str = zend_string_alloc(result_len, 0);
1689			memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1690		}
1691
1692		/* This has to happen first to account for the cases where result == op1 == op2 and
1693		 * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1694		 * point to the new string. The first op2_len bytes of result will still be the same. */
1695		ZVAL_NEW_STR(result, result_str);
1696
1697		memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1698		ZSTR_VAL(result_str)[result_len] = '\0';
1699	}
1700
1701	if (UNEXPECTED(use_copy1)) {
1702		zval_dtor(op1);
1703	}
1704	if (UNEXPECTED(use_copy2)) {
1705		zval_dtor(op2);
1706	}
1707	return SUCCESS;
1708}
1709/* }}} */
1710
1711ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
1712{
1713	zend_string *str1 = zval_get_string(op1);
1714	zend_string *str2 = zval_get_string(op2);
1715	int ret;
1716
1717	if (case_insensitive) {
1718		ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
1719	} else {
1720		ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
1721	}
1722
1723	zend_string_release(str1);
1724	zend_string_release(str2);
1725	return ret;
1726}
1727/* }}} */
1728
1729ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
1730{
1731	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1732	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1733		if (Z_STR_P(op1) == Z_STR_P(op2)) {
1734			return 0;
1735		} else {
1736			return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1737		}
1738	} else {
1739		zend_string *str1 = zval_get_string(op1);
1740		zend_string *str2 = zval_get_string(op2);
1741		int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
1742
1743		zend_string_release(str1);
1744		zend_string_release(str2);
1745		return ret;
1746	}
1747}
1748/* }}} */
1749
1750ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
1751{
1752	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1753	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1754		if (Z_STR_P(op1) == Z_STR_P(op2)) {
1755			return 0;
1756		} else {
1757			return zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1758		}
1759	} else {
1760		zend_string *str1 = zval_get_string(op1);
1761		zend_string *str2 = zval_get_string(op2);
1762		int ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
1763
1764		zend_string_release(str1);
1765		zend_string_release(str2);
1766		return ret;
1767	}
1768}
1769/* }}} */
1770
1771#if HAVE_STRCOLL
1772ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
1773{
1774	zend_string *str1 = zval_get_string(op1);
1775	zend_string *str2 = zval_get_string(op2);
1776	int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
1777
1778	zend_string_release(str1);
1779	zend_string_release(str2);
1780	return ret;
1781}
1782/* }}} */
1783#endif
1784
1785ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
1786{
1787	double d1, d2;
1788
1789	d1 = zval_get_double(op1);
1790	d2 = zval_get_double(op2);
1791
1792	return ZEND_NORMALIZE_BOOL(d1 - d2);
1793}
1794/* }}} */
1795
1796static inline void zend_free_obj_get_result(zval *op) /* {{{ */
1797{
1798	if (Z_REFCOUNTED_P(op)) {
1799		if (Z_REFCOUNT_P(op) == 0) {
1800			zval_dtor(op);
1801		} else {
1802			zval_ptr_dtor(op);
1803		}
1804	}
1805}
1806/* }}} */
1807
1808static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */
1809{
1810	if (Z_TYPE_P(result) == IS_DOUBLE) {
1811		ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1812	} else {
1813		convert_to_long(result);
1814	}
1815}
1816/* }}} */
1817
1818ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1819{
1820	int ret;
1821	int converted = 0;
1822	zval op1_copy, op2_copy;
1823	zval *op_free, tmp_free;
1824
1825	while (1) {
1826		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1827			case TYPE_PAIR(IS_LONG, IS_LONG):
1828				ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1829				return SUCCESS;
1830
1831			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1832				Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1833				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1834				return SUCCESS;
1835
1836			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1837				Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1838				ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1839				return SUCCESS;
1840
1841			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1842				if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1843					ZVAL_LONG(result, 0);
1844				} else {
1845					Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1846					ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1847				}
1848				return SUCCESS;
1849
1850			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1851				ZVAL_LONG(result, zend_compare_arrays(op1, op2));
1852				return SUCCESS;
1853
1854			case TYPE_PAIR(IS_NULL, IS_NULL):
1855			case TYPE_PAIR(IS_NULL, IS_FALSE):
1856			case TYPE_PAIR(IS_FALSE, IS_NULL):
1857			case TYPE_PAIR(IS_FALSE, IS_FALSE):
1858			case TYPE_PAIR(IS_TRUE, IS_TRUE):
1859				ZVAL_LONG(result, 0);
1860				return SUCCESS;
1861
1862			case TYPE_PAIR(IS_NULL, IS_TRUE):
1863				ZVAL_LONG(result, -1);
1864				return SUCCESS;
1865
1866			case TYPE_PAIR(IS_TRUE, IS_NULL):
1867				ZVAL_LONG(result, 1);
1868				return SUCCESS;
1869
1870			case TYPE_PAIR(IS_STRING, IS_STRING):
1871				if (Z_STR_P(op1) == Z_STR_P(op2)) {
1872					ZVAL_LONG(result, 0);
1873					return SUCCESS;
1874				}
1875				ZVAL_LONG(result, zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)));
1876				return SUCCESS;
1877
1878			case TYPE_PAIR(IS_NULL, IS_STRING):
1879				ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
1880				return SUCCESS;
1881
1882			case TYPE_PAIR(IS_STRING, IS_NULL):
1883				ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
1884				return SUCCESS;
1885
1886			case TYPE_PAIR(IS_OBJECT, IS_NULL):
1887				ZVAL_LONG(result, 1);
1888				return SUCCESS;
1889
1890			case TYPE_PAIR(IS_NULL, IS_OBJECT):
1891				ZVAL_LONG(result, -1);
1892				return SUCCESS;
1893
1894			default:
1895				if (Z_ISREF_P(op1)) {
1896					op1 = Z_REFVAL_P(op1);
1897					continue;
1898				} else if (Z_ISREF_P(op2)) {
1899					op2 = Z_REFVAL_P(op2);
1900					continue;
1901				}
1902
1903				if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1904					ret = Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);
1905					if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
1906						convert_compare_result_to_long(result);
1907					}
1908					return ret;
1909				} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1910					ret = Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);
1911					if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
1912						convert_compare_result_to_long(result);
1913					}
1914					return ret;
1915				}
1916
1917				if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1918					if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
1919						/* object handles are identical, apparently this is the same object */
1920						ZVAL_LONG(result, 0);
1921						return SUCCESS;
1922					}
1923					if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1924						ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));
1925						return SUCCESS;
1926					}
1927				}
1928				if (Z_TYPE_P(op1) == IS_OBJECT) {
1929					if (Z_OBJ_HT_P(op1)->get) {
1930						zval rv;
1931						op_free = Z_OBJ_HT_P(op1)->get(op1, &rv);
1932						ret = compare_function(result, op_free, op2);
1933						zend_free_obj_get_result(op_free);
1934						return ret;
1935					} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1936						ZVAL_UNDEF(&tmp_free);
1937						if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) {
1938							ZVAL_LONG(result, 1);
1939							zend_free_obj_get_result(&tmp_free);
1940							return SUCCESS;
1941						}
1942						ret = compare_function(result, &tmp_free, op2);
1943						zend_free_obj_get_result(&tmp_free);
1944						return ret;
1945					}
1946				}
1947				if (Z_TYPE_P(op2) == IS_OBJECT) {
1948					if (Z_OBJ_HT_P(op2)->get) {
1949						zval rv;
1950						op_free = Z_OBJ_HT_P(op2)->get(op2, &rv);
1951						ret = compare_function(result, op1, op_free);
1952						zend_free_obj_get_result(op_free);
1953						return ret;
1954					} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1955						ZVAL_UNDEF(&tmp_free);
1956						if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) {
1957							ZVAL_LONG(result, -1);
1958							zend_free_obj_get_result(&tmp_free);
1959							return SUCCESS;
1960						}
1961						ret = compare_function(result, op1, &tmp_free);
1962						zend_free_obj_get_result(&tmp_free);
1963						return ret;
1964					} else if (Z_TYPE_P(op1) == IS_OBJECT) {
1965						ZVAL_LONG(result, 1);
1966						return SUCCESS;
1967					}
1968				}
1969				if (!converted) {
1970					if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1971						ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);
1972						return SUCCESS;
1973					} else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) {
1974						ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);
1975						return SUCCESS;
1976					} else if (Z_TYPE_P(op1) == IS_TRUE) {
1977						ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);
1978						return SUCCESS;
1979					} else if (Z_TYPE_P(op2) == IS_TRUE) {
1980						ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);
1981						return SUCCESS;
1982					} else {
1983						zendi_convert_scalar_to_number(op1, op1_copy, result, 1);
1984						zendi_convert_scalar_to_number(op2, op2_copy, result, 1);
1985						converted = 1;
1986					}
1987				} else if (Z_TYPE_P(op1)==IS_ARRAY) {
1988					ZVAL_LONG(result, 1);
1989					return SUCCESS;
1990				} else if (Z_TYPE_P(op2)==IS_ARRAY) {
1991					ZVAL_LONG(result, -1);
1992					return SUCCESS;
1993				} else if (Z_TYPE_P(op1)==IS_OBJECT) {
1994					ZVAL_LONG(result, 1);
1995					return SUCCESS;
1996				} else if (Z_TYPE_P(op2)==IS_OBJECT) {
1997					ZVAL_LONG(result, -1);
1998					return SUCCESS;
1999				} else {
2000					ZVAL_LONG(result, 0);
2001					return FAILURE;
2002				}
2003		}
2004	}
2005}
2006/* }}} */
2007
2008static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
2009{
2010	zval result;
2011
2012	/* is_identical_function() returns 1 in case of identity and 0 in case
2013	 * of a difference;
2014	 * whereas this comparison function is expected to return 0 on identity,
2015	 * and non zero otherwise.
2016	 */
2017	ZVAL_DEREF(z1);
2018	ZVAL_DEREF(z2);
2019	if (is_identical_function(&result, z1, z2)==FAILURE) {
2020		return 1;
2021	}
2022	return Z_TYPE(result) != IS_TRUE;
2023}
2024/* }}} */
2025
2026ZEND_API int ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */
2027{
2028	if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
2029		return 0;
2030	}
2031	switch (Z_TYPE_P(op1)) {
2032		case IS_NULL:
2033		case IS_FALSE:
2034		case IS_TRUE:
2035			return 1;
2036		case IS_LONG:
2037			return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
2038		case IS_RESOURCE:
2039			return (Z_RES_P(op1) == Z_RES_P(op2));
2040		case IS_DOUBLE:
2041			return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
2042		case IS_STRING:
2043			return (Z_STR_P(op1) == Z_STR_P(op2) ||
2044				(Z_STRLEN_P(op1) == Z_STRLEN_P(op2) &&
2045				 memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0));
2046		case IS_ARRAY:
2047			return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
2048				zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
2049		case IS_OBJECT:
2050			return (Z_OBJ_P(op1) == Z_OBJ_P(op2) && Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2));
2051		default:
2052			return 0;
2053	}
2054}
2055/* }}} */
2056
2057ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2058{
2059	ZVAL_BOOL(result, zend_is_identical(op1, op2));
2060	return SUCCESS;
2061}
2062/* }}} */
2063
2064ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2065{
2066	ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2067	return SUCCESS;
2068}
2069/* }}} */
2070
2071ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2072{
2073	if (compare_function(result, op1, op2) == FAILURE) {
2074		return FAILURE;
2075	}
2076	ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
2077	return SUCCESS;
2078}
2079/* }}} */
2080
2081ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2082{
2083	if (compare_function(result, op1, op2) == FAILURE) {
2084		return FAILURE;
2085	}
2086	ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
2087	return SUCCESS;
2088}
2089/* }}} */
2090
2091ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
2092{
2093	if (compare_function(result, op1, op2) == FAILURE) {
2094		return FAILURE;
2095	}
2096	ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
2097	return SUCCESS;
2098}
2099/* }}} */
2100
2101ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2102{
2103	if (compare_function(result, op1, op2) == FAILURE) {
2104		return FAILURE;
2105	}
2106	ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
2107	return SUCCESS;
2108}
2109/* }}} */
2110
2111static zend_bool ZEND_FASTCALL instanceof_interface_only(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2112{
2113	uint32_t i;
2114
2115	for (i = 0; i < instance_ce->num_interfaces; i++) {
2116		if (instanceof_interface_only(instance_ce->interfaces[i], ce)) {
2117			return 1;
2118		}
2119	}
2120	return 0;
2121}
2122/* }}} */
2123
2124static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2125{
2126	while (instance_ce) {
2127		if (instance_ce == ce) {
2128			return 1;
2129		}
2130		instance_ce = instance_ce->parent;
2131	}
2132	return 0;
2133}
2134/* }}} */
2135
2136static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2137{
2138	uint32_t i;
2139
2140	for (i = 0; i < instance_ce->num_interfaces; i++) {
2141		if (instanceof_interface(instance_ce->interfaces[i], ce)) {
2142			return 1;
2143		}
2144	}
2145	return instanceof_class(instance_ce, ce);
2146}
2147/* }}} */
2148
2149ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only) /* {{{ */
2150{
2151	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2152		if (!interfaces_only) {
2153			if (instanceof_interface_only(instance_ce, ce)) {
2154				return 1;
2155			}
2156		} else {
2157			return instanceof_interface(instance_ce, ce);
2158		}
2159	}
2160	if (!interfaces_only) {
2161		return instanceof_class(instance_ce, ce);
2162	}
2163	return 0;
2164}
2165/* }}} */
2166
2167ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2168{
2169	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2170		return instanceof_interface(instance_ce, ce);
2171	} else {
2172		return instanceof_class(instance_ce, ce);
2173	}
2174}
2175/* }}} */
2176
2177#define LOWER_CASE 1
2178#define UPPER_CASE 2
2179#define NUMERIC 3
2180
2181static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2182{
2183	int carry=0;
2184	size_t pos=Z_STRLEN_P(str)-1;
2185	char *s;
2186	zend_string *t;
2187	int last=0; /* Shut up the compiler warning */
2188	int ch;
2189
2190	if (Z_STRLEN_P(str) == 0) {
2191		zend_string_release(Z_STR_P(str));
2192		if (CG(one_char_string)['1']) {
2193			ZVAL_INTERNED_STR(str, CG(one_char_string)['1']);
2194		} else {
2195			Z_STR_P(str) = zend_string_init("1", sizeof("1")-1, 0);
2196			Z_TYPE_INFO_P(str) = IS_STRING_EX;
2197		}
2198		return;
2199	}
2200
2201	if (!Z_REFCOUNTED_P(str)) {
2202		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2203		Z_TYPE_INFO_P(str) = IS_STRING_EX;
2204	} else if (Z_REFCOUNT_P(str) > 1) {
2205		Z_DELREF_P(str);
2206		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2207	} else {
2208		zend_string_forget_hash_val(Z_STR_P(str));
2209	}
2210	s = Z_STRVAL_P(str);
2211
2212	do {
2213		ch = s[pos];
2214		if (ch >= 'a' && ch <= 'z') {
2215			if (ch == 'z') {
2216				s[pos] = 'a';
2217				carry=1;
2218			} else {
2219				s[pos]++;
2220				carry=0;
2221			}
2222			last=LOWER_CASE;
2223		} else if (ch >= 'A' && ch <= 'Z') {
2224			if (ch == 'Z') {
2225				s[pos] = 'A';
2226				carry=1;
2227			} else {
2228				s[pos]++;
2229				carry=0;
2230			}
2231			last=UPPER_CASE;
2232		} else if (ch >= '0' && ch <= '9') {
2233			if (ch == '9') {
2234				s[pos] = '0';
2235				carry=1;
2236			} else {
2237				s[pos]++;
2238				carry=0;
2239			}
2240			last = NUMERIC;
2241		} else {
2242			carry=0;
2243			break;
2244		}
2245		if (carry == 0) {
2246			break;
2247		}
2248	} while (pos-- > 0);
2249
2250	if (carry) {
2251		t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2252		memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2253		ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2254		switch (last) {
2255			case NUMERIC:
2256				ZSTR_VAL(t)[0] = '1';
2257				break;
2258			case UPPER_CASE:
2259				ZSTR_VAL(t)[0] = 'A';
2260				break;
2261			case LOWER_CASE:
2262				ZSTR_VAL(t)[0] = 'a';
2263				break;
2264		}
2265		zend_string_free(Z_STR_P(str));
2266		ZVAL_NEW_STR(str, t);
2267	}
2268}
2269/* }}} */
2270
2271ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2272{
2273try_again:
2274	switch (Z_TYPE_P(op1)) {
2275		case IS_LONG:
2276			fast_long_increment_function(op1);
2277			break;
2278		case IS_DOUBLE:
2279			Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2280			break;
2281		case IS_NULL:
2282			ZVAL_LONG(op1, 1);
2283			break;
2284		case IS_STRING: {
2285				zend_long lval;
2286				double dval;
2287
2288				switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2289					case IS_LONG:
2290						zend_string_release(Z_STR_P(op1));
2291						if (lval == ZEND_LONG_MAX) {
2292							/* switch to double */
2293							double d = (double)lval;
2294							ZVAL_DOUBLE(op1, d+1);
2295						} else {
2296							ZVAL_LONG(op1, lval+1);
2297						}
2298						break;
2299					case IS_DOUBLE:
2300						zend_string_release(Z_STR_P(op1));
2301						ZVAL_DOUBLE(op1, dval+1);
2302						break;
2303					default:
2304						/* Perl style string increment */
2305						increment_string(op1);
2306						break;
2307				}
2308			}
2309			break;
2310		case IS_OBJECT:
2311			if (Z_OBJ_HANDLER_P(op1, get)
2312			   && Z_OBJ_HANDLER_P(op1, set)) {
2313				/* proxy object */
2314				zval rv;
2315				zval *val;
2316
2317				val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2318				Z_TRY_ADDREF_P(val);
2319				increment_function(val);
2320				Z_OBJ_HANDLER_P(op1, set)(op1, val);
2321				zval_ptr_dtor(val);
2322			} else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2323				zval op2;
2324				int res;
2325
2326				ZVAL_LONG(&op2, 1);
2327				res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2);
2328				zval_ptr_dtor(&op2);
2329
2330				return res;
2331			}
2332			return FAILURE;
2333		case IS_REFERENCE:
2334			op1 = Z_REFVAL_P(op1);
2335			goto try_again;
2336		default:
2337			return FAILURE;
2338	}
2339	return SUCCESS;
2340}
2341/* }}} */
2342
2343ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2344{
2345	zend_long lval;
2346	double dval;
2347
2348try_again:
2349	switch (Z_TYPE_P(op1)) {
2350		case IS_LONG:
2351			fast_long_decrement_function(op1);
2352			break;
2353		case IS_DOUBLE:
2354			Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2355			break;
2356		case IS_STRING:		/* Like perl we only support string increment */
2357			if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2358				zend_string_release(Z_STR_P(op1));
2359				ZVAL_LONG(op1, -1);
2360				break;
2361			}
2362			switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2363				case IS_LONG:
2364					zend_string_release(Z_STR_P(op1));
2365					if (lval == ZEND_LONG_MIN) {
2366						double d = (double)lval;
2367						ZVAL_DOUBLE(op1, d-1);
2368					} else {
2369						ZVAL_LONG(op1, lval-1);
2370					}
2371					break;
2372				case IS_DOUBLE:
2373					zend_string_release(Z_STR_P(op1));
2374					ZVAL_DOUBLE(op1, dval - 1);
2375					break;
2376			}
2377			break;
2378		case IS_OBJECT:
2379			if (Z_OBJ_HANDLER_P(op1, get)
2380			   && Z_OBJ_HANDLER_P(op1, set)) {
2381				/* proxy object */
2382				zval rv;
2383				zval *val;
2384
2385				val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2386				Z_TRY_ADDREF_P(val);
2387				decrement_function(val);
2388				Z_OBJ_HANDLER_P(op1, set)(op1, val);
2389				zval_ptr_dtor(val);
2390			} else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2391				zval op2;
2392				int res;
2393
2394				ZVAL_LONG(&op2, 1);
2395				res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2);
2396				zval_ptr_dtor(&op2);
2397
2398				return res;
2399			}
2400			return FAILURE;
2401		case IS_REFERENCE:
2402			op1 = Z_REFVAL_P(op1);
2403			goto try_again;
2404		default:
2405			return FAILURE;
2406	}
2407
2408	return SUCCESS;
2409}
2410/* }}} */
2411
2412ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
2413{
2414	return i_zend_is_true(op);
2415}
2416/* }}} */
2417
2418ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
2419{
2420	if (Z_OBJ_HT_P(op)->cast_object) {
2421		zval tmp;
2422		if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, _IS_BOOL) == SUCCESS) {
2423			return Z_TYPE(tmp) == IS_TRUE;
2424		}
2425		zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to boolean", ZSTR_VAL(Z_OBJ_P(op)->ce->name));
2426	} else if (Z_OBJ_HT_P(op)->get) {
2427		int result;
2428		zval rv;
2429		zval *tmp = Z_OBJ_HT_P(op)->get(op, &rv);
2430
2431		if (Z_TYPE_P(tmp) != IS_OBJECT) {
2432			/* for safety - avoid loop */
2433			result = i_zend_is_true(tmp);
2434			zval_ptr_dtor(tmp);
2435			return result;
2436		}
2437	}
2438	return 1;
2439}
2440/* }}} */
2441
2442#ifdef ZEND_USE_TOLOWER_L
2443ZEND_API void zend_update_current_locale(void) /* {{{ */
2444{
2445	current_locale = _get_current_locale();
2446}
2447/* }}} */
2448#endif
2449
2450ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2451{
2452	register unsigned char *str = (unsigned char*)source;
2453	register unsigned char *result = (unsigned char*)dest;
2454	register unsigned char *end = str + length;
2455
2456	while (str < end) {
2457		*result++ = zend_tolower_ascii(*str++);
2458	}
2459	*result = '\0';
2460
2461	return dest;
2462}
2463/* }}} */
2464
2465ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2466{
2467	return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2468}
2469/* }}} */
2470
2471ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2472{
2473	register unsigned char *p = (unsigned char*)str;
2474	register unsigned char *end = p + length;
2475
2476	while (p < end) {
2477		*p = zend_tolower_ascii(*p);
2478		p++;
2479	}
2480}
2481/* }}} */
2482
2483ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
2484{
2485	register const unsigned char *p = (const unsigned char*)source;
2486	register const unsigned char *end = p + length;
2487
2488	while (p < end) {
2489		if (*p != zend_tolower_ascii(*p)) {
2490			char *res = (char*)emalloc(length + 1);
2491			register unsigned char *r;
2492
2493			if (p != (const unsigned char*)source) {
2494				memcpy(res, source, p - (const unsigned char*)source);
2495			}
2496			r = (unsigned char*)p + (res - source);
2497			while (p < end) {
2498				*r = zend_tolower_ascii(*p);
2499				p++;
2500				r++;
2501			}
2502			*r = '\0';
2503			return res;
2504		}
2505		p++;
2506	}
2507	return NULL;
2508}
2509/* }}} */
2510
2511ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower(zend_string *str) /* {{{ */
2512{
2513	register unsigned char *p = (unsigned char*)ZSTR_VAL(str);
2514	register unsigned char *end = p + ZSTR_LEN(str);
2515
2516	while (p < end) {
2517		if (*p != zend_tolower_ascii(*p)) {
2518			zend_string *res = zend_string_alloc(ZSTR_LEN(str), 0);
2519			register unsigned char *r;
2520
2521			if (p != (unsigned char*)ZSTR_VAL(str)) {
2522				memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*)ZSTR_VAL(str));
2523			}
2524			r = p + (ZSTR_VAL(res) - ZSTR_VAL(str));
2525			while (p < end) {
2526				*r = zend_tolower_ascii(*p);
2527				p++;
2528				r++;
2529			}
2530			*r = '\0';
2531			return res;
2532		}
2533		p++;
2534	}
2535	return zend_string_copy(str);
2536}
2537/* }}} */
2538
2539ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2540{
2541	int retval;
2542
2543	if (s1 == s2) {
2544		return 0;
2545	}
2546	retval = memcmp(s1, s2, MIN(len1, len2));
2547	if (!retval) {
2548		return (int)(len1 - len2);
2549	} else {
2550		return retval;
2551	}
2552}
2553/* }}} */
2554
2555ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2556{
2557	int retval;
2558
2559	if (s1 == s2) {
2560		return 0;
2561	}
2562	retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2563	if (!retval) {
2564		return (int)(MIN(length, len1) - MIN(length, len2));
2565	} else {
2566		return retval;
2567	}
2568}
2569/* }}} */
2570
2571ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2572{
2573	size_t len;
2574	int c1, c2;
2575
2576	if (s1 == s2) {
2577		return 0;
2578	}
2579
2580	len = MIN(len1, len2);
2581	while (len--) {
2582		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2583		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2584		if (c1 != c2) {
2585			return c1 - c2;
2586		}
2587	}
2588
2589	return (int)(len1 - len2);
2590}
2591/* }}} */
2592
2593ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2594{
2595	size_t len;
2596	int c1, c2;
2597
2598	if (s1 == s2) {
2599		return 0;
2600	}
2601	len = MIN(length, MIN(len1, len2));
2602	while (len--) {
2603		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2604		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2605		if (c1 != c2) {
2606			return c1 - c2;
2607		}
2608	}
2609
2610	return (int)(MIN(length, len1) - MIN(length, len2));
2611}
2612/* }}} */
2613
2614ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2615{
2616	size_t len;
2617	int c1, c2;
2618
2619	if (s1 == s2) {
2620		return 0;
2621	}
2622
2623	len = MIN(len1, len2);
2624	while (len--) {
2625		c1 = zend_tolower((int)*(unsigned char *)s1++);
2626		c2 = zend_tolower((int)*(unsigned char *)s2++);
2627		if (c1 != c2) {
2628			return c1 - c2;
2629		}
2630	}
2631
2632	return (int)(len1 - len2);
2633}
2634/* }}} */
2635
2636ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2637{
2638	size_t len;
2639	int c1, c2;
2640
2641	if (s1 == s2) {
2642		return 0;
2643	}
2644	len = MIN(length, MIN(len1, len2));
2645	while (len--) {
2646		c1 = zend_tolower((int)*(unsigned char *)s1++);
2647		c2 = zend_tolower((int)*(unsigned char *)s2++);
2648		if (c1 != c2) {
2649			return c1 - c2;
2650		}
2651	}
2652
2653	return (int)(MIN(length, len1) - MIN(length, len2));
2654}
2655/* }}} */
2656
2657ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2658{
2659	return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2660}
2661/* }}} */
2662
2663ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2664{
2665	return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2666}
2667/* }}} */
2668
2669ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2670{
2671	return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2672}
2673/* }}} */
2674
2675ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2676{
2677	return zend_binary_strncasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2678}
2679/* }}} */
2680
2681ZEND_API zend_long ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
2682{
2683	int ret1, ret2;
2684	int oflow1, oflow2;
2685	zend_long lval1 = 0, lval2 = 0;
2686	double dval1 = 0.0, dval2 = 0.0;
2687
2688	if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
2689		(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
2690#if ZEND_ULONG_MAX == 0xFFFFFFFF
2691		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2692			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2693			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
2694#else
2695		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2696#endif
2697			/* both values are integers overflown to the same side, and the
2698			 * double comparison may have resulted in crucial accuracy lost */
2699			goto string_cmp;
2700		}
2701		if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2702			if (ret1 != IS_DOUBLE) {
2703				if (oflow2) {
2704					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2705					return -1 * oflow2;
2706				}
2707				dval1 = (double) lval1;
2708			} else if (ret2 != IS_DOUBLE) {
2709				if (oflow1) {
2710					return oflow1;
2711				}
2712				dval2 = (double) lval2;
2713			} else if (dval1 == dval2 && !zend_finite(dval1)) {
2714				/* Both values overflowed and have the same sign,
2715				 * so a numeric comparison would be inaccurate */
2716				goto string_cmp;
2717			}
2718			dval1 = dval1 - dval2;
2719			return ZEND_NORMALIZE_BOOL(dval1);
2720		} else { /* they both have to be long's */
2721			return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
2722		}
2723	} else {
2724		int strcmp_ret;
2725string_cmp:
2726		strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
2727		return ZEND_NORMALIZE_BOOL(strcmp_ret);
2728	}
2729}
2730/* }}} */
2731
2732static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
2733{
2734	zval result;
2735
2736	if (compare_function(&result, z1, z2)==FAILURE) {
2737		return 1;
2738	}
2739	return Z_LVAL(result);
2740}
2741/* }}} */
2742
2743ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
2744{
2745	return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
2746}
2747/* }}} */
2748
2749ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
2750{
2751	return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
2752}
2753/* }}} */
2754
2755ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
2756{
2757	if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2758		return 0;
2759	}
2760
2761	if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2762		return 1;
2763	} else {
2764		return Z_OBJ_HT_P(o1)->compare_objects(o1, o2);
2765	}
2766}
2767/* }}} */
2768
2769ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2770{
2771	zend_string *str;
2772
2773	str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2774	ZVAL_NEW_STR(op, str);
2775}
2776/* }}} */
2777
2778ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
2779{
2780	char buf[MAX_LENGTH_OF_LONG + 1];
2781	char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
2782	return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
2783}
2784/* }}} */
2785
2786ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
2787    return is_numeric_string_ex(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, -1, NULL);
2788}
2789/* }}} */
2790
2791ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) /* {{{ */
2792{
2793	const char *ptr;
2794	int digits = 0, dp_or_e = 0;
2795	double local_dval = 0.0;
2796	zend_uchar type;
2797	zend_long tmp_lval = 0;
2798	int neg = 0;
2799
2800	if (!length) {
2801		return 0;
2802	}
2803
2804	if (oflow_info != NULL) {
2805		*oflow_info = 0;
2806	}
2807
2808	/* Skip any whitespace
2809	 * This is much faster than the isspace() function */
2810	while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
2811		str++;
2812		length--;
2813	}
2814	ptr = str;
2815
2816	if (*ptr == '-') {
2817		neg = 1;
2818		ptr++;
2819	} else if (*ptr == '+') {
2820		ptr++;
2821	}
2822
2823	if (ZEND_IS_DIGIT(*ptr)) {
2824		/* Skip any leading 0s */
2825		while (*ptr == '0') {
2826			ptr++;
2827		}
2828
2829		/* Count the number of digits. If a decimal point/exponent is found,
2830		 * it's a double. Otherwise, if there's a dval or no need to check for
2831		 * a full match, stop when there are too many digits for a long */
2832		for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
2833check_digits:
2834			if (ZEND_IS_DIGIT(*ptr)) {
2835				tmp_lval = tmp_lval * 10 + (*ptr) - '0';
2836				continue;
2837			} else if (*ptr == '.' && dp_or_e < 1) {
2838				goto process_double;
2839			} else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
2840				const char *e = ptr + 1;
2841
2842				if (*e == '-' || *e == '+') {
2843					ptr = e++;
2844				}
2845				if (ZEND_IS_DIGIT(*e)) {
2846					goto process_double;
2847				}
2848			}
2849
2850			break;
2851		}
2852
2853		if (digits >= MAX_LENGTH_OF_LONG) {
2854			if (oflow_info != NULL) {
2855				*oflow_info = *str == '-' ? -1 : 1;
2856			}
2857			dp_or_e = -1;
2858			goto process_double;
2859		}
2860	} else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
2861process_double:
2862		type = IS_DOUBLE;
2863
2864		/* If there's a dval, do the conversion; else continue checking
2865		 * the digits if we need to check for a full match */
2866		if (dval) {
2867			local_dval = zend_strtod(str, &ptr);
2868		} else if (allow_errors != 1 && dp_or_e != -1) {
2869			dp_or_e = (*ptr++ == '.') ? 1 : 2;
2870			goto check_digits;
2871		}
2872	} else {
2873		return 0;
2874	}
2875
2876	if (ptr != str + length) {
2877		if (!allow_errors) {
2878			return 0;
2879		}
2880		if (allow_errors == -1) {
2881			zend_error(E_NOTICE, "A non well formed numeric value encountered");
2882		}
2883	}
2884
2885	if (type == IS_LONG) {
2886		if (digits == MAX_LENGTH_OF_LONG - 1) {
2887			int cmp = strcmp(&ptr[-digits], long_min_digits);
2888
2889			if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
2890				if (dval) {
2891					*dval = zend_strtod(str, NULL);
2892				}
2893				if (oflow_info != NULL) {
2894					*oflow_info = *str == '-' ? -1 : 1;
2895				}
2896
2897				return IS_DOUBLE;
2898			}
2899		}
2900
2901		if (lval) {
2902			if (neg) {
2903				tmp_lval = -tmp_lval;
2904			}
2905			*lval = tmp_lval;
2906		}
2907
2908		return IS_LONG;
2909	} else {
2910		if (dval) {
2911			*dval = local_dval;
2912		}
2913
2914		return IS_DOUBLE;
2915	}
2916}
2917/* }}} */
2918
2919/*
2920 * String matching - Sunday algorithm
2921 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
2922 */
2923static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
2924	int i;
2925
2926	for (i = 0; i < 256; i++) {
2927		td[i] = needle_len + 1;
2928	}
2929
2930	if (reverse) {
2931		for (i = needle_len - 1; i >= 0; i--) {
2932			td[(unsigned char)needle[i]] = i + 1;
2933		}
2934	} else {
2935		size_t i;
2936
2937		for (i = 0; i < needle_len; i++) {
2938			td[(unsigned char)needle[i]] = (int)needle_len - i;
2939		}
2940	}
2941}
2942/* }}} */
2943
2944ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
2945{
2946	unsigned int td[256];
2947	register size_t i;
2948	register const char *p;
2949
2950	if (needle_len == 0 || (end - haystack) == 0) {
2951		return NULL;
2952	}
2953
2954	zend_memnstr_ex_pre(td, needle, needle_len, 0);
2955
2956	p = haystack;
2957	end -= needle_len;
2958
2959	while (p <= end) {
2960		for (i = 0; i < needle_len; i++) {
2961			if (needle[i] != p[i]) {
2962				break;
2963			}
2964		}
2965		if (i == needle_len) {
2966			return p;
2967		}
2968		p += td[(unsigned char)(p[needle_len])];
2969	}
2970
2971	return NULL;
2972}
2973/* }}} */
2974
2975ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
2976{
2977	unsigned int td[256];
2978	register size_t i;
2979	register const char *p;
2980
2981	if (needle_len == 0 || (end - haystack) == 0) {
2982		return NULL;
2983	}
2984
2985	zend_memnstr_ex_pre(td, needle, needle_len, 1);
2986
2987	p = end;
2988	p -= needle_len;
2989
2990	while (p >= haystack) {
2991		for (i = 0; i < needle_len; i++) {
2992			if (needle[i] != p[i]) {
2993				break;
2994			}
2995		}
2996
2997		if (i == needle_len) {
2998			return (const char *)p;
2999		}
3000
3001		if (UNEXPECTED(p == haystack)) {
3002			return NULL;
3003		}
3004
3005		p -= td[(unsigned char)(p[-1])];
3006	}
3007
3008	return NULL;
3009}
3010/* }}} */
3011
3012#if !ZEND_DVAL_TO_LVAL_CAST_OK
3013# if SIZEOF_ZEND_LONG == 4
3014ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3015{
3016	double	two_pow_32 = pow(2., 32.),
3017			dmod;
3018
3019	dmod = fmod(d, two_pow_32);
3020	if (dmod < 0) {
3021		/* we're going to make this number positive; call ceil()
3022		 * to simulate rounding towards 0 of the negative number */
3023		dmod = ceil(dmod);// + two_pow_32;
3024	}
3025	return (zend_long)(zend_ulong)dmod;
3026}
3027#else
3028ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3029{
3030	double	two_pow_64 = pow(2., 64.),
3031			dmod;
3032
3033	dmod = fmod(d, two_pow_64);
3034	if (dmod < 0) {
3035		/* no need to call ceil; original double must have had no
3036		 * fractional part, hence dmod does not have one either */
3037		dmod += two_pow_64;
3038	}
3039	return (zend_long)(zend_ulong)dmod;
3040}
3041#endif
3042#endif
3043
3044/*
3045 * Local variables:
3046 * tab-width: 4
3047 * c-basic-offset: 4
3048 * indent-tabs-mode: t
3049 * End:
3050 */
3051