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