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