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