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