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 = 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
1049ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1050{
1051    zval op1_copy, op2_copy;
1052    int converted = 0;
1053
1054    while (1) {
1055        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1056            case TYPE_PAIR(IS_LONG, IS_LONG):
1057                if (Z_LVAL_P(op2) == 0) {
1058                    zend_error(E_WARNING, "Division by zero");
1059                    ZVAL_BOOL(result, 0);
1060                    return FAILURE;         /* division by zero */
1061                } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == LONG_MIN) {
1062                    /* Prevent overflow error/crash */
1063                    ZVAL_DOUBLE(result, (double) LONG_MIN / -1);
1064                    return SUCCESS;
1065                }
1066                if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1067                    ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1068                } else {
1069                    ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1070                }
1071                return SUCCESS;
1072
1073            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1074                if (Z_LVAL_P(op2) == 0) {
1075                    zend_error(E_WARNING, "Division by zero");
1076                    ZVAL_BOOL(result, 0);
1077                    return FAILURE;         /* division by zero */
1078                }
1079                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1080                return SUCCESS;
1081
1082            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1083                if (Z_DVAL_P(op2) == 0) {
1084                    zend_error(E_WARNING, "Division by zero");
1085                    ZVAL_BOOL(result, 0);
1086                    return FAILURE;         /* division by zero */
1087                }
1088                ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1089                return SUCCESS;
1090
1091            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1092                if (Z_DVAL_P(op2) == 0) {
1093                    zend_error(E_WARNING, "Division by zero");
1094                    ZVAL_BOOL(result, 0);
1095                    return FAILURE;         /* division by zero */
1096                }
1097                ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1098                return SUCCESS;
1099
1100            default:
1101                if (!converted) {
1102                    ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1103
1104                    zendi_convert_scalar_to_number(op1, op1_copy, result);
1105                    zendi_convert_scalar_to_number(op2, op2_copy, result);
1106                    converted = 1;
1107                } else {
1108                    zend_error(E_ERROR, "Unsupported operand types");
1109                    return FAILURE; /* unknown datatype */
1110                }
1111        }
1112    }
1113}
1114/* }}} */
1115
1116ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1117{
1118    zval op1_copy, op2_copy;
1119    long op1_lval;
1120
1121    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1122        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD);
1123
1124        zendi_convert_to_long(op1, op1_copy, result);
1125        op1_lval = Z_LVAL_P(op1);
1126        zendi_convert_to_long(op2, op2_copy, result);
1127    } else {
1128        op1_lval = Z_LVAL_P(op1);
1129    }
1130
1131    if (Z_LVAL_P(op2) == 0) {
1132        zend_error(E_WARNING, "Division by zero");
1133        ZVAL_BOOL(result, 0);
1134        return FAILURE;         /* modulus by zero */
1135    }
1136
1137    if (Z_LVAL_P(op2) == -1) {
1138        /* Prevent overflow error/crash if op1==LONG_MIN */
1139        ZVAL_LONG(result, 0);
1140        return SUCCESS;
1141    }
1142
1143    ZVAL_LONG(result, op1_lval % Z_LVAL_P(op2));
1144    return SUCCESS;
1145}
1146/* }}} */
1147
1148ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1149{
1150    zval op1_copy, op2_copy;
1151    long op1_lval;
1152
1153    if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) {
1154        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR);
1155
1156        zendi_convert_to_boolean(op1, op1_copy, result);
1157        op1_lval = Z_LVAL_P(op1);
1158        zendi_convert_to_boolean(op2, op2_copy, result);
1159    } else {
1160        op1_lval = Z_LVAL_P(op1);
1161    }
1162
1163    ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
1164    return SUCCESS;
1165}
1166/* }}} */
1167
1168ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1169{
1170    zval op1_copy;
1171
1172    if (Z_TYPE_P(op1) != IS_BOOL) {
1173        ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1174
1175        zendi_convert_to_boolean(op1, op1_copy, result);
1176    }
1177
1178    ZVAL_BOOL(result, !Z_LVAL_P(op1));
1179    return SUCCESS;
1180}
1181/* }}} */
1182
1183ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
1184{
1185
1186    switch (Z_TYPE_P(op1)) {
1187        case IS_LONG:
1188            ZVAL_LONG(result, ~Z_LVAL_P(op1));
1189            return SUCCESS;
1190        case IS_DOUBLE:
1191            ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1192            return SUCCESS;
1193        case IS_STRING: {
1194            int i;
1195            zval op1_copy = *op1;
1196
1197            Z_TYPE_P(result) = IS_STRING;
1198            Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy));
1199            Z_STRLEN_P(result) = Z_STRLEN(op1_copy);
1200            for (i = 0; i < Z_STRLEN(op1_copy); i++) {
1201                Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i];
1202            }
1203            return SUCCESS;
1204        }
1205        default:
1206            ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1207
1208            zend_error(E_ERROR, "Unsupported operand types");
1209            return FAILURE;
1210    }
1211}
1212/* }}} */
1213
1214ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1215{
1216    zval op1_copy, op2_copy;
1217    long op1_lval;
1218
1219    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1220        zval *longer, *shorter;
1221        char *result_str;
1222        int i, result_len;
1223
1224        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1225            longer = op1;
1226            shorter = op2;
1227        } else {
1228            longer = op2;
1229            shorter = op1;
1230        }
1231
1232        Z_TYPE_P(result) = IS_STRING;
1233        result_len = Z_STRLEN_P(longer);
1234        result_str = estrndup(Z_STRVAL_P(longer), Z_STRLEN_P(longer));
1235        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1236            result_str[i] |= Z_STRVAL_P(shorter)[i];
1237        }
1238        if (result==op1) {
1239            str_efree(Z_STRVAL_P(result));
1240        }
1241        Z_STRVAL_P(result) = result_str;
1242        Z_STRLEN_P(result) = result_len;
1243        return SUCCESS;
1244    }
1245
1246    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1247        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR);
1248
1249        zendi_convert_to_long(op1, op1_copy, result);
1250        op1_lval = Z_LVAL_P(op1);
1251        zendi_convert_to_long(op2, op2_copy, result);
1252    } else {
1253        op1_lval = Z_LVAL_P(op1);
1254    }
1255
1256    ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
1257    return SUCCESS;
1258}
1259/* }}} */
1260
1261ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1262{
1263    zval op1_copy, op2_copy;
1264    long op1_lval;
1265
1266    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1267        zval *longer, *shorter;
1268        char *result_str;
1269        int i, result_len;
1270
1271        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1272            longer = op1;
1273            shorter = op2;
1274        } else {
1275            longer = op2;
1276            shorter = op1;
1277        }
1278
1279        Z_TYPE_P(result) = IS_STRING;
1280        result_len = Z_STRLEN_P(shorter);
1281        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1282        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1283            result_str[i] &= Z_STRVAL_P(longer)[i];
1284        }
1285        if (result==op1) {
1286            str_efree(Z_STRVAL_P(result));
1287        }
1288        Z_STRVAL_P(result) = result_str;
1289        Z_STRLEN_P(result) = result_len;
1290        return SUCCESS;
1291    }
1292
1293    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1294        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND);
1295
1296        zendi_convert_to_long(op1, op1_copy, result);
1297        op1_lval = Z_LVAL_P(op1);
1298        zendi_convert_to_long(op2, op2_copy, result);
1299    } else {
1300        op1_lval = Z_LVAL_P(op1);
1301    }
1302
1303    ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
1304    return SUCCESS;
1305}
1306/* }}} */
1307
1308ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1309{
1310    zval op1_copy, op2_copy;
1311    long op1_lval;
1312
1313    if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1314        zval *longer, *shorter;
1315        char *result_str;
1316        int i, result_len;
1317
1318        if (Z_STRLEN_P(op1) >= Z_STRLEN_P(op2)) {
1319            longer = op1;
1320            shorter = op2;
1321        } else {
1322            longer = op2;
1323            shorter = op1;
1324        }
1325
1326        Z_TYPE_P(result) = IS_STRING;
1327        result_len = Z_STRLEN_P(shorter);
1328        result_str = estrndup(Z_STRVAL_P(shorter), Z_STRLEN_P(shorter));
1329        for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1330            result_str[i] ^= Z_STRVAL_P(longer)[i];
1331        }
1332        if (result==op1) {
1333            str_efree(Z_STRVAL_P(result));
1334        }
1335        Z_STRVAL_P(result) = result_str;
1336        Z_STRLEN_P(result) = result_len;
1337        return SUCCESS;
1338    }
1339
1340    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1341        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR);
1342
1343        zendi_convert_to_long(op1, op1_copy, result);
1344        op1_lval = Z_LVAL_P(op1);
1345        zendi_convert_to_long(op2, op2_copy, result);
1346    } else {
1347        op1_lval = Z_LVAL_P(op1);
1348    }
1349
1350    ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
1351    return SUCCESS;
1352}
1353/* }}} */
1354
1355ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1356{
1357    zval op1_copy, op2_copy;
1358    long op1_lval;
1359
1360    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1361        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL);
1362
1363        zendi_convert_to_long(op1, op1_copy, result);
1364        op1_lval = Z_LVAL_P(op1);
1365        zendi_convert_to_long(op2, op2_copy, result);
1366    } else {
1367        op1_lval = Z_LVAL_P(op1);
1368    }
1369
1370    ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
1371    return SUCCESS;
1372}
1373/* }}} */
1374
1375ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1376{
1377    zval op1_copy, op2_copy;
1378    long op1_lval;
1379
1380    if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
1381        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR);
1382
1383        zendi_convert_to_long(op1, op1_copy, result);
1384        op1_lval = Z_LVAL_P(op1);
1385        zendi_convert_to_long(op2, op2_copy, result);
1386    } else {
1387        op1_lval = Z_LVAL_P(op1);
1388    }
1389
1390    ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
1391    return SUCCESS;
1392}
1393/* }}} */
1394
1395/* must support result==op1 */
1396ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1397{
1398    int length = Z_STRLEN_P(op1) + 1;
1399    char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1400
1401    buf[length - 1] = (char) Z_LVAL_P(op2);
1402    buf[length] = 0;
1403    ZVAL_STRINGL(result, buf, length, 0);
1404    return SUCCESS;
1405}
1406/* }}} */
1407
1408/* must support result==op1 */
1409ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */
1410{
1411    int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1412    char *buf = str_erealloc(Z_STRVAL_P(op1), length + 1);
1413
1414    memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1415    buf[length] = 0;
1416    ZVAL_STRINGL(result, buf, length, 0);
1417    return SUCCESS;
1418}
1419/* }}} */
1420
1421ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1422{
1423    zval op1_copy, op2_copy;
1424    int use_copy1 = 0, use_copy2 = 0;
1425
1426    if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) {
1427        ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1428
1429        if (Z_TYPE_P(op1) != IS_STRING) {
1430            zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1431        }
1432        if (Z_TYPE_P(op2) != IS_STRING) {
1433            zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1434        }
1435    }
1436
1437    if (use_copy1) {
1438        /* We have created a converted copy of op1. Therefore, op1 won't become the result so
1439         * we have to free it.
1440         */
1441        if (result == op1) {
1442            zval_dtor(op1);
1443        }
1444        op1 = &op1_copy;
1445    }
1446    if (use_copy2) {
1447        op2 = &op2_copy;
1448    }
1449    if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */
1450        uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1451
1452        if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
1453            efree(Z_STRVAL_P(result));
1454            ZVAL_EMPTY_STRING(result);
1455            zend_error(E_ERROR, "String size overflow");
1456        }
1457
1458        Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);
1459
1460        memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1461        Z_STRVAL_P(result)[res_len]=0;
1462        Z_STRLEN_P(result) = res_len;
1463    } else {
1464        int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
1465        char *buf = (char *) emalloc(length + 1);
1466
1467        memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
1468        memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1469        buf[length] = 0;
1470        ZVAL_STRINGL(result, buf, length, 0);
1471    }
1472    if (use_copy1) {
1473        zval_dtor(op1);
1474    }
1475    if (use_copy2) {
1476        zval_dtor(op2);
1477    }
1478    return SUCCESS;
1479}
1480/* }}} */
1481
1482ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
1483{
1484    zval op1_copy, op2_copy;
1485    int use_copy1 = 0, use_copy2 = 0;
1486
1487    if (Z_TYPE_P(op1) != IS_STRING) {
1488        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1489    }
1490    if (Z_TYPE_P(op2) != IS_STRING) {
1491        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1492    }
1493
1494    if (use_copy1) {
1495        op1 = &op1_copy;
1496    }
1497    if (use_copy2) {
1498        op2 = &op2_copy;
1499    }
1500
1501    if (case_insensitive) {
1502        ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2));
1503    } else {
1504        ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2));
1505    }
1506
1507    if (use_copy1) {
1508        zval_dtor(op1);
1509    }
1510    if (use_copy2) {
1511        zval_dtor(op2);
1512    }
1513    return SUCCESS;
1514}
1515/* }}} */
1516
1517ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1518{
1519    return string_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
1520}
1521/* }}} */
1522
1523ZEND_API int string_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1524{
1525    return string_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
1526}
1527/* }}} */
1528
1529#if HAVE_STRCOLL
1530ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1531{
1532    zval op1_copy, op2_copy;
1533    int use_copy1 = 0, use_copy2 = 0;
1534
1535    if (Z_TYPE_P(op1) != IS_STRING) {
1536        zend_make_printable_zval(op1, &op1_copy, &use_copy1);
1537    }
1538    if (Z_TYPE_P(op2) != IS_STRING) {
1539        zend_make_printable_zval(op2, &op2_copy, &use_copy2);
1540    }
1541
1542    if (use_copy1) {
1543        op1 = &op1_copy;
1544    }
1545    if (use_copy2) {
1546        op2 = &op2_copy;
1547    }
1548
1549    ZVAL_LONG(result, strcoll(Z_STRVAL_P(op1), Z_STRVAL_P(op2)));
1550
1551    if (use_copy1) {
1552        zval_dtor(op1);
1553    }
1554    if (use_copy2) {
1555        zval_dtor(op2);
1556    }
1557    return SUCCESS;
1558}
1559/* }}} */
1560#endif
1561
1562ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1563{
1564    zval op1_copy, op2_copy;
1565
1566    op1_copy = *op1;
1567    zval_copy_ctor(&op1_copy);
1568
1569    op2_copy = *op2;
1570    zval_copy_ctor(&op2_copy);
1571
1572    convert_to_double(&op1_copy);
1573    convert_to_double(&op2_copy);
1574
1575    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL(op1_copy)-Z_DVAL(op2_copy)));
1576
1577    return SUCCESS;
1578}
1579/* }}} */
1580
1581static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
1582{
1583    if (Z_REFCOUNT_P(op) == 0) {
1584        GC_REMOVE_ZVAL_FROM_BUFFER(op);
1585        zval_dtor(op);
1586        FREE_ZVAL(op);
1587    } else {
1588        zval_ptr_dtor(&op);
1589    }
1590}
1591/* }}} */
1592
1593ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1594{
1595    int ret;
1596    int converted = 0;
1597    zval op1_copy, op2_copy;
1598    zval *op_free;
1599
1600    while (1) {
1601        switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
1602            case TYPE_PAIR(IS_LONG, IS_LONG):
1603                ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
1604                return SUCCESS;
1605
1606            case TYPE_PAIR(IS_DOUBLE, IS_LONG):
1607                Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
1608                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1609                return SUCCESS;
1610
1611            case TYPE_PAIR(IS_LONG, IS_DOUBLE):
1612                Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
1613                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1614                return SUCCESS;
1615
1616            case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
1617                if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
1618                    ZVAL_LONG(result, 0);
1619                } else {
1620                    Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
1621                    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
1622                }
1623                return SUCCESS;
1624
1625            case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
1626                zend_compare_arrays(result, op1, op2 TSRMLS_CC);
1627                return SUCCESS;
1628
1629            case TYPE_PAIR(IS_NULL, IS_NULL):
1630                ZVAL_LONG(result, 0);
1631                return SUCCESS;
1632
1633            case TYPE_PAIR(IS_NULL, IS_BOOL):
1634                ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1635                return SUCCESS;
1636
1637            case TYPE_PAIR(IS_BOOL, IS_NULL):
1638                ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1639                return SUCCESS;
1640
1641            case TYPE_PAIR(IS_BOOL, IS_BOOL):
1642                ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1643                return SUCCESS;
1644
1645            case TYPE_PAIR(IS_STRING, IS_STRING):
1646                zendi_smart_strcmp(result, op1, op2);
1647                return SUCCESS;
1648
1649            case TYPE_PAIR(IS_NULL, IS_STRING):
1650                ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2)));
1651                return SUCCESS;
1652
1653            case TYPE_PAIR(IS_STRING, IS_NULL):
1654                ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0));
1655                return SUCCESS;
1656
1657            case TYPE_PAIR(IS_OBJECT, IS_NULL):
1658                ZVAL_LONG(result, 1);
1659                return SUCCESS;
1660
1661            case TYPE_PAIR(IS_NULL, IS_OBJECT):
1662                ZVAL_LONG(result, -1);
1663                return SUCCESS;
1664
1665            default:
1666                if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
1667                    return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
1668                } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
1669                    return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
1670                }
1671
1672                if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
1673                    if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
1674                        /* object handles are identical, apparently this is the same object */
1675                        ZVAL_LONG(result, 0);
1676                        return SUCCESS;
1677                    }
1678                    if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
1679                        ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
1680                        return SUCCESS;
1681                    }
1682                }
1683                if (Z_TYPE_P(op1) == IS_OBJECT) {
1684                    if (Z_OBJ_HT_P(op1)->get) {
1685                        op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
1686                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1687                        zend_free_obj_get_result(op_free TSRMLS_CC);
1688                        return ret;
1689                    } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
1690                        ALLOC_INIT_ZVAL(op_free);
1691                        if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {
1692                            ZVAL_LONG(result, 1);
1693                            zend_free_obj_get_result(op_free TSRMLS_CC);
1694                            return SUCCESS;
1695                        }
1696                        ret = compare_function(result, op_free, op2 TSRMLS_CC);
1697                        zend_free_obj_get_result(op_free TSRMLS_CC);
1698                        return ret;
1699                    }
1700                }
1701                if (Z_TYPE_P(op2) == IS_OBJECT) {
1702                    if (Z_OBJ_HT_P(op2)->get) {
1703                        op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC);
1704                        ret = compare_function(result, op1, op_free TSRMLS_CC);
1705                        zend_free_obj_get_result(op_free TSRMLS_CC);
1706                        return ret;
1707                    } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
1708                        ALLOC_INIT_ZVAL(op_free);
1709                        if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) 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, op1, op_free TSRMLS_CC);
1715                        zend_free_obj_get_result(op_free TSRMLS_CC);
1716                        return ret;
1717                    } else if (Z_TYPE_P(op1) == IS_OBJECT) {
1718                        ZVAL_LONG(result, 1);
1719                        return SUCCESS;
1720                    }
1721                }
1722                if (!converted) {
1723                    if (Z_TYPE_P(op1) == IS_NULL) {
1724                        zendi_convert_to_boolean(op2, op2_copy, result);
1725                        ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0);
1726                        return SUCCESS;
1727                    } else if (Z_TYPE_P(op2) == IS_NULL) {
1728                        zendi_convert_to_boolean(op1, op1_copy, result);
1729                        ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0);
1730                        return SUCCESS;
1731                    } else if (Z_TYPE_P(op1) == IS_BOOL) {
1732                        zendi_convert_to_boolean(op2, op2_copy, result);
1733                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1734                        return SUCCESS;
1735                    } else if (Z_TYPE_P(op2) == IS_BOOL) {
1736                        zendi_convert_to_boolean(op1, op1_copy, result);
1737                        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));
1738                        return SUCCESS;
1739                    } else {
1740                        zendi_convert_scalar_to_number(op1, op1_copy, result);
1741                        zendi_convert_scalar_to_number(op2, op2_copy, result);
1742                        converted = 1;
1743                    }
1744                } else if (Z_TYPE_P(op1)==IS_ARRAY) {
1745                    ZVAL_LONG(result, 1);
1746                    return SUCCESS;
1747                } else if (Z_TYPE_P(op2)==IS_ARRAY) {
1748                    ZVAL_LONG(result, -1);
1749                    return SUCCESS;
1750                } else if (Z_TYPE_P(op1)==IS_OBJECT) {
1751                    ZVAL_LONG(result, 1);
1752                    return SUCCESS;
1753                } else if (Z_TYPE_P(op2)==IS_OBJECT) {
1754                    ZVAL_LONG(result, -1);
1755                    return SUCCESS;
1756                } else {
1757                    ZVAL_LONG(result, 0);
1758                    return FAILURE;
1759                }
1760        }
1761    }
1762}
1763/* }}} */
1764
1765static int hash_zval_identical_function(const zval **z1, const zval **z2) /* {{{ */
1766{
1767    zval result;
1768    TSRMLS_FETCH();
1769
1770    /* is_identical_function() returns 1 in case of identity and 0 in case
1771     * of a difference;
1772     * whereas this comparison function is expected to return 0 on identity,
1773     * and non zero otherwise.
1774     */
1775    if (is_identical_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
1776        return 1;
1777    }
1778    return !Z_LVAL(result);
1779}
1780/* }}} */
1781
1782ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1783{
1784    Z_TYPE_P(result) = IS_BOOL;
1785    if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
1786        Z_LVAL_P(result) = 0;
1787        return SUCCESS;
1788    }
1789    switch (Z_TYPE_P(op1)) {
1790        case IS_NULL:
1791            Z_LVAL_P(result) = 1;
1792            break;
1793        case IS_BOOL:
1794        case IS_LONG:
1795        case IS_RESOURCE:
1796            Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
1797            break;
1798        case IS_DOUBLE:
1799            Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
1800            break;
1801        case IS_STRING:
1802            Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2))
1803                && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1))));
1804            break;
1805        case IS_ARRAY:
1806            Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
1807                zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0);
1808            break;
1809        case IS_OBJECT:
1810            if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) {
1811                Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2));
1812            } else {
1813                Z_LVAL_P(result) = 0;
1814            }
1815            break;
1816        default:
1817            Z_LVAL_P(result) = 0;
1818            return FAILURE;
1819    }
1820    return SUCCESS;
1821}
1822/* }}} */
1823
1824ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1825{
1826    if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1827        return FAILURE;
1828    }
1829    Z_LVAL_P(result) = !Z_LVAL_P(result);
1830    return SUCCESS;
1831}
1832/* }}} */
1833
1834ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1835{
1836    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1837        return FAILURE;
1838    }
1839    ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1840    return SUCCESS;
1841}
1842/* }}} */
1843
1844ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1845{
1846    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1847        return FAILURE;
1848    }
1849    ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1850    return SUCCESS;
1851}
1852/* }}} */
1853
1854ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1855{
1856    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1857        return FAILURE;
1858    }
1859    ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
1860    return SUCCESS;
1861}
1862/* }}} */
1863
1864ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
1865{
1866    if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {
1867        return FAILURE;
1868    }
1869    ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
1870    return SUCCESS;
1871}
1872/* }}} */
1873
1874ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC) /* {{{ */
1875{
1876    zend_uint i;
1877
1878    for (i=0; i<instance_ce->num_interfaces; i++) {
1879        if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
1880            return 1;
1881        }
1882    }
1883    if (!interfaces_only) {
1884        while (instance_ce) {
1885            if (instance_ce == ce) {
1886                return 1;
1887            }
1888            instance_ce = instance_ce->parent;
1889        }
1890    }
1891
1892    return 0;
1893}
1894/* }}} */
1895
1896ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC) /* {{{ */
1897{
1898    return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
1899}
1900/* }}} */
1901
1902#define LOWER_CASE 1
1903#define UPPER_CASE 2
1904#define NUMERIC 3
1905
1906static void increment_string(zval *str) /* {{{ */
1907{
1908    int carry=0;
1909    int pos=Z_STRLEN_P(str)-1;
1910    char *s=Z_STRVAL_P(str);
1911    char *t;
1912    int last=0; /* Shut up the compiler warning */
1913    int ch;
1914
1915    if (Z_STRLEN_P(str) == 0) {
1916        str_efree(Z_STRVAL_P(str));
1917        Z_STRVAL_P(str) = estrndup("1", sizeof("1")-1);
1918        Z_STRLEN_P(str) = 1;
1919        return;
1920    }
1921
1922    if (IS_INTERNED(s)) {
1923        Z_STRVAL_P(str) = s = estrndup(s, Z_STRLEN_P(str));
1924    }
1925
1926    while (pos >= 0) {
1927        ch = s[pos];
1928        if (ch >= 'a' && ch <= 'z') {
1929            if (ch == 'z') {
1930                s[pos] = 'a';
1931                carry=1;
1932            } else {
1933                s[pos]++;
1934                carry=0;
1935            }
1936            last=LOWER_CASE;
1937        } else if (ch >= 'A' && ch <= 'Z') {
1938            if (ch == 'Z') {
1939                s[pos] = 'A';
1940                carry=1;
1941            } else {
1942                s[pos]++;
1943                carry=0;
1944            }
1945            last=UPPER_CASE;
1946        } else if (ch >= '0' && ch <= '9') {
1947            if (ch == '9') {
1948                s[pos] = '0';
1949                carry=1;
1950            } else {
1951                s[pos]++;
1952                carry=0;
1953            }
1954            last = NUMERIC;
1955        } else {
1956            carry=0;
1957            break;
1958        }
1959        if (carry == 0) {
1960            break;
1961        }
1962        pos--;
1963    }
1964
1965    if (carry) {
1966        t = (char *) emalloc(Z_STRLEN_P(str)+1+1);
1967        memcpy(t+1, Z_STRVAL_P(str), Z_STRLEN_P(str));
1968        Z_STRLEN_P(str)++;
1969        t[Z_STRLEN_P(str)] = '\0';
1970        switch (last) {
1971            case NUMERIC:
1972                t[0] = '1';
1973                break;
1974            case UPPER_CASE:
1975                t[0] = 'A';
1976                break;
1977            case LOWER_CASE:
1978                t[0] = 'a';
1979                break;
1980        }
1981        str_efree(Z_STRVAL_P(str));
1982        Z_STRVAL_P(str) = t;
1983    }
1984}
1985/* }}} */
1986
1987ZEND_API int increment_function(zval *op1) /* {{{ */
1988{
1989    switch (Z_TYPE_P(op1)) {
1990        case IS_LONG:
1991            if (Z_LVAL_P(op1) == LONG_MAX) {
1992                /* switch to double */
1993                double d = (double)Z_LVAL_P(op1);
1994                ZVAL_DOUBLE(op1, d+1);
1995            } else {
1996            Z_LVAL_P(op1)++;
1997            }
1998            break;
1999        case IS_DOUBLE:
2000            Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2001            break;
2002        case IS_NULL:
2003            ZVAL_LONG(op1, 1);
2004            break;
2005        case IS_STRING: {
2006                long lval;
2007                double dval;
2008
2009                switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2010                    case IS_LONG:
2011                        str_efree(Z_STRVAL_P(op1));
2012                        if (lval == LONG_MAX) {
2013                            /* switch to double */
2014                            double d = (double)lval;
2015                            ZVAL_DOUBLE(op1, d+1);
2016                        } else {
2017                            ZVAL_LONG(op1, lval+1);
2018                        }
2019                        break;
2020                    case IS_DOUBLE:
2021                        str_efree(Z_STRVAL_P(op1));
2022                        ZVAL_DOUBLE(op1, dval+1);
2023                        break;
2024                    default:
2025                        /* Perl style string increment */
2026                        increment_string(op1);
2027                        break;
2028                }
2029            }
2030            break;
2031        case IS_OBJECT:
2032            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2033                zval *op2;
2034                int res;
2035                TSRMLS_FETCH();
2036
2037                MAKE_STD_ZVAL(op2);
2038                ZVAL_LONG(op2, 1);
2039                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
2040                zval_ptr_dtor(&op2);
2041
2042                return res;
2043            }
2044            return FAILURE;
2045        default:
2046            return FAILURE;
2047    }
2048    return SUCCESS;
2049}
2050/* }}} */
2051
2052ZEND_API int decrement_function(zval *op1) /* {{{ */
2053{
2054    long lval;
2055    double dval;
2056
2057    switch (Z_TYPE_P(op1)) {
2058        case IS_LONG:
2059            if (Z_LVAL_P(op1) == LONG_MIN) {
2060                double d = (double)Z_LVAL_P(op1);
2061                ZVAL_DOUBLE(op1, d-1);
2062            } else {
2063            Z_LVAL_P(op1)--;
2064            }
2065            break;
2066        case IS_DOUBLE:
2067            Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2068            break;
2069        case IS_STRING:     /* Like perl we only support string increment */
2070            if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2071                str_efree(Z_STRVAL_P(op1));
2072                ZVAL_LONG(op1, -1);
2073                break;
2074            }
2075            switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2076                case IS_LONG:
2077                    str_efree(Z_STRVAL_P(op1));
2078                    if (lval == LONG_MIN) {
2079                        double d = (double)lval;
2080                        ZVAL_DOUBLE(op1, d-1);
2081                    } else {
2082                        ZVAL_LONG(op1, lval-1);
2083                    }
2084                    break;
2085                case IS_DOUBLE:
2086                    str_efree(Z_STRVAL_P(op1));
2087                    ZVAL_DOUBLE(op1, dval - 1);
2088                    break;
2089            }
2090            break;
2091        case IS_OBJECT:
2092            if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2093                zval *op2;
2094                int res;
2095                TSRMLS_FETCH();
2096
2097                MAKE_STD_ZVAL(op2);
2098                ZVAL_LONG(op2, 1);
2099                res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
2100                zval_ptr_dtor(&op2);
2101
2102                return res;
2103            }
2104            return FAILURE;
2105        default:
2106            return FAILURE;
2107    }
2108
2109    return SUCCESS;
2110}
2111/* }}} */
2112
2113ZEND_API int zval_is_true(zval *op) /* {{{ */
2114{
2115    convert_to_boolean(op);
2116    return (Z_LVAL_P(op) ? 1 : 0);
2117}
2118/* }}} */
2119
2120#ifdef ZEND_USE_TOLOWER_L
2121ZEND_API void zend_update_current_locale(void) /* {{{ */
2122{
2123    current_locale = _get_current_locale();
2124}
2125/* }}} */
2126#endif
2127
2128ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
2129{
2130    register unsigned char *str = (unsigned char*)source;
2131    register unsigned char *result = (unsigned char*)dest;
2132    register unsigned char *end = str + length;
2133
2134    while (str < end) {
2135        *result++ = zend_tolower_ascii(*str++);
2136    }
2137    *result = '\0';
2138
2139    return dest;
2140}
2141/* }}} */
2142
2143ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
2144{
2145    return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2146}
2147/* }}} */
2148
2149ZEND_API void zend_str_tolower(char *str, unsigned int length) /* {{{ */
2150{
2151    register unsigned char *p = (unsigned char*)str;
2152    register unsigned char *end = p + length;
2153
2154    while (p < end) {
2155        *p = zend_tolower_ascii(*p);
2156        p++;
2157    }
2158}
2159/* }}} */
2160
2161ZEND_API int zend_binary_strcmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2162{
2163    int retval;
2164
2165    if (s1 == s2) {
2166        return 0;
2167    }
2168    retval = memcmp(s1, s2, MIN(len1, len2));
2169    if (!retval) {
2170        return (len1 - len2);
2171    } else {
2172        return retval;
2173    }
2174}
2175/* }}} */
2176
2177ZEND_API int zend_binary_strncmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2178{
2179    int retval;
2180
2181    if (s1 == s2) {
2182        return 0;
2183    }
2184    retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2185    if (!retval) {
2186        return (MIN(length, len1) - MIN(length, len2));
2187    } else {
2188        return retval;
2189    }
2190}
2191/* }}} */
2192
2193ZEND_API int zend_binary_strcasecmp(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2194{
2195    int len;
2196    int c1, c2;
2197
2198    if (s1 == s2) {
2199        return 0;
2200    }
2201
2202    len = MIN(len1, len2);
2203    while (len--) {
2204        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2205        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2206        if (c1 != c2) {
2207            return c1 - c2;
2208        }
2209    }
2210
2211    return len1 - len2;
2212}
2213/* }}} */
2214
2215ZEND_API int zend_binary_strncasecmp(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2216{
2217    int len;
2218    int c1, c2;
2219
2220    if (s1 == s2) {
2221        return 0;
2222    }
2223    len = MIN(length, MIN(len1, len2));
2224    while (len--) {
2225        c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2226        c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2227        if (c1 != c2) {
2228            return c1 - c2;
2229        }
2230    }
2231
2232    return MIN(length, len1) - MIN(length, len2);
2233}
2234/* }}} */
2235
2236ZEND_API int zend_binary_strcasecmp_l(const char *s1, uint len1, const char *s2, uint len2) /* {{{ */
2237{
2238    int len;
2239    int c1, c2;
2240
2241    if (s1 == s2) {
2242        return 0;
2243    }
2244
2245    len = MIN(len1, len2);
2246    while (len--) {
2247        c1 = zend_tolower((int)*(unsigned char *)s1++);
2248        c2 = zend_tolower((int)*(unsigned char *)s2++);
2249        if (c1 != c2) {
2250            return c1 - c2;
2251        }
2252    }
2253
2254    return len1 - len2;
2255}
2256/* }}} */
2257
2258ZEND_API int zend_binary_strncasecmp_l(const char *s1, uint len1, const char *s2, uint len2, uint length) /* {{{ */
2259{
2260    int len;
2261    int c1, c2;
2262
2263    if (s1 == s2) {
2264        return 0;
2265    }
2266    len = MIN(length, MIN(len1, len2));
2267    while (len--) {
2268        c1 = zend_tolower((int)*(unsigned char *)s1++);
2269        c2 = zend_tolower((int)*(unsigned char *)s2++);
2270        if (c1 != c2) {
2271            return c1 - c2;
2272        }
2273    }
2274
2275    return MIN(length, len1) - MIN(length, len2);
2276}
2277/* }}} */
2278
2279ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2280{
2281    return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2282}
2283/* }}} */
2284
2285ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2286{
2287    return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2288}
2289/* }}} */
2290
2291ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2292{
2293    return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2294}
2295/* }}} */
2296
2297ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2298{
2299    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));
2300}
2301/* }}} */
2302
2303ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2) /* {{{ */
2304{
2305    int ret1, ret2;
2306    int oflow1, oflow2;
2307    long lval1 = 0, lval2 = 0;
2308    double dval1 = 0.0, dval2 = 0.0;
2309
2310    if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) &&
2311        (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) {
2312#if ULONG_MAX == 0xFFFFFFFF
2313        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2314            ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2315            || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2316#else
2317        if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2318#endif
2319            /* both values are integers overflown to the same side, and the
2320             * double comparison may have resulted in crucial accuracy lost */
2321            goto string_cmp;
2322        }
2323        if ((ret1==IS_DOUBLE) || (ret2==IS_DOUBLE)) {
2324            if (ret1!=IS_DOUBLE) {
2325                if (oflow2) {
2326                    /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2327                    ZVAL_LONG(result, -1 * oflow2);
2328                    return;
2329                }
2330                dval1 = (double) lval1;
2331            } else if (ret2!=IS_DOUBLE) {
2332                if (oflow1) {
2333                    ZVAL_LONG(result, oflow1);
2334                    return;
2335                }
2336                dval2 = (double) lval2;
2337            } else if (dval1 == dval2 && !zend_finite(dval1)) {
2338                /* Both values overflowed and have the same sign,
2339                 * so a numeric comparison would be inaccurate */
2340                goto string_cmp;
2341            }
2342            Z_DVAL_P(result) = dval1 - dval2;
2343            ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2344        } else { /* they both have to be long's */
2345            ZVAL_LONG(result, lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0));
2346        }
2347    } else {
2348string_cmp:
2349        Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
2350        ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
2351    }
2352}
2353/* }}} */
2354
2355static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC) /* {{{ */
2356{
2357    zval result;
2358
2359    if (compare_function(&result, (zval *) *z1, (zval *) *z2 TSRMLS_CC)==FAILURE) {
2360        return 1;
2361    }
2362    return Z_LVAL(result);
2363}
2364/* }}} */
2365
2366ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2367{
2368    return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
2369}
2370/* }}} */
2371
2372ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC) /* {{{ */
2373{
2374    ZVAL_LONG(result, ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC));
2375}
2376/* }}} */
2377
2378ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC) /* {{{ */
2379{
2380    zend_compare_symbol_tables(result, Z_ARRVAL_P(a1), Z_ARRVAL_P(a2) TSRMLS_CC);
2381}
2382/* }}} */
2383
2384ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
2385{
2386    Z_TYPE_P(result) = IS_LONG;
2387
2388    if (Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
2389        Z_LVAL_P(result) = 0;
2390        return;
2391    }
2392
2393    if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2394        Z_LVAL_P(result) = 1;
2395    } else {
2396        Z_LVAL_P(result) = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
2397    }
2398}
2399/* }}} */
2400
2401ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2402{
2403    TSRMLS_FETCH();
2404
2405    Z_STRLEN_P(op) = zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
2406}
2407/* }}} */
2408
2409/*
2410 * Local variables:
2411 * tab-width: 4
2412 * c-basic-offset: 4
2413 * indent-tabs-mode: t
2414 * End:
2415 */
2416