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