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