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 = (int)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 = (int)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
1284            ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1285            for (i = 0; i < Z_STRLEN_P(op1); i++) {
1286                Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1287            }
1288            Z_STRVAL_P(result)[i] = 0;
1289            return SUCCESS;
1290        }
1291        default:
1292            ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1293
1294            zend_error(E_ERROR, "Unsupported operand types");
1295            return FAILURE;
1296    }
1297}
1298/* }}} */
1299
1300ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1301{
1302    zval op1_copy, op2_copy;
1303    zend_long op1_lval;
1304
1305    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1306        zval *longer, *shorter;
1307        zend_string *str;
1308        size_t i;
1309
1310        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1311            longer = op1;
1312            shorter = op2;
1313        } else {
1314            longer = op2;
1315            shorter = op1;
1316        }
1317
1318        str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1319        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1320            str->val[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1321        }
1322        memcpy(str->val + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1323        if (result==op1) {
1324            zend_string_release(Z_STR_P(result));
1325        }
1326        ZVAL_NEW_STR(result, str);
1327        return SUCCESS;
1328    }
1329
1330    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1331        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
1332        zendi_convert_to_long(op1, op1_copy, result);
1333    }
1334    op1_lval = Z_LVAL_P(op1);
1335    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1336        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1337        zendi_convert_to_long(op2, op2_copy, result);
1338    }
1339
1340    ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1341    return SUCCESS;
1342}
1343/* }}} */
1344
1345ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1346{
1347    zval op1_copy, op2_copy;
1348    zend_long op1_lval;
1349
1350    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1351        zval *longer, *shorter;
1352        zend_string *str;
1353        size_t i;
1354
1355        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1356            longer = op1;
1357            shorter = op2;
1358        } else {
1359            longer = op2;
1360            shorter = op1;
1361        }
1362
1363        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1364        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1365            str->val[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1366        }
1367        str->val[i] = 0;
1368        if (result==op1) {
1369            zend_string_release(Z_STR_P(result));
1370        }
1371        ZVAL_NEW_STR(result, str);
1372        return SUCCESS;
1373    }
1374
1375    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1376        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function);
1377        zendi_convert_to_long(op1, op1_copy, result);
1378    }
1379    op1_lval = Z_LVAL_P(op1);
1380    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1381        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1382        zendi_convert_to_long(op2, op2_copy, result);
1383    }
1384
1385    ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1386    return SUCCESS;
1387}
1388/* }}} */
1389
1390ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1391{
1392    zval op1_copy, op2_copy;
1393    zend_long op1_lval;
1394
1395    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1396        zval *longer, *shorter;
1397        zend_string *str;
1398        size_t i;
1399
1400        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1401            longer = op1;
1402            shorter = op2;
1403        } else {
1404            longer = op2;
1405            shorter = op1;
1406        }
1407
1408        str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1409        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1410            str->val[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1411        }
1412        str->val[i] = 0;
1413        if (result==op1) {
1414            zend_string_release(Z_STR_P(result));
1415        }
1416        ZVAL_NEW_STR(result, str);
1417        return SUCCESS;
1418    }
1419
1420    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1421        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function);
1422        zendi_convert_to_long(op1, op1_copy, result);
1423    }
1424    op1_lval = Z_LVAL_P(op1);
1425    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1426        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1427        zendi_convert_to_long(op2, op2_copy, result);
1428    }
1429
1430    ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1431    return SUCCESS;
1432}
1433/* }}} */
1434
1435ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1436{
1437    zval op1_copy, op2_copy;
1438    zend_long op1_lval;
1439
1440    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1441        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_SL, shift_left_function);
1442        zendi_convert_to_long(op1, op1_copy, result);
1443    }
1444    op1_lval = Z_LVAL_P(op1);
1445    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1446        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_SL);
1447        zendi_convert_to_long(op2, op2_copy, result);
1448    }
1449
1450    /* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1451    if (Z_LVAL_P(op2) >= SIZEOF_ZEND_LONG * 8) {
1452        ZVAL_LONG(result, 0);
1453        return SUCCESS;
1454    }
1455
1456    if (Z_LVAL_P(op2) < 0) {
1457        zend_error(E_WARNING, "Bit shift by negative number");
1458        ZVAL_FALSE(result);
1459        return FAILURE;
1460    }
1461
1462    ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1463    return SUCCESS;
1464}
1465/* }}} */
1466
1467ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1468{
1469    zval op1_copy, op2_copy;
1470    zend_long op1_lval;
1471
1472    if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1473        ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_SR, shift_right_function);
1474        zendi_convert_to_long(op1, op1_copy, result);
1475    }
1476    op1_lval = Z_LVAL_P(op1);
1477    if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1478        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_SR);
1479        zendi_convert_to_long(op2, op2_copy, result);
1480    }
1481
1482    /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1483    if (Z_LVAL_P(op2) >= SIZEOF_ZEND_LONG * 8) {
1484        ZVAL_LONG(result, (Z_LVAL_P(op1) < 0) ? -1 : 0);
1485        return SUCCESS;
1486    }
1487
1488    if (Z_LVAL_P(op2) < 0) {
1489        zend_error(E_WARNING, "Bit shift by negative number");
1490        ZVAL_FALSE(result);
1491        return FAILURE;
1492    }
1493
1494    ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1495    return SUCCESS;
1496}
1497/* }}} */
1498
1499/* must support result==op1 */
1500ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1501{
1502    size_t length = Z_STRLEN_P(op1) + 1;
1503    zend_string *buf = zend_string_realloc(Z_STR_P(op1), length, 0);
1504
1505    buf->val[length - 1] = (char) Z_LVAL_P(op2);
1506    buf->val[length] = 0;
1507    ZVAL_NEW_STR(result, buf);
1508    return SUCCESS;
1509}
1510/* }}} */
1511
1512/* must support result==op1 */
1513ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1514{
1515    size_t op1_len = Z_STRLEN_P(op1);
1516    size_t length = op1_len + Z_STRLEN_P(op2);
1517    zend_string *buf = zend_string_realloc(Z_STR_P(op1), length, 0);
1518
1519    memcpy(buf->val + op1_len, Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1520    buf->val[length] = 0;
1521    ZVAL_NEW_STR(result, buf);
1522    return SUCCESS;
1523}
1524/* }}} */
1525
1526ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1527{
1528    zval op1_copy, op2_copy;
1529    int use_copy1 = 0, use_copy2 = 0;
1530
1531    if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
1532        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
1533        use_copy1 = zend_make_printable_zval(op1, &op1_copy TSRMLS_CC);
1534        if (use_copy1) {
1535            /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1536             * we have to free it.
1537             */
1538            if (result == op1) {
1539                zval_dtor(op1);
1540                if (UNEXPECTED(op1 == op2)) {
1541                    op2 = &op1_copy;
1542                }
1543            }
1544            op1 = &op1_copy;
1545        }
1546    }
1547    if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
1548        ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
1549        use_copy2 = zend_make_printable_zval(op2, &op2_copy TSRMLS_CC);
1550        if (use_copy2) {
1551            op2 = &op2_copy;
1552        }
1553    }
1554
1555    {
1556        size_t op1_len = Z_STRLEN_P(op1);
1557        size_t op2_len = Z_STRLEN_P(op2);
1558        size_t result_len = op1_len + op2_len;
1559        zend_string *result_str;
1560
1561        if (op1_len > SIZE_MAX - op2_len) {
1562            zend_error_noreturn(E_ERROR, "String size overflow");
1563        }
1564
1565        if (result == op1 && Z_REFCOUNTED_P(result)) {
1566            /* special case, perform operations on result */
1567            result_str = zend_string_realloc(Z_STR_P(result), result_len, 0);
1568        } else {
1569            result_str = zend_string_alloc(result_len, 0);
1570            memcpy(result_str->val, Z_STRVAL_P(op1), op1_len);
1571        }
1572
1573        /* This has to happen first to account for the cases where result == op1 == op2 and
1574         * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1575         * point to the new string. The first op2_len bytes of result will still be the same. */
1576        ZVAL_NEW_STR(result, result_str);
1577
1578        memcpy(result_str->val + op1_len, Z_STRVAL_P(op2), op2_len);
1579        result_str->val[result_len] = '\0';
1580    }
1581
1582    if (UNEXPECTED(use_copy1)) {
1583        zval_dtor(op1);
1584    }
1585    if (UNEXPECTED(use_copy2)) {
1586        zval_dtor(op2);
1587    }
1588    return SUCCESS;
1589}
1590/* }}} */
1591
1592ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1593{
1594    zend_string *str1 = zval_get_string(op1);
1595    zend_string *str2 = zval_get_string(op2);
1596
1597    if (case_insensitive) {
1598        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1599    } else {
1600        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1601    }
1602
1603    zend_string_release(str1);
1604    zend_string_release(str2);
1605    return SUCCESS;
1606}
1607/* }}} */
1608
1609ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1610{
1611    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1612        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1613        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1614            ZVAL_LONG(result, 0);
1615        } else {
1616            ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1617        }
1618    } else {
1619        zend_string *str1 = zval_get_string(op1);
1620        zend_string *str2 = zval_get_string(op2);
1621
1622        ZVAL_LONG(result, zend_binary_strcmp(str1->val, str1->len, str2->val, str2->len));
1623
1624        zend_string_release(str1);
1625        zend_string_release(str2);
1626    }
1627    return SUCCESS;
1628}
1629/* }}} */
1630
1631ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1632{
1633    if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1634        EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1635        if (Z_STR_P(op1) == Z_STR_P(op2)) {
1636            ZVAL_LONG(result, 0);
1637        } else {
1638            ZVAL_LONG(result, zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1639        }
1640    } else {
1641        zend_string *str1 = zval_get_string(op1);
1642        zend_string *str2 = zval_get_string(op2);
1643
1644        ZVAL_LONG(result, zend_binary_strcasecmp_l(str1->val, str1->len, str2->val, str1->len));
1645
1646        zend_string_release(str1);
1647        zend_string_release(str2);
1648    }
1649    return SUCCESS;
1650}
1651/* }}} */
1652
1653#if HAVE_STRCOLL
1654ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1655{
1656    zend_string *str1 = zval_get_string(op1);
1657    zend_string *str2 = zval_get_string(op2);
1658
1659    ZVAL_LONG(result, strcoll(str1->val, str2->val));
1660
1661    zend_string_release(str1);
1662    zend_string_release(str2);
1663    return SUCCESS;
1664}
1665/* }}} */
1666#endif
1667
1668ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1669{
1670    double d1, d2;
1671
1672    d1 = zval_get_double(op1);
1673    d2 = zval_get_double(op2);
1674
1675    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(d1 - d2));
1676
1677    return SUCCESS;
1678}
1679/* }}} */
1680
1681static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1682{
1683    if (Z_REFCOUNTED_P(op)) {
1684        if (Z_REFCOUNT_P(op) == 0) {
1685            zval_dtor(op);
1686        } else {
1687            zval_ptr_dtor(op);
1688        }
1689    }
1690}
1691/* }}} */
1692
1693ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1694{
1695    int ret;
1696    int converted = 0;
1697    zval op1_copy, op2_copy;
1698    zval *op_free, tmp_free;
1699
1700    while (1) {
1701        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1702            case TYPE_PAIR(IS_LONG, IS_LONG):
1703                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1704                return SUCCESS;
1705
1706            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1707                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1708                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1709                return SUCCESS;
1710
1711            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1712                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1713                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1714                return SUCCESS;
1715
1716            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1717                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1718                    ZVAL_LONG(result, 0);
1719                } else {
1720                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1721                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1722                }
1723                return SUCCESS;
1724
1725            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1726                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1727                return SUCCESS;
1728
1729            case TYPE_PAIR(IS_NULL, IS_NULL):
1730            case TYPE_PAIR(IS_NULL, IS_FALSE):
1731            case TYPE_PAIR(IS_FALSE, IS_NULL):
1732            case TYPE_PAIR(IS_FALSE, IS_FALSE):
1733            case TYPE_PAIR(IS_TRUE, IS_TRUE):
1734                ZVAL_LONG(result, 0);
1735                return SUCCESS;
1736
1737            case TYPE_PAIR(IS_NULL, IS_TRUE):
1738                ZVAL_LONG(result, -1);
1739                return SUCCESS;
1740
1741            case TYPE_PAIR(IS_TRUE, IS_NULL):
1742                ZVAL_LONG(result, 1);
1743                return SUCCESS;
1744
1745            case TYPE_PAIR(IS_STRING, IS_STRING):
1746                if (Z_STR_P(op1) == Z_STR_P(op2)) {
1747                    ZVAL_LONG(result, 0);
1748                    return SUCCESS;
1749                }
1750                zendi_smart_strcmp(result, op1, op2);
1751                return SUCCESS;
1752
1753            case TYPE_PAIR(IS_NULL, IS_STRING):
1754                ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
1755                return SUCCESS;
1756
1757            case TYPE_PAIR(IS_STRING, IS_NULL):
1758                ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
1759                return SUCCESS;
1760
1761            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1762                ZVAL_LONG(result, 1);
1763                return SUCCESS;
1764
1765            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1766                ZVAL_LONG(result, -1);
1767                return SUCCESS;
1768
1769            default:
1770                if (Z_ISREF_P(op1)) {
1771                    op1 = Z_REFVAL_P(op1);
1772                    continue;
1773                } else if (Z_ISREF_P(op2)) {
1774                    op2 = Z_REFVAL_P(op2);
1775                    continue;
1776                }
1777
1778                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1779                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
1780                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1781                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
1782                }
1783
1784                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1785                    if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
1786                        /* object handles are identical, apparently this is the same object */
1787                        ZVAL_LONG(result, 0);
1788                        return SUCCESS;
1789                    }
1790                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1791                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
1792                        return SUCCESS;
1793                    }
1794                }
1795                if (Z_TYPE_P(op1) == IS_OBJECT) {
1796                    if (Z_OBJ_HT_P(op1)->get) {
1797                        zval rv;
1798                        op_free = Z_OBJ_HT_P(op1)->get(op1, &rv TSRMLS_CC);
1799                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1800                        zend_free_obj_get_result(op_free TSRMLS_CC);
1801                        return ret;
1802                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1803                        ZVAL_UNDEF(&tmp_free);
1804                        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) {
1805                            ZVAL_LONG(result, 1);
1806                            zend_free_obj_get_result(&tmp_free TSRMLS_CC);
1807                            return SUCCESS;
1808                        }
1809                        ret = compare_function(result, &tmp_free, op2 TSRMLS_CC);
1810                        zend_free_obj_get_result(&tmp_free TSRMLS_CC);
1811                        return ret;
1812                    }
1813                }
1814                if (Z_TYPE_P(op2) == IS_OBJECT) {
1815                    if (Z_OBJ_HT_P(op2)->get) {
1816                        zval rv;
1817                        op_free = Z_OBJ_HT_P(op2)->get(op2, &rv TSRMLS_CC);
1818                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1819                        zend_free_obj_get_result(op_free TSRMLS_CC);
1820                        return ret;
1821                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1822                        ZVAL_UNDEF(&tmp_free);
1823                        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) {
1824                            ZVAL_LONG(result, -1);
1825                            zend_free_obj_get_result(&tmp_free TSRMLS_CC);
1826                            return SUCCESS;
1827                        }
1828                        ret = compare_function(result, op1, &tmp_free TSRMLS_CC);
1829                        zend_free_obj_get_result(&tmp_free TSRMLS_CC);
1830                        return ret;
1831                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1832                        ZVAL_LONG(result, 1);
1833                        return SUCCESS;
1834                    }
1835                }
1836                if (!converted) {
1837                    if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1838                        zendi_convert_to_boolean(op2, op2_copy, result);
1839                        ZVAL_LONG(result, (Z_TYPE_P(op2) == IS_TRUE) ? -1 : 0);
1840                        return SUCCESS;
1841                    } else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) {
1842                        zendi_convert_to_boolean(op1, op1_copy, result);
1843                        ZVAL_LONG(result, (Z_TYPE_P(op1) == IS_TRUE) ? 1 : 0);
1844                        return SUCCESS;
1845                    } else if (Z_TYPE_P(op1) == IS_TRUE) {
1846                        zendi_convert_to_boolean(op2, op2_copy, result);
1847                        ZVAL_LONG(result, (Z_TYPE_P(op2) == IS_TRUE) ? 0 : 1);
1848                        return SUCCESS;
1849                    } else if (Z_TYPE_P(op2) == IS_TRUE) {
1850                        zendi_convert_to_boolean(op1, op1_copy, result);
1851                        ZVAL_LONG(result, (Z_TYPE_P(op1) == IS_TRUE) ? 0 : -1);
1852                        return SUCCESS;
1853                    } else {
1854                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1855                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1856                        converted = 1;
1857                    }
1858                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1859                    ZVAL_LONG(result, 1);
1860                    return SUCCESS;
1861                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1862                    ZVAL_LONG(result, -1);
1863                    return SUCCESS;
1864                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1865                    ZVAL_LONG(result, 1);
1866                    return SUCCESS;
1867                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1868                    ZVAL_LONG(result, -1);
1869                    return SUCCESS;
1870                } else {
1871                    ZVAL_LONG(result, 0);
1872                    return FAILURE;
1873                }
1874        }
1875    }
1876}
1877/* }}} */
1878
1879static int hash_zval_identical_function(zval *z1, zval *z2 TSRMLS_DC) /* {{{ */
1880{
1881    zval result;
1882
1883    /* is_identical_function() returns 1 in case of identity and 0 in case
1884     * of a difference;
1885     * whereas this comparison function is expected to return 0 on identity,
1886     * and non zero otherwise.
1887     */
1888    ZVAL_DEREF(z1);
1889    ZVAL_DEREF(z2);
1890    if (is_identical_function(&result, z1, z2 TSRMLS_CC)==FAILURE) {
1891        return 1;
1892    }
1893    return Z_TYPE(result) != IS_TRUE;
1894}
1895/* }}} */
1896
1897ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1898{
1899    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1900        ZVAL_BOOL(result, 0);
1901        return SUCCESS;
1902    }
1903    switch (Z_TYPE_P(op1)) {
1904        case IS_NULL:
1905        case IS_FALSE:
1906        case IS_TRUE:
1907            ZVAL_BOOL(result, 1);
1908            break;
1909        case IS_LONG:
1910            ZVAL_BOOL(result, Z_LVAL_P(op1) == Z_LVAL_P(op2));
1911            break;
1912        case IS_RESOURCE:
1913            ZVAL_BOOL(result, Z_RES_P(op1) == Z_RES_P(op2));
1914            break;
1915        case IS_DOUBLE:
1916            ZVAL_BOOL(result, Z_DVAL_P(op1) == Z_DVAL_P(op2));
1917            break;
1918        case IS_STRING:
1919            if (Z_STR_P(op1) == Z_STR_P(op2)) {
1920                ZVAL_BOOL(result, 1);
1921            } else {
1922                ZVAL_BOOL(result, (Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1923                    && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1924            }
1925            break;
1926        case IS_ARRAY:
1927            ZVAL_BOOL(result, Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1928                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1929            break;
1930        case IS_OBJECT:
1931            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1932                ZVAL_BOOL(result, Z_OBJ_P(op1) == Z_OBJ_P(op2));
1933            } else {
1934                ZVAL_BOOL(result, 0);
1935            }
1936            break;
1937        default:
1938            ZVAL_BOOL(result, 0);
1939            return FAILURE;
1940    }
1941    return SUCCESS;
1942}
1943/* }}} */
1944
1945ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1946{
1947    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1948        return FAILURE;
1949    }
1950    ZVAL_BOOL(result, Z_TYPE_P(result) != IS_TRUE);
1951    return SUCCESS;
1952}
1953/* }}} */
1954
1955ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1956{
1957    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1958        return FAILURE;
1959    }
1960    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1961    return SUCCESS;
1962}
1963/* }}} */
1964
1965ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1966{
1967    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1968        return FAILURE;
1969    }
1970    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1971    return SUCCESS;
1972}
1973/* }}} */
1974
1975ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1976{
1977    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1978        return FAILURE;
1979    }
1980    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1981    return SUCCESS;
1982}
1983/* }}} */
1984
1985ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1986{
1987    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1988        return FAILURE;
1989    }
1990    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1991    return SUCCESS;
1992}
1993/* }}} */
1994
1995ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1996{
1997    uint32_t i;
1998
1999    for (i=0; i<instance_ce->num_interfaces; i++) {
2000        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
2001            return 1;
2002        }
2003    }
2004    if (!interfaces_only) {
2005        while (instance_ce) {
2006            if (instance_ce == ce) {
2007                return 1;
2008            }
2009            instance_ce = instance_ce->parent;
2010        }
2011    }
2012
2013    return 0;
2014}
2015/* }}} */
2016
2017ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
2018{
2019    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
2020}
2021/* }}} */
2022
2023#define LOWER_CASE 1
2024#define UPPER_CASE 2
2025#define NUMERIC 3
2026
2027static void increment_string(zval *str) /* {{{ */
2028{
2029    int carry=0;
2030    size_t pos=Z_STRLEN_P(str)-1;
2031    char *s;
2032    zend_string *t;
2033    int last=0; /* Shut up the compiler warning */
2034    int ch;
2035
2036    if (Z_STRLEN_P(str) == 0) {
2037        zend_string_release(Z_STR_P(str));
2038        Z_STR_P(str) = zend_string_init("1", sizeof("1")-1, 0);
2039        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2040        return;
2041    }
2042
2043    if (!Z_REFCOUNTED_P(str)) {
2044        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2045        Z_TYPE_INFO_P(str) = IS_STRING_EX;
2046    } else if (Z_REFCOUNT_P(str) > 1) {
2047        Z_DELREF_P(str);
2048        Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2049    } else {
2050        zend_string_forget_hash_val(Z_STR_P(str));
2051    }
2052    s = Z_STRVAL_P(str);
2053
2054    do {
2055        ch = s[pos];
2056        if (ch >= 'a' && ch <= 'z') {
2057            if (ch == 'z') {
2058                s[pos] = 'a';
2059                carry=1;
2060            } else {
2061                s[pos]++;
2062                carry=0;
2063            }
2064            last=LOWER_CASE;
2065        } else if (ch >= 'A' && ch <= 'Z') {
2066            if (ch == 'Z') {
2067                s[pos] = 'A';
2068                carry=1;
2069            } else {
2070                s[pos]++;
2071                carry=0;
2072            }
2073            last=UPPER_CASE;
2074        } else if (ch >= '0' && ch <= '9') {
2075            if (ch == '9') {
2076                s[pos] = '0';
2077                carry=1;
2078            } else {
2079                s[pos]++;
2080                carry=0;
2081            }
2082            last = NUMERIC;
2083        } else {
2084            carry=0;
2085            break;
2086        }
2087        if (carry == 0) {
2088            break;
2089        }
2090    } while (pos-- > 0);
2091
2092    if (carry) {
2093        t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2094        memcpy(t->val + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2095        t->val[Z_STRLEN_P(str) + 1] = '\0';
2096        switch (last) {
2097            case NUMERIC:
2098                t->val[0] = '1';
2099                break;
2100            case UPPER_CASE:
2101                t->val[0] = 'A';
2102                break;
2103            case LOWER_CASE:
2104                t->val[0] = 'a';
2105                break;
2106        }
2107        zend_string_free(Z_STR_P(str));
2108        ZVAL_NEW_STR(str, t);
2109    }
2110}
2111/* }}} */
2112
2113ZEND_API int increment_function(zval *op1) /* {{{ */
2114{
2115try_again:
2116    switch (Z_TYPE_P(op1)) {
2117        case IS_LONG:
2118            if (Z_LVAL_P(op1) == ZEND_LONG_MAX) {
2119                /* switch to double */
2120                double d = (double)Z_LVAL_P(op1);
2121                ZVAL_DOUBLE(op1, d+1);
2122            } else {
2123            Z_LVAL_P(op1)++;
2124            }
2125            break;
2126        case IS_DOUBLE:
2127            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2128            break;
2129        case IS_NULL:
2130            ZVAL_LONG(op1, 1);
2131            break;
2132        case IS_STRING: {
2133                zend_long lval;
2134                double dval;
2135
2136                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2137                    case IS_LONG:
2138                        zend_string_release(Z_STR_P(op1));
2139                        if (lval == ZEND_LONG_MAX) {
2140                            /* switch to double */
2141                            double d = (double)lval;
2142                            ZVAL_DOUBLE(op1, d+1);
2143                        } else {
2144                            ZVAL_LONG(op1, lval+1);
2145                        }
2146                        break;
2147                    case IS_DOUBLE:
2148                        zend_string_release(Z_STR_P(op1));
2149                        ZVAL_DOUBLE(op1, dval+1);
2150                        break;
2151                    default:
2152                        /* Perl style string increment */
2153                        increment_string(op1);
2154                        break;
2155                }
2156            }
2157            break;
2158        case IS_OBJECT:
2159            if (Z_OBJ_HANDLER_P(op1, get)
2160               && Z_OBJ_HANDLER_P(op1, set)) {
2161                /* proxy object */
2162                zval rv;
2163                zval *val;
2164                TSRMLS_FETCH();
2165
2166                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv TSRMLS_CC);
2167                Z_ADDREF_P(val);
2168                fast_increment_function(val);
2169                Z_OBJ_HANDLER_P(op1, set)(op1, val TSRMLS_CC);
2170                zval_ptr_dtor(val);
2171            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2172                zval op2;
2173                int res;
2174                TSRMLS_FETCH();
2175
2176                ZVAL_LONG(&op2, 1);
2177                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2 TSRMLS_CC);
2178                zval_ptr_dtor(&op2);
2179
2180                return res;
2181            }
2182            return FAILURE;
2183        case IS_REFERENCE:
2184            op1 = Z_REFVAL_P(op1);
2185            goto try_again;
2186        default:
2187            return FAILURE;
2188    }
2189    return SUCCESS;
2190}
2191/* }}} */
2192
2193ZEND_API int decrement_function(zval *op1) /* {{{ */
2194{
2195    zend_long lval;
2196    double dval;
2197
2198try_again:
2199    switch (Z_TYPE_P(op1)) {
2200        case IS_LONG:
2201            if (Z_LVAL_P(op1) == ZEND_LONG_MIN) {
2202                double d = (double)Z_LVAL_P(op1);
2203                ZVAL_DOUBLE(op1, d-1);
2204            } else {
2205            Z_LVAL_P(op1)--;
2206            }
2207            break;
2208        case IS_DOUBLE:
2209            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2210            break;
2211        case IS_STRING:     /* Like perl we only support string increment */
2212            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2213                zend_string_release(Z_STR_P(op1));
2214                ZVAL_LONG(op1, -1);
2215                break;
2216            }
2217            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2218                case IS_LONG:
2219                    zend_string_release(Z_STR_P(op1));
2220                    if (lval == ZEND_LONG_MIN) {
2221                        double d = (double)lval;
2222                        ZVAL_DOUBLE(op1, d-1);
2223                    } else {
2224                        ZVAL_LONG(op1, lval-1);
2225                    }
2226                    break;
2227                case IS_DOUBLE:
2228                    zend_string_release(Z_STR_P(op1));
2229                    ZVAL_DOUBLE(op1, dval - 1);
2230                    break;
2231            }
2232            break;
2233        case IS_OBJECT:
2234            if (Z_OBJ_HANDLER_P(op1, get)
2235               && Z_OBJ_HANDLER_P(op1, set)) {
2236                /* proxy object */
2237                zval rv;
2238                zval *val;
2239                TSRMLS_FETCH();
2240
2241                val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv TSRMLS_CC);
2242                Z_ADDREF_P(val);
2243                fast_decrement_function(val);
2244                Z_OBJ_HANDLER_P(op1, set)(op1, val TSRMLS_CC);
2245                zval_ptr_dtor(val);
2246            } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2247                zval op2;
2248                int res;
2249                TSRMLS_FETCH();
2250
2251                ZVAL_LONG(&op2, 1);
2252                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2 TSRMLS_CC);
2253                zval_ptr_dtor(&op2);
2254
2255                return res;
2256            }
2257            return FAILURE;
2258        case IS_REFERENCE:
2259            op1 = Z_REFVAL_P(op1);
2260            goto try_again;
2261        default:
2262            return FAILURE;
2263    }
2264
2265    return SUCCESS;
2266}
2267/* }}} */
2268
2269ZEND_API int zval_is_true(zval *op) /* {{{ */
2270{
2271    convert_to_boolean(op);
2272    return (Z_TYPE_P(op) == IS_TRUE ? 1 : 0);
2273}
2274/* }}} */
2275
2276#ifdef ZEND_USE_TOLOWER_L
2277ZEND_API void zend_update_current_locale(void) /* {{{ */
2278{
2279    current_locale = _get_current_locale();
2280}
2281/* }}} */
2282#endif
2283
2284ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2285{
2286    register unsigned char *str = (unsigned char*)source;
2287    register unsigned char *result = (unsigned char*)dest;
2288    register unsigned char *end = str + length;
2289
2290    while (str < end) {
2291        *result++ = zend_tolower_ascii(*str++);
2292    }
2293    *result = '\0';
2294
2295    return dest;
2296}
2297/* }}} */
2298
2299ZEND_API char *zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2300{
2301    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2302}
2303/* }}} */
2304
2305ZEND_API void zend_str_tolower(char *str, size_t length) /* {{{ */
2306{
2307    register unsigned char *p = (unsigned char*)str;
2308    register unsigned char *end = p + length;
2309
2310    while (p < end) {
2311        *p = zend_tolower_ascii(*p);
2312        p++;
2313    }
2314}
2315/* }}} */
2316
2317ZEND_API int zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2318{
2319    int retval;
2320
2321    if (s1 == s2) {
2322        return 0;
2323    }
2324    retval = memcmp(s1, s2, MIN(len1, len2));
2325    if (!retval) {
2326        return (int)(len1 - len2);
2327    } else {
2328        return retval;
2329    }
2330}
2331/* }}} */
2332
2333ZEND_API int zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2334{
2335    int retval;
2336
2337    if (s1 == s2) {
2338        return 0;
2339    }
2340    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2341    if (!retval) {
2342        return (int)(MIN(length, len1) - MIN(length, len2));
2343    } else {
2344        return retval;
2345    }
2346}
2347/* }}} */
2348
2349ZEND_API int zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2350{
2351    size_t len;
2352    int c1, c2;
2353
2354    if (s1 == s2) {
2355        return 0;
2356    }
2357
2358    len = MIN(len1, len2);
2359    while (len--) {
2360        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2361        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2362        if (c1 != c2) {
2363            return c1 - c2;
2364        }
2365    }
2366
2367    return (int)(len1 - len2);
2368}
2369/* }}} */
2370
2371ZEND_API int zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2372{
2373    size_t len;
2374    int c1, c2;
2375
2376    if (s1 == s2) {
2377        return 0;
2378    }
2379    len = MIN(length, MIN(len1, len2));
2380    while (len--) {
2381        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2382        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2383        if (c1 != c2) {
2384            return c1 - c2;
2385        }
2386    }
2387
2388    return (int)(MIN(length, len1) - MIN(length, len2));
2389}
2390/* }}} */
2391
2392ZEND_API int zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2393{
2394    size_t len;
2395    int c1, c2;
2396
2397    if (s1 == s2) {
2398        return 0;
2399    }
2400
2401    len = MIN(len1, len2);
2402    while (len--) {
2403        c1 = zend_tolower((int)*(unsigned char *)s1++);
2404        c2 = zend_tolower((int)*(unsigned char *)s2++);
2405        if (c1 != c2) {
2406            return c1 - c2;
2407        }
2408    }
2409
2410    return (int)(len1 - len2);
2411}
2412/* }}} */
2413
2414ZEND_API int zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2415{
2416    size_t len;
2417    int c1, c2;
2418
2419    if (s1 == s2) {
2420        return 0;
2421    }
2422    len = MIN(length, MIN(len1, len2));
2423    while (len--) {
2424        c1 = zend_tolower((int)*(unsigned char *)s1++);
2425        c2 = zend_tolower((int)*(unsigned char *)s2++);
2426        if (c1 != c2) {
2427            return c1 - c2;
2428        }
2429    }
2430
2431    return (int)(MIN(length, len1) - MIN(length, len2));
2432}
2433/* }}} */
2434
2435ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2436{
2437    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2438}
2439/* }}} */
2440
2441ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2442{
2443    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2444}
2445/* }}} */
2446
2447ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2448{
2449    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2450}
2451/* }}} */
2452
2453ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2454{
2455    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));
2456}
2457/* }}} */
2458
2459ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2460{
2461    int ret1, ret2;
2462    int oflow1, oflow2;
2463    zend_long lval1 = 0, lval2 = 0;
2464    double dval1 = 0.0, dval2 = 0.0;
2465
2466    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2467        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2468#if ZEND_ULONG_MAX == 0xFFFFFFFF
2469        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2470            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2471            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2472#else
2473        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2474#endif
2475            /* both values are integers overflown to the same side, and the
2476             * double comparison may have resulted in crucial accuracy lost */
2477            goto string_cmp;
2478        }
2479        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2480            if (ret1!=IS_DOUBLE) {
2481                if (oflow2) {
2482                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2483                    ZVAL_LONG(result, -1 * oflow2);
2484                    return;
2485                }
2486                dval1 = (double) lval1;
2487            } else if (ret2!=IS_DOUBLE) {
2488                if (oflow1) {
2489                    ZVAL_LONG(result, oflow1);
2490                    return;
2491                }
2492                dval2 = (double) lval2;
2493            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2494                /* Both values overflowed and have the same sign,
2495                 * so a numeric comparison would be inaccurate */
2496                goto string_cmp;
2497            }
2498            Z_DVAL_P(result) = dval1 - dval2;
2499            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2500        } else { /* they both have to be long's */
2501            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2502        }
2503    } else {
2504string_cmp:
2505        Z_LVAL_P(result) = zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2506        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2507    }
2508}
2509/* }}} */
2510
2511static int hash_zval_compare_function(zval *z1, zval *z2 TSRMLS_DC) /* {{{ */
2512{
2513    zval result;
2514
2515    if (compare_function(&result, z1, z2 TSRMLS_CC)==FAILURE) {
2516        return 1;
2517    }
2518    return Z_LVAL(result);
2519}
2520/* }}} */
2521
2522ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2523{
2524    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2525}
2526/* }}} */
2527
2528ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2529{
2530    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2531}
2532/* }}} */
2533
2534ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2535{
2536    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2537}
2538/* }}} */
2539
2540ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2541{
2542    if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2543        ZVAL_LONG(result, 0);
2544        return;
2545    }
2546
2547    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2548        ZVAL_LONG(result, 1);
2549    } else {
2550        ZVAL_LONG(result, Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC));
2551    }
2552}
2553/* }}} */
2554
2555ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2556{
2557    zend_string *str;
2558    TSRMLS_FETCH();
2559
2560    str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2561    ZVAL_NEW_STR(op, str);
2562}
2563/* }}} */
2564
2565ZEND_API zend_string *zend_long_to_str(zend_long num) /* {{{ */
2566{
2567    char buf[MAX_LENGTH_OF_LONG + 1];
2568    char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
2569    return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
2570}
2571/* }}} */
2572
2573ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) {
2574    return is_numeric_string_ex(str->val, str->len, lval, dval, -1, NULL);
2575}
2576
2577ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info)
2578{
2579    const char *ptr;
2580    int base = 10, digits = 0, dp_or_e = 0;
2581    double local_dval = 0.0;
2582    zend_uchar type;
2583
2584    if (!length) {
2585        return 0;
2586    }
2587
2588    if (oflow_info != NULL) {
2589        *oflow_info = 0;
2590    }
2591
2592    /* Skip any whitespace
2593     * This is much faster than the isspace() function */
2594    while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
2595        str++;
2596        length--;
2597    }
2598    ptr = str;
2599
2600    if (*ptr == '-' || *ptr == '+') {
2601        ptr++;
2602    }
2603
2604    if (ZEND_IS_DIGIT(*ptr)) {
2605        /* Handle hex numbers
2606         * str is used instead of ptr to disallow signs and keep old behavior */
2607        if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
2608            base = 16;
2609            ptr += 2;
2610        }
2611
2612        /* Skip any leading 0s */
2613        while (*ptr == '0') {
2614            ptr++;
2615        }
2616
2617        /* Count the number of digits. If a decimal point/exponent is found,
2618         * it's a double. Otherwise, if there's a dval or no need to check for
2619         * a full match, stop when there are too many digits for a long */
2620        for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
2621check_digits:
2622            if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
2623                continue;
2624            } else if (base == 10) {
2625                if (*ptr == '.' && dp_or_e < 1) {
2626                    goto process_double;
2627                } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
2628                    const char *e = ptr + 1;
2629
2630                    if (*e == '-' || *e == '+') {
2631                        ptr = e++;
2632                    }
2633                    if (ZEND_IS_DIGIT(*e)) {
2634                        goto process_double;
2635                    }
2636                }
2637            }
2638
2639            break;
2640        }
2641
2642        if (base == 10) {
2643            if (digits >= MAX_LENGTH_OF_LONG) {
2644                if (oflow_info != NULL) {
2645                    *oflow_info = *str == '-' ? -1 : 1;
2646                }
2647                dp_or_e = -1;
2648                goto process_double;
2649            }
2650        } else if (!(digits < SIZEOF_ZEND_LONG * 2 || (digits == SIZEOF_ZEND_LONG * 2 && ptr[-digits] <= '7'))) {
2651            if (dval) {
2652                local_dval = zend_hex_strtod(str, &ptr);
2653            }
2654            if (oflow_info != NULL) {
2655                *oflow_info = 1;
2656            }
2657            type = IS_DOUBLE;
2658        }
2659    } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
2660process_double:
2661        type = IS_DOUBLE;
2662
2663        /* If there's a dval, do the conversion; else continue checking
2664         * the digits if we need to check for a full match */
2665        if (dval) {
2666            local_dval = zend_strtod(str, &ptr);
2667        } else if (allow_errors != 1 && dp_or_e != -1) {
2668            dp_or_e = (*ptr++ == '.') ? 1 : 2;
2669            goto check_digits;
2670        }
2671    } else {
2672        return 0;
2673    }
2674
2675    if (ptr != str + length) {
2676        if (!allow_errors) {
2677            return 0;
2678        }
2679        if (allow_errors == -1) {
2680            zend_error(E_NOTICE, "A non well formed numeric value encountered");
2681        }
2682    }
2683
2684    if (type == IS_LONG) {
2685        if (digits == MAX_LENGTH_OF_LONG - 1) {
2686            int cmp = strcmp(&ptr[-digits], long_min_digits);
2687
2688            if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
2689                if (dval) {
2690                    *dval = zend_strtod(str, NULL);
2691                }
2692                if (oflow_info != NULL) {
2693                    *oflow_info = *str == '-' ? -1 : 1;
2694                }
2695
2696                return IS_DOUBLE;
2697            }
2698        }
2699
2700        if (lval) {
2701            *lval = ZEND_STRTOL(str, NULL, base);
2702        }
2703
2704        return IS_LONG;
2705    } else {
2706        if (dval) {
2707            *dval = local_dval;
2708        }
2709
2710        return IS_DOUBLE;
2711    }
2712}
2713
2714/*
2715 * Local variables:
2716 * tab-width: 4
2717 * c-basic-offset: 4
2718 * indent-tabs-mode: t
2719 * End:
2720 */
2721