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>
39 static _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
zend_atoi(const char * str,int str_len)48 ZEND_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
zend_atol(const char * str,int str_len)76 ZEND_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
zend_string_to_double(const char * number,zend_uint length)104 ZEND_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
convert_scalar_to_number(zval * op TSRMLS_DC)150 ZEND_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
convert_to_long(zval * op)327 ZEND_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
convert_to_long_base(zval * op,int base)335 ZEND_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
convert_to_double(zval * op)395 ZEND_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
convert_to_null(zval * op)454 ZEND_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
convert_to_boolean(zval * op)477 ZEND_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
_convert_to_string(zval * op ZEND_FILE_LINE_DC)541 ZEND_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
convert_scalar_to_array(zval * op,int type TSRMLS_DC)612 static 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
convert_to_array(zval * op)635 ZEND_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
convert_to_object(zval * op)688 ZEND_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
multi_convert_to_long_ex(int argc,...)710 ZEND_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
multi_convert_to_double_ex(int argc,...)726 ZEND_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
multi_convert_to_string_ex(int argc,...)742 ZEND_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
add_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)758 ZEND_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
sub_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)820 ZEND_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
mul_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)867 ZEND_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
div_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)908 ZEND_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
mod_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)973 ZEND_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
boolean_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)999 ZEND_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
boolean_not_function(zval * result,zval * op1 TSRMLS_DC)1012 ZEND_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
bitwise_not_function(zval * result,zval * op1 TSRMLS_DC)1022 ZEND_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
bitwise_or_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1050 ZEND_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
bitwise_and_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1090 ZEND_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
bitwise_xor_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1132 ZEND_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
shift_left_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1173 ZEND_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
shift_right_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1186 ZEND_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 */
add_char_to_string(zval * result,const zval * op1,const zval * op2)1200 ZEND_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 */
add_string_to_string(zval * result,const zval * op1,const zval * op2)1212 ZEND_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
concat_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1225 ZEND_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
string_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1281 ZEND_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
string_locale_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1313 ZEND_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
numeric_compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1345 ZEND_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
zend_free_obj_get_result(zval * op TSRMLS_DC)1364 static 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
compare_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1376 ZEND_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
hash_zval_identical_function(const zval ** z1,const zval ** z2)1540 static 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
is_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1557 ZEND_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
is_not_identical_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1599 ZEND_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
is_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1609 ZEND_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
is_not_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1619 ZEND_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
is_smaller_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1629 ZEND_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
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2 TSRMLS_DC)1639 ZEND_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
instanceof_function_ex(const zend_class_entry * instance_ce,const zend_class_entry * ce,zend_bool interfaces_only TSRMLS_DC)1649 ZEND_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
instanceof_function(const zend_class_entry * instance_ce,const zend_class_entry * ce TSRMLS_DC)1671 ZEND_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
increment_string(zval * str)1681 static 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
increment_function(zval * op1)1758 ZEND_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
decrement_function(zval * op1)1809 ZEND_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
zval_is_true(zval * op)1856 ZEND_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
zend_update_current_locale(void)1864 ZEND_API void zend_update_current_locale(void) /* {{{ */
1865 {
1866 current_locale = _get_current_locale();
1867 }
1868 /* }}} */
1869 #endif
1870
zend_str_tolower_copy(char * dest,const char * source,unsigned int length)1871 ZEND_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
zend_str_tolower_dup(const char * source,unsigned int length)1886 ZEND_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
zend_str_tolower(char * str,unsigned int length)1892 ZEND_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
zend_binary_strcmp(const char * s1,uint len1,const char * s2,uint len2)1904 ZEND_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
zend_binary_strncmp(const char * s1,uint len1,const char * s2,uint len2,uint length)1917 ZEND_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
zend_binary_strcasecmp(const char * s1,uint len1,const char * s2,uint len2)1930 ZEND_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
zend_binary_strncasecmp(const char * s1,uint len1,const char * s2,uint len2,uint length)1949 ZEND_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
zend_binary_zval_strcmp(zval * s1,zval * s2)1968 ZEND_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
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)1974 ZEND_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
zend_binary_zval_strcasecmp(zval * s1,zval * s2)1980 ZEND_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
zend_binary_zval_strncasecmp(zval * s1,zval * s2,zval * s3)1986 ZEND_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
zendi_smart_strcmp(zval * result,zval * s1,zval * s2)1992 ZEND_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 {
2016 string_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
hash_zval_compare_function(const zval ** z1,const zval ** z2 TSRMLS_DC)2023 static 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
zend_compare_symbol_tables_i(HashTable * ht1,HashTable * ht2 TSRMLS_DC)2034 ZEND_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
zend_compare_symbol_tables(zval * result,HashTable * ht1,HashTable * ht2 TSRMLS_DC)2040 ZEND_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
zend_compare_arrays(zval * result,zval * a1,zval * a2 TSRMLS_DC)2046 ZEND_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
zend_compare_objects(zval * result,zval * o1,zval * o2 TSRMLS_DC)2052 ZEND_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
zend_locale_sprintf_double(zval * op ZEND_FILE_LINE_DC)2069 ZEND_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