1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
33 #include "Zend/zend_interfaces.h"
34 #include "ext/spl/spl_iterators.h"
36 zend_long
psi_zval_count(zval
*zvalue
)
38 /* mimic PHP count() */
42 switch (Z_TYPE_P(zvalue
)) {
50 count
= zend_array_count(Z_ARRVAL_P(zvalue
));
54 if (Z_OBJ_HT_P(zvalue
)->count_elements
) {
55 if (SUCCESS
== Z_OBJ_HT_P(zvalue
)->count_elements(zvalue
, &count
)) {
60 if (instanceof_function(Z_OBJCE_P(zvalue
), spl_ce_Countable
)) {
61 zend_call_method_with_0_params(zvalue
, NULL
, NULL
, "count", &retval
);
62 if (Z_TYPE(retval
) != IS_UNDEF
) {
63 count
= zval_get_long(&retval
);
64 zval_ptr_dtor(&retval
);
73 int psi_internal_type(struct psi_impl_type
*type
)
92 zend_internal_arg_info
*psi_internal_arginfo(struct psi_impl
*impl
)
94 size_t i
= 0, argc
= psi_plist_count(impl
->func
->args
);
95 zend_internal_arg_info
*aip
;
96 zend_internal_function_info
*fi
;
97 struct psi_impl_arg
*iarg
;
99 aip
= calloc(argc
+ 1 + !!impl
->func
->vararg
, sizeof(*aip
));
101 fi
= (zend_internal_function_info
*) &aip
[0];
102 #ifdef ZEND_TYPE_ENCODE
103 fi
->type
= ZEND_TYPE_ENCODE(psi_internal_type(impl
->func
->return_type
), 1);
106 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
108 fi
->required_num_args
= psi_impl_num_min_args(impl
);
109 fi
->return_reference
= impl
->func
->return_reference
;
111 if (impl
->func
->vararg
) {
112 struct psi_impl_arg
*vararg
= impl
->func
->vararg
;
113 zend_internal_arg_info
*ai
= &aip
[argc
];
115 ai
->name
= vararg
->var
->name
;
116 #ifdef ZEND_TYPE_ENCODE
117 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(vararg
->type
), 1);
120 ai
->type_hint
= psi_internal_type(vararg
->type
);
122 if (vararg
->var
->reference
) {
123 ai
->pass_by_reference
= 1;
128 while (psi_plist_get(impl
->func
->args
, i
++, &iarg
)) {
129 zend_internal_arg_info
*ai
= &aip
[i
];
131 ai
->name
= iarg
->var
->name
;
132 #ifdef ZEND_TYPE_ENCODE
133 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(iarg
->type
), 1);
136 ai
->type_hint
= psi_internal_type(iarg
->type
);
138 if (iarg
->var
->reference
) {
139 ai
->pass_by_reference
= 1;
149 void psi_set_void(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
157 impl_val
*psi_let_void(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
163 * set $ivar = zval(dvar)
165 void psi_set_zval(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
) {
166 RETVAL_ZVAL(ret_val
->ptr
, 1, 0);
170 * let dvar = zval($ivar)
172 impl_val
*psi_let_zval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
174 *to_free
= tmp
->ptr
= emalloc(sizeof(zval
));
175 ZVAL_COPY_VALUE(tmp
->ptr
, zvalue
);
180 * return to_bool(dvar)
182 void psi_set_to_bool(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
184 psi_set_to_int(return_value
, set
, ret_val
, frame
);
185 convert_to_boolean(return_value
);
188 static inline impl_val
*psi_val_boolval(impl_val
*tmp
, token_t real_type
, zend_bool boolval
) {
190 case PSI_T_INT8
: tmp
->i8
= boolval
; break;
191 case PSI_T_UINT8
: tmp
->u8
= boolval
; break;
192 case PSI_T_INT16
: tmp
->i16
= boolval
; break;
193 case PSI_T_UINT16
: tmp
->u16
= boolval
; break;
194 case PSI_T_INT32
: tmp
->i32
= boolval
; break;
195 case PSI_T_UINT32
: tmp
->u32
= boolval
; break;
196 case PSI_T_INT64
: tmp
->i64
= boolval
; break;
197 case PSI_T_UINT64
: tmp
->u64
= boolval
; break;
198 case PSI_T_FLOAT
: tmp
->fval
= boolval
; break;
199 case PSI_T_DOUBLE
: tmp
->dval
= boolval
; break;
200 #ifdef HAVE_LONG_DOUBLE
201 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= boolval
; break;
203 EMPTY_SWITCH_DEFAULT_CASE();
209 * let dvar = boolval($ivar)
211 impl_val
*psi_let_boolval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
214 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_UINT8
;
216 if (ival
&& impl_type
== PSI_T_BOOL
) {
217 boolval
= ival
->zend
.bval
;
219 boolval
= zend_is_true(zvalue
);
222 return psi_val_boolval(tmp
, real_type
, boolval
);
225 # define RETVAL_LONG_U64(V) \
226 if (V > ZEND_LONG_MAX) { \
228 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
234 * set $ivar = to_int(*dvar)
236 void psi_set_to_int(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
238 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
239 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
240 impl_val
*v
= deref_impl_val(ret_val
, var
);
243 case PSI_T_INT8
: RETVAL_LONG(v
->i8
); break;
244 case PSI_T_UINT8
: RETVAL_LONG(v
->u8
); break;
245 case PSI_T_INT16
: RETVAL_LONG(v
->i16
); break;
246 case PSI_T_UINT16
: RETVAL_LONG(v
->u16
); break;
247 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
248 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
249 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
250 case PSI_T_UINT64
: RETVAL_LONG_U64(v
->u64
); break;
251 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
252 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
253 #ifdef HAVE_LONG_DOUBLE
254 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
256 EMPTY_SWITCH_DEFAULT_CASE();
259 convert_to_long(return_value
);
262 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
264 case PSI_T_INT8
: tmp
->i8
= intval
; break;
265 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
266 case PSI_T_INT16
: tmp
->i16
= intval
; break;
267 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
268 case PSI_T_INT32
: tmp
->i32
= intval
; break;
269 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
270 case PSI_T_INT64
: tmp
->i64
= intval
; break;
271 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
272 case PSI_T_INT
: tmp
->ival
= intval
; break;
273 case PSI_T_LONG
: tmp
->lval
= intval
; break;
274 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
275 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
276 #ifdef HAVE_LONG_DOUBLE
277 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
279 EMPTY_SWITCH_DEFAULT_CASE();
286 * let dvar = intval($ivar)
288 impl_val
*psi_let_intval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
291 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_LONG
;
293 if (ival
&& impl_type
== PSI_T_INT
) {
294 intval
= ival
->zend
.lval
;
296 intval
= zval_get_long(zvalue
);
299 return psi_val_intval(tmp
, real_type
, intval
);
303 * set $ivar = to_float(dvar)
305 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
307 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
308 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
309 impl_val
*v
= deref_impl_val(ret_val
, var
);
312 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
313 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
314 #ifdef HAVE_LONG_DOUBLE
315 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
317 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
318 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
319 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
320 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
321 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
322 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
323 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
324 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
325 EMPTY_SWITCH_DEFAULT_CASE();
329 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
331 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
332 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
333 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
334 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
335 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
336 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
337 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
338 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
339 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
340 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
341 #ifdef HAVE_LONG_DOUBLE
342 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
344 EMPTY_SWITCH_DEFAULT_CASE();
351 * let dvar = floatval($ivar)
353 impl_val
*psi_let_floatval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
356 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_DOUBLE
;
358 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
359 floatval
= ival
->dval
;
361 floatval
= zval_get_double(zvalue
);
364 return psi_val_floatval(tmp
, real_type
, floatval
);
368 * set $ivar = to_string(dvar)
370 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
372 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
373 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
376 if (var
->arg
->var
->array_size
) {
385 RETVAL_EMPTY_STRING();
390 * set $ivar = to_string(dvar, num_exp)
392 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
394 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
395 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
398 struct psi_set_exp
*sub_exp
;
400 psi_plist_get(set
->inner
, 0, &sub_exp
);
401 RETVAL_STRINGL(str
, psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
));
403 RETVAL_EMPTY_STRING();
408 * let dvar = strval($ivar)
410 impl_val
*psi_let_strval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
412 if (ival
&& impl_type
== PSI_T_STRING
) {
413 if (ival
->zend
.str
) {
414 tmp
->ptr
= ival
->zend
.str
->val
;
419 zend_string
*zs
= zval_get_string(zvalue
);
420 tmp
->ptr
= estrdup(zs
->val
);
422 zend_string_release(zs
);
429 * let dvar = pathval($ivar)
431 impl_val
*psi_let_pathval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
433 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
434 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
437 return *to_free
= NULL
;
443 * let dvar = strlen($ivar)
445 impl_val
*psi_let_strlen(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
447 if (ival
&& impl_type
== PSI_T_STRING
) {
448 if (ival
->zend
.str
) {
449 tmp
->lval
= ival
->zend
.str
->len
;
454 zend_string
*zs
= zval_get_string(zvalue
);
456 zend_string_release(zs
);
463 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
465 memset(tmp
, 0, sizeof(*tmp
));
466 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
472 * set $ivar = to_array(dvar,
473 * $foo = to_int(d_foo),
474 * $bar = to_string(d_bar),
475 * $baz = to_array(*d_next, ...)
477 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
478 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
482 * set $ivar = to_array(dvar, to_string(*dvar));
484 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
486 struct psi_set_exp
*sub_exp
;
487 struct psi_decl_var
*var
;
492 array_init(return_value
);
494 var
= psi_set_exp_get_decl_var(set
);
495 ret_val
= deref_impl_val(r_val
, var
);
496 if ((intptr_t) ret_val
<= (intptr_t) 0) {
500 psi_plist_get(set
->inner
, 0, &sub_exp
);
502 size
= psi_decl_arg_get_size(var
->arg
);
503 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
507 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
508 add_next_index_zval(return_value
, &ele
);
513 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
515 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
517 struct psi_set_exp
*sub_exp
;
518 struct psi_decl_var
*var
;
524 array_init(return_value
);
526 var
= psi_set_exp_get_decl_var(set
);
527 ret_val
= deref_impl_val(r_val
, var
);
528 if ((intptr_t) ret_val
<= (intptr_t) 0) {
532 psi_plist_get(set
->inner
, 0, &sub_exp
);
533 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
);
534 psi_plist_get(set
->inner
, 1, &sub_exp
);
536 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
537 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
541 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
542 add_next_index_zval(return_value
, &ele
);
549 * set $ivar = to_array(dvar,
550 * $foo = to_int(d_foo),
551 * $bar = to_string(d_bar));
553 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
555 struct psi_set_exp
*sub_exp
;
556 struct psi_decl_var
*var
;
560 array_init(return_value
);
562 var
= psi_set_exp_get_decl_var(set
);
563 ret_val
= deref_impl_val(r_val
, var
);
564 if ((intptr_t) ret_val
<= (intptr_t) 0) {
568 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
570 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
571 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
572 struct psi_call_frame_symbol
*sym
;
574 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
575 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
578 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
579 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
583 //impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
585 // decl_type *real = real_decl_type(spec);
589 // decl_arg tmp_arg = {0};
591 // if (impl_type != PSI_T_ARRAY) {
592 // SEPARATE_ARG_IF_REF(zvalue);
593 // convert_to_array(zvalue);
595 // arr = HASH_OF(zvalue);
597 // switch (real->type) {
598 // case PSI_T_STRUCT:
599 // *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
602 // *to_free = tmp = psi_array_to_union(real->real.unn, arr);
605 // sz = psi_t_size(real->type);
606 // tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
607 // tmp_arg.type = spec;
608 // tmp_arg.var = spec_var;
609 // ZEND_HASH_FOREACH_VAL_IND(arr, zv)
611 // void *ptr = ((char *) tmp) + (i++ * sz);
612 // psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
614 // ZEND_HASH_FOREACH_END();
621 * let dvar = count($ivar)
623 impl_val
*psi_let_count(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
625 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
)->type
, psi_zval_count(zvalue
));
629 * set $ivar = to_object(dvar)
631 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
633 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
634 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
636 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
637 object_init_ex(return_value
, psi_object_get_class_entry());
638 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
645 * let dvar = objval($ivar)
647 impl_val
*psi_let_objval(impl_val
*tmp
, struct psi_decl_type
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
651 if (Z_TYPE_P(zvalue
) != IS_OBJECT
652 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
656 obj
= PSI_OBJ(zvalue
, NULL
);
657 tmp
->ptr
= obj
->data
;