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 fi
->type
= ZEND_TYPE_ENCODE(psi_internal_type(impl
->func
->return_type
), 1);
103 fi
->required_num_args
= psi_impl_num_min_args(impl
);
104 fi
->return_reference
= impl
->func
->return_reference
;
106 if (impl
->func
->vararg
) {
107 struct psi_impl_arg
*vararg
= impl
->func
->vararg
;
108 zend_internal_arg_info
*ai
= &aip
[argc
];
110 ai
->name
= vararg
->var
->name
;
111 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(vararg
->type
), 1);
112 if (vararg
->var
->reference
) {
113 ai
->pass_by_reference
= 1;
118 while (psi_plist_get(impl
->func
->args
, i
++, &iarg
)) {
119 zend_internal_arg_info
*ai
= &aip
[i
];
121 ai
->name
= iarg
->var
->name
;
122 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(iarg
->type
), 1);
123 if (iarg
->var
->reference
) {
124 ai
->pass_by_reference
= 1;
134 void psi_set_void(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
142 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
)
148 * set $ivar = zval(dvar)
150 void psi_set_zval(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
) {
151 RETVAL_ZVAL(ret_val
->ptr
, 1, 0);
155 * let dvar = zval($ivar)
157 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
)
159 *to_free
= tmp
->ptr
= emalloc(sizeof(zval
));
160 ZVAL_COPY_VALUE(tmp
->ptr
, zvalue
);
165 * return to_bool(dvar)
167 void psi_set_to_bool(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
169 psi_set_to_int(return_value
, set
, ret_val
, frame
);
170 convert_to_boolean(return_value
);
173 static inline impl_val
*psi_val_boolval(impl_val
*tmp
, token_t real_type
, zend_bool boolval
) {
175 case PSI_T_INT8
: tmp
->i8
= boolval
; break;
176 case PSI_T_UINT8
: tmp
->u8
= boolval
; break;
177 case PSI_T_INT16
: tmp
->i16
= boolval
; break;
178 case PSI_T_UINT16
: tmp
->u16
= boolval
; break;
179 case PSI_T_INT32
: tmp
->i32
= boolval
; break;
180 case PSI_T_UINT32
: tmp
->u32
= boolval
; break;
181 case PSI_T_INT64
: tmp
->i64
= boolval
; break;
182 case PSI_T_UINT64
: tmp
->u64
= boolval
; break;
183 case PSI_T_FLOAT
: tmp
->fval
= boolval
; break;
184 case PSI_T_DOUBLE
: tmp
->dval
= boolval
; break;
185 #ifdef HAVE_LONG_DOUBLE
186 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= boolval
; break;
188 EMPTY_SWITCH_DEFAULT_CASE();
194 * let dvar = boolval($ivar)
196 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
)
199 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_UINT8
;
201 if (ival
&& impl_type
== PSI_T_BOOL
) {
202 boolval
= ival
->zend
.bval
;
204 boolval
= zend_is_true(zvalue
);
207 return psi_val_boolval(tmp
, real_type
, boolval
);
210 # define RETVAL_LONG_U64(V) \
211 if (V > ZEND_LONG_MAX) { \
213 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
219 * set $ivar = to_int(*dvar)
221 void psi_set_to_int(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
223 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
224 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
225 impl_val
*v
= deref_impl_val(ret_val
, var
);
228 case PSI_T_INT8
: RETVAL_LONG(v
->i8
); break;
229 case PSI_T_UINT8
: RETVAL_LONG(v
->u8
); break;
230 case PSI_T_INT16
: RETVAL_LONG(v
->i16
); break;
231 case PSI_T_UINT16
: RETVAL_LONG(v
->u16
); break;
232 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
233 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
234 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
235 case PSI_T_UINT64
: RETVAL_LONG_U64(v
->u64
); break;
236 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
237 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
238 #ifdef HAVE_LONG_DOUBLE
239 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
241 EMPTY_SWITCH_DEFAULT_CASE();
244 convert_to_long(return_value
);
247 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
249 case PSI_T_INT8
: tmp
->i8
= intval
; break;
250 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
251 case PSI_T_INT16
: tmp
->i16
= intval
; break;
252 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
253 case PSI_T_INT32
: tmp
->i32
= intval
; break;
254 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
255 case PSI_T_INT64
: tmp
->i64
= intval
; break;
256 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
257 case PSI_T_INT
: tmp
->ival
= intval
; break;
258 case PSI_T_LONG
: tmp
->lval
= intval
; break;
259 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
260 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
261 #ifdef HAVE_LONG_DOUBLE
262 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
264 EMPTY_SWITCH_DEFAULT_CASE();
271 * let dvar = intval($ivar)
273 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
)
276 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_LONG
;
278 if (ival
&& impl_type
== PSI_T_INT
) {
279 intval
= ival
->zend
.lval
;
281 intval
= zval_get_long(zvalue
);
284 return psi_val_intval(tmp
, real_type
, intval
);
288 * set $ivar = to_float(dvar)
290 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
292 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
293 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
294 impl_val
*v
= deref_impl_val(ret_val
, var
);
297 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
298 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
299 #ifdef HAVE_LONG_DOUBLE
300 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
302 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
303 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
304 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
305 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
306 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
307 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
308 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
309 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
310 EMPTY_SWITCH_DEFAULT_CASE();
314 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
316 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
317 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
318 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
319 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
320 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
321 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
322 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
323 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
324 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
325 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
326 #ifdef HAVE_LONG_DOUBLE
327 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
329 EMPTY_SWITCH_DEFAULT_CASE();
336 * let dvar = floatval($ivar)
338 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
)
341 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_DOUBLE
;
343 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
344 floatval
= ival
->dval
;
346 floatval
= zval_get_double(zvalue
);
349 return psi_val_floatval(tmp
, real_type
, floatval
);
353 * set $ivar = to_string(dvar)
355 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
357 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
358 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
361 if (var
->arg
->var
->array_size
) {
370 RETVAL_EMPTY_STRING();
375 * set $ivar = to_string(dvar, num_exp)
377 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
379 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
380 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
383 struct psi_set_exp
*sub_exp
;
385 psi_plist_get(set
->inner
, 0, &sub_exp
);
386 RETVAL_STRINGL(str
, psi_long_num_exp(sub_exp
->data
.num
, frame
));
388 RETVAL_EMPTY_STRING();
393 * let dvar = strval($ivar)
395 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
)
397 if (ival
&& impl_type
== PSI_T_STRING
) {
398 if (ival
->zend
.str
) {
399 tmp
->ptr
= ival
->zend
.str
->val
;
403 } else if (0 && Z_TYPE_P(zvalue
) == IS_STRING
) {
404 tmp
->ptr
= Z_STRVAL_P(zvalue
);
406 zend_string
*zs
= zval_get_string(zvalue
);
407 tmp
->ptr
= estrdup(zs
->val
);
409 zend_string_release(zs
);
416 * let dvar = pathval($ivar)
418 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
)
420 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
421 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
424 return *to_free
= NULL
;
430 * let dvar = strlen($ivar)
432 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
)
434 if (ival
&& impl_type
== PSI_T_STRING
) {
435 if (ival
->zend
.str
) {
436 tmp
->lval
= ival
->zend
.str
->len
;
441 zend_string
*zs
= zval_get_string(zvalue
);
443 zend_string_release(zs
);
449 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
451 memset(tmp
, 0, sizeof(*tmp
));
452 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
457 * set $ivar = to_array(dvar,
458 * $foo = to_int(d_foo),
459 * $bar = to_string(d_bar),
460 * $baz = to_array(*d_next, ...)
462 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
463 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
467 * set $ivar = to_array(dvar, to_string(*dvar));
469 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
471 struct psi_set_exp
*sub_exp
;
472 struct psi_decl_var
*var
;
477 array_init(return_value
);
479 var
= psi_set_exp_get_decl_var(set
);
480 ret_val
= deref_impl_val(r_val
, var
);
481 if ((intptr_t) ret_val
<= (intptr_t) 0) {
485 psi_plist_get(set
->inner
, 0, &sub_exp
);
487 size
= psi_decl_arg_get_size(var
->arg
);
488 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
492 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
493 add_next_index_zval(return_value
, &ele
);
498 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
500 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
502 struct psi_set_exp
*sub_exp
;
503 struct psi_decl_var
*var
;
509 array_init(return_value
);
511 var
= psi_set_exp_get_decl_var(set
);
512 ret_val
= deref_impl_val(r_val
, var
);
513 if ((intptr_t) ret_val
<= (intptr_t) 0) {
517 psi_plist_get(set
->inner
, 0, &sub_exp
);
518 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
);
519 psi_plist_get(set
->inner
, 1, &sub_exp
);
521 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
522 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
526 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
527 add_next_index_zval(return_value
, &ele
);
534 * set $ivar = to_array(dvar,
535 * $foo = to_int(d_foo),
536 * $bar = to_string(d_bar));
538 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
540 struct psi_set_exp
*sub_exp
;
541 struct psi_decl_var
*var
;
545 array_init(return_value
);
547 var
= psi_set_exp_get_decl_var(set
);
548 ret_val
= deref_impl_val(r_val
, var
);
549 if ((intptr_t) ret_val
<= (intptr_t) 0) {
553 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
555 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
556 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
557 struct psi_call_frame_symbol
*sym
;
559 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
560 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
563 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
564 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
568 //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)
570 // decl_type *real = real_decl_type(spec);
574 // decl_arg tmp_arg = {0};
576 // if (impl_type != PSI_T_ARRAY) {
577 // SEPARATE_ARG_IF_REF(zvalue);
578 // convert_to_array(zvalue);
580 // arr = HASH_OF(zvalue);
582 // switch (real->type) {
583 // case PSI_T_STRUCT:
584 // *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
587 // *to_free = tmp = psi_array_to_union(real->real.unn, arr);
590 // sz = psi_t_size(real->type);
591 // tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
592 // tmp_arg.type = spec;
593 // tmp_arg.var = spec_var;
594 // ZEND_HASH_FOREACH_VAL_IND(arr, zv)
596 // void *ptr = ((char *) tmp) + (i++ * sz);
597 // psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
599 // ZEND_HASH_FOREACH_END();
606 * let dvar = count($ivar)
608 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
)
610 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
)->type
, psi_zval_count(zvalue
));
614 * set $ivar = to_object(dvar)
616 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
618 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
619 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
621 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
622 object_init_ex(return_value
, psi_object_get_class_entry());
623 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
630 * let dvar = objval($ivar)
632 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
)
636 if (Z_TYPE_P(zvalue
) != IS_OBJECT
637 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
641 obj
= PSI_OBJ(zvalue
, NULL
);
642 tmp
->ptr
= obj
->data
;