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