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