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];
103 fi
->required_num_args
= psi_impl_num_min_args(impl
);
104 fi
->return_reference
= impl
->func
->return_reference
;
105 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
107 if (impl
->func
->vararg
) {
108 struct psi_impl_arg
*vararg
= impl
->func
->vararg
;
109 zend_internal_arg_info
*ai
= &aip
[argc
];
111 ai
->name
= vararg
->var
->name
;
113 ai
->type_hint
= psi_internal_type(vararg
->type
);
114 if (vararg
->var
->reference
) {
115 ai
->pass_by_reference
= 1;
120 while (psi_plist_get(impl
->func
->args
, i
++, &iarg
)) {
121 zend_internal_arg_info
*ai
= &aip
[i
];
123 ai
->name
= iarg
->var
->name
;
124 ai
->type_hint
= psi_internal_type(iarg
->type
);
125 if (iarg
->var
->reference
) {
126 ai
->pass_by_reference
= 1;
128 /* FIXME: if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) */
138 void psi_set_void(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
146 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
)
152 * set $ivar = zval(dvar)
154 void psi_set_zval(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
) {
155 RETVAL_ZVAL(ret_val
->ptr
, 1, 0);
159 * let dvar = zval($ivar)
161 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
)
163 *to_free
= tmp
->ptr
= emalloc(sizeof(zval
));
164 ZVAL_COPY_VALUE(tmp
->ptr
, zvalue
);
169 * return to_bool(dvar)
171 void psi_set_to_bool(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
173 psi_set_to_int(return_value
, set
, ret_val
, frame
);
174 convert_to_boolean(return_value
);
177 static inline impl_val
*psi_val_boolval(impl_val
*tmp
, token_t real_type
, zend_bool boolval
) {
179 case PSI_T_INT8
: tmp
->i8
= boolval
; break;
180 case PSI_T_UINT8
: tmp
->u8
= boolval
; break;
181 case PSI_T_INT16
: tmp
->i16
= boolval
; break;
182 case PSI_T_UINT16
: tmp
->u16
= boolval
; break;
183 case PSI_T_INT32
: tmp
->i32
= boolval
; break;
184 case PSI_T_UINT32
: tmp
->u32
= boolval
; break;
185 case PSI_T_INT64
: tmp
->i64
= boolval
; break;
186 case PSI_T_UINT64
: tmp
->u64
= boolval
; break;
187 case PSI_T_FLOAT
: tmp
->fval
= boolval
; break;
188 case PSI_T_DOUBLE
: tmp
->dval
= boolval
; break;
189 #ifdef HAVE_LONG_DOUBLE
190 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= boolval
; break;
192 EMPTY_SWITCH_DEFAULT_CASE();
198 * let dvar = boolval($ivar)
200 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
)
203 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_UINT8
;
205 if (ival
&& impl_type
== PSI_T_BOOL
) {
206 boolval
= ival
->zend
.bval
;
208 boolval
= zend_is_true(zvalue
);
211 return psi_val_boolval(tmp
, real_type
, boolval
);
214 # define RETVAL_LONG_U64(V) \
215 if (V > ZEND_LONG_MAX) { \
217 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
223 * set $ivar = to_int(*dvar)
225 void psi_set_to_int(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
227 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
228 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
229 impl_val
*v
= deref_impl_val(ret_val
, var
);
232 case PSI_T_INT8
: RETVAL_LONG(v
->i8
); break;
233 case PSI_T_UINT8
: RETVAL_LONG(v
->u8
); break;
234 case PSI_T_INT16
: RETVAL_LONG(v
->i16
); break;
235 case PSI_T_UINT16
: RETVAL_LONG(v
->u16
); break;
236 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
237 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
238 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
239 case PSI_T_UINT64
: RETVAL_LONG_U64(v
->u64
); break;
240 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
241 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
242 #ifdef HAVE_LONG_DOUBLE
243 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
245 EMPTY_SWITCH_DEFAULT_CASE();
248 convert_to_long(return_value
);
251 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
253 case PSI_T_INT8
: tmp
->i8
= intval
; break;
254 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
255 case PSI_T_INT16
: tmp
->i16
= intval
; break;
256 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
257 case PSI_T_INT32
: tmp
->i32
= intval
; break;
258 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
259 case PSI_T_INT64
: tmp
->i64
= intval
; break;
260 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
261 case PSI_T_INT
: tmp
->ival
= intval
; break;
262 case PSI_T_LONG
: tmp
->lval
= intval
; break;
263 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
264 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
265 #ifdef HAVE_LONG_DOUBLE
266 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
268 EMPTY_SWITCH_DEFAULT_CASE();
275 * let dvar = intval($ivar)
277 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
)
280 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_LONG
;
282 if (ival
&& impl_type
== PSI_T_INT
) {
283 intval
= ival
->zend
.lval
;
285 intval
= zval_get_long(zvalue
);
288 return psi_val_intval(tmp
, real_type
, intval
);
292 * set $ivar = to_float(dvar)
294 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
296 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
297 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
298 impl_val
*v
= deref_impl_val(ret_val
, var
);
301 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
302 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
303 #ifdef HAVE_LONG_DOUBLE
304 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
306 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
307 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
308 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
309 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
310 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
311 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
312 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
313 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
314 EMPTY_SWITCH_DEFAULT_CASE();
318 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
320 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
321 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
322 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
323 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
324 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
325 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
326 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
327 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
328 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
329 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
330 #ifdef HAVE_LONG_DOUBLE
331 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
333 EMPTY_SWITCH_DEFAULT_CASE();
340 * let dvar = floatval($ivar)
342 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
)
345 token_t real_type
= spec
? psi_decl_type_get_real(spec
)->type
: PSI_T_DOUBLE
;
347 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
348 floatval
= ival
->dval
;
350 floatval
= zval_get_double(zvalue
);
353 return psi_val_floatval(tmp
, real_type
, floatval
);
357 * set $ivar = to_string(dvar)
359 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
361 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
362 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
365 if (var
->arg
->var
->array_size
) {
374 RETVAL_EMPTY_STRING();
379 * set $ivar = to_string(dvar, num_exp)
381 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
383 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
384 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
387 struct psi_set_exp
*sub_exp
;
389 psi_plist_get(set
->inner
, 0, &sub_exp
);
390 RETVAL_STRINGL(str
, psi_long_num_exp(sub_exp
->data
.num
, frame
));
392 RETVAL_EMPTY_STRING();
397 * let dvar = strval($ivar)
399 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
)
401 if (ival
&& impl_type
== PSI_T_STRING
) {
402 if (ival
->zend
.str
) {
403 tmp
->ptr
= ival
->zend
.str
->val
;
407 } else if (0 && Z_TYPE_P(zvalue
) == IS_STRING
) {
408 tmp
->ptr
= Z_STRVAL_P(zvalue
);
410 zend_string
*zs
= zval_get_string(zvalue
);
411 tmp
->ptr
= estrdup(zs
->val
);
413 zend_string_release(zs
);
420 * let dvar = pathval($ivar)
422 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
)
424 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
425 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
428 return *to_free
= NULL
;
434 * let dvar = strlen($ivar)
436 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
)
438 if (ival
&& impl_type
== PSI_T_STRING
) {
439 if (ival
->zend
.str
) {
440 tmp
->lval
= ival
->zend
.str
->len
;
445 zend_string
*zs
= zval_get_string(zvalue
);
447 zend_string_release(zs
);
453 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
455 memset(tmp
, 0, sizeof(*tmp
));
456 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
461 * set $ivar = to_array(dvar,
462 * $foo = to_int(d_foo),
463 * $bar = to_string(d_bar),
464 * $baz = to_array(*d_next, ...)
466 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
467 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
471 * set $ivar = to_array(dvar, to_string(*dvar));
473 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
475 struct psi_set_exp
*sub_exp
;
476 struct psi_decl_var
*var
;
481 array_init(return_value
);
483 var
= psi_set_exp_get_decl_var(set
);
484 ret_val
= deref_impl_val(r_val
, var
);
485 if ((intptr_t) ret_val
<= (intptr_t) 0) {
489 psi_plist_get(set
->inner
, 0, &sub_exp
);
491 size
= psi_decl_arg_get_size(var
->arg
);
492 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
496 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
497 add_next_index_zval(return_value
, &ele
);
502 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
504 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
506 struct psi_set_exp
*sub_exp
;
507 struct psi_decl_var
*var
;
513 array_init(return_value
);
515 var
= psi_set_exp_get_decl_var(set
);
516 ret_val
= deref_impl_val(r_val
, var
);
517 if ((intptr_t) ret_val
<= (intptr_t) 0) {
521 psi_plist_get(set
->inner
, 0, &sub_exp
);
522 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
);
523 psi_plist_get(set
->inner
, 1, &sub_exp
);
525 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
526 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
530 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
531 add_next_index_zval(return_value
, &ele
);
538 * set $ivar = to_array(dvar,
539 * $foo = to_int(d_foo),
540 * $bar = to_string(d_bar));
542 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
544 struct psi_set_exp
*sub_exp
;
545 struct psi_decl_var
*var
;
549 array_init(return_value
);
551 var
= psi_set_exp_get_decl_var(set
);
552 ret_val
= deref_impl_val(r_val
, var
);
553 if ((intptr_t) ret_val
<= (intptr_t) 0) {
557 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
559 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
560 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
561 struct psi_call_frame_symbol
*sym
;
563 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
564 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
567 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
568 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
572 //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)
574 // decl_type *real = real_decl_type(spec);
578 // decl_arg tmp_arg = {0};
580 // if (impl_type != PSI_T_ARRAY) {
581 // SEPARATE_ARG_IF_REF(zvalue);
582 // convert_to_array(zvalue);
584 // arr = HASH_OF(zvalue);
586 // switch (real->type) {
587 // case PSI_T_STRUCT:
588 // *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
591 // *to_free = tmp = psi_array_to_union(real->real.unn, arr);
594 // sz = psi_t_size(real->type);
595 // tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
596 // tmp_arg.type = spec;
597 // tmp_arg.var = spec_var;
598 // ZEND_HASH_FOREACH_VAL_IND(arr, zv)
600 // void *ptr = ((char *) tmp) + (i++ * sz);
601 // psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
603 // ZEND_HASH_FOREACH_END();
610 * let dvar = count($ivar)
612 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
)
614 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
)->type
, psi_zval_count(zvalue
));
618 * set $ivar = to_object(dvar)
620 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
622 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
623 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
625 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
626 object_init_ex(return_value
, psi_object_get_class_entry());
627 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
634 * let dvar = objval($ivar)
636 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
)
640 if (Z_TYPE_P(zvalue
) != IS_OBJECT
641 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
645 obj
= PSI_OBJ(zvalue
, NULL
);
646 tmp
->ptr
= obj
->data
;