834a38f3b4bc0323914001e3ac3d6ecffbda7989
[m6w6/ext-psi] / src / marshal.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
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.
13
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 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include "data.h"
28 #include "calc.h"
29
30 #include "php.h"
31 #include "php_psi.h"
32
33 #include "Zend/zend_interfaces.h"
34 #include "ext/spl/spl_iterators.h"
35
36 zend_long psi_zval_count(zval *zvalue)
37 {
38 /* mimic PHP count() */
39 zend_long count;
40 zval retval;
41
42 switch (Z_TYPE_P(zvalue)) {
43 default:
44 count = 1;
45 break;
46 case IS_NULL:
47 count = 0;
48 break;
49 case IS_ARRAY:
50 count = zend_array_count(Z_ARRVAL_P(zvalue));
51 break;
52 case IS_OBJECT:
53 count = 1;
54 if (Z_OBJ_HT_P(zvalue)->count_elements) {
55 if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) {
56 break;
57 }
58 }
59
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);
65 }
66 }
67 break;
68 }
69
70 return count;
71 }
72
73 int psi_internal_type(struct psi_impl_type *type)
74 {
75 switch (type->type) {
76 case PSI_T_BOOL:
77 return _IS_BOOL;
78 case PSI_T_INT:
79 return IS_LONG;
80 case PSI_T_FLOAT:
81 case PSI_T_DOUBLE:
82 return IS_DOUBLE;
83 case PSI_T_STRING:
84 return IS_STRING;
85 case PSI_T_ARRAY:
86 return IS_ARRAY;
87 default:
88 return 0;
89 }
90 }
91
92 zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
93 {
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;
98
99 aip = calloc(argc + 1 + !!impl->func->vararg, sizeof(*aip));
100
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);
104 #else
105 fi->allow_null = 1;
106 fi->type_hint = psi_internal_type(impl->func->return_type);
107 #endif
108 fi->required_num_args = psi_impl_num_min_args(impl);
109 fi->return_reference = impl->func->return_reference;
110
111 if (impl->func->vararg) {
112 struct psi_impl_arg *vararg = impl->func->vararg;
113 zend_internal_arg_info *ai = &aip[argc];
114
115 ai->name = vararg->var->name;
116 #ifdef ZEND_TYPE_ENCODE
117 ai->type = ZEND_TYPE_ENCODE(psi_internal_type(vararg->type), 1);
118 #else
119 ai->allow_null = 1;
120 ai->type_hint = psi_internal_type(vararg->type);
121 #endif
122 if (vararg->var->reference) {
123 ai->pass_by_reference = 1;
124 }
125 ai->is_variadic = 1;
126 }
127
128 while (psi_plist_get(impl->func->args, i++, &iarg)) {
129 zend_internal_arg_info *ai = &aip[i];
130
131 ai->name = iarg->var->name;
132 #ifdef ZEND_TYPE_ENCODE
133 ai->type = ZEND_TYPE_ENCODE(psi_internal_type(iarg->type), 1);
134 #else
135 ai->allow_null = 1;
136 ai->type_hint = psi_internal_type(iarg->type);
137 #endif
138 if (iarg->var->reference) {
139 ai->pass_by_reference = 1;
140 }
141 }
142
143 return aip;
144 }
145
146 /*
147 * return void(dvar)
148 */
149 void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
150 {
151 RETVAL_NULL();
152 }
153
154 /*
155 * ?
156 */
157 impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
158 {
159 return tmp;
160 }
161
162 /*
163 * set $ivar = zval(dvar)
164 */
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);
167 }
168
169 /*
170 * let dvar = zval($ivar)
171 */
172 impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
173 {
174 *to_free = tmp->ptr = emalloc(sizeof(zval));
175 ZVAL_COPY_VALUE(tmp->ptr, zvalue);
176 return tmp;
177 }
178
179 /*
180 * return to_bool(dvar)
181 */
182 void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
183 {
184 psi_set_to_int(return_value, set, ret_val, frame);
185 convert_to_boolean(return_value);
186 }
187
188 static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_bool boolval) {
189 switch (real_type) {
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 #ifdef HAVE_INT128
199 case PSI_T_INT128: tmp->i128 = boolval; break;
200 case PSI_T_UINT128: tmp->u128 = boolval; break;
201 #endif
202 case PSI_T_FLOAT: tmp->fval = boolval; break;
203 case PSI_T_DOUBLE: tmp->dval = boolval; break;
204 #ifdef HAVE_LONG_DOUBLE
205 case PSI_T_LONG_DOUBLE: tmp->ldval = boolval; break;
206 #endif
207 EMPTY_SWITCH_DEFAULT_CASE();
208 }
209 return tmp;
210 }
211
212 /*
213 * let dvar = boolval($ivar)
214 */
215 impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
216 {
217 zend_bool boolval;
218 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8;
219
220 if (ival && impl_type == PSI_T_BOOL) {
221 boolval = ival->zend.bval;
222 } else {
223 boolval = zend_is_true(zvalue);
224 }
225
226 return psi_val_boolval(tmp, real_type, boolval);
227 }
228
229 #if HAVE_INT128
230 static inline char *psi_u128_to_buf(char *buf, unsigned __int128 u128)
231 {
232 for (*buf = 0; u128 > 0; u128 /= 10) {
233 *--buf = ((u128 % 10) + '0') & 0xff;
234 }
235 return buf;
236 }
237
238 static inline char *psi_i128_to_buf(char *buf, __int128 i128)
239 {
240 if (i128 < 0) {
241 char *res = psi_u128_to_buf(buf, ~((unsigned __int128) i128) + 1);
242
243 *--res = '-';
244 return res;
245 }
246 return psi_u128_to_buf(buf, i128);
247 }
248
249 # define RETVAL_LONG_STR(V, s) do {\
250 char buf[0x30] = {0}; \
251 if (s && V >= ZEND_LONG_MIN && V <= ZEND_LONG_MAX) { \
252 RETVAL_LONG(V); \
253 } else if (!s && V <= ZEND_LONG_MAX) { \
254 RETVAL_LONG(V); \
255 } else if (!s && V <= ZEND_ULONG_MAX) { \
256 RETVAL_STRING(zend_print_ulong_to_buf(&buf[sizeof(buf) - 1], V)); \
257 } else if (s && V >= INT128_MIN && V <= INT128_MAX) { \
258 RETVAL_STRING(psi_i128_to_buf(&buf[sizeof(buf) - 1], V)); \
259 } else { \
260 RETVAL_STRING(psi_u128_to_buf(&buf[sizeof(buf) - 1], V)); \
261 } \
262 } while (0)
263 #else
264 # define RETVAL_LONG_STR(V, s) do {\
265 char buf[0x20] = {0}; \
266 if (s && V >= ZEND_LONG_MIN && V <= ZEND_LONG_MAX) { \
267 RETVAL_LONG(V); \
268 } else if (!s && V <= ZEND_LONG_MAX) { \
269 RETVAL_LONG(V); \
270 } else { \
271 RETVAL_STRING(zend_print_ulong_to_buf(&buf[sizeof(buf) - 1], V)); \
272 } \
273 } while (0)
274 #endif
275 /*
276 * set $ivar = to_int(*dvar)
277 */
278 void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
279 {
280 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
281 token_t t = psi_decl_type_get_real(var->arg->type)->type;
282 impl_val *v = deref_impl_val(ret_val, var);
283
284 switch (t) {
285 case PSI_T_INT8: RETVAL_LONG(v->i8); break;
286 case PSI_T_UINT8: RETVAL_LONG(v->u8); break;
287 case PSI_T_INT16: RETVAL_LONG(v->i16); break;
288 case PSI_T_UINT16: RETVAL_LONG(v->u16); break;
289 case PSI_T_ENUM:
290 case PSI_T_INT32: RETVAL_LONG(v->i32); break;
291 case PSI_T_UINT32: RETVAL_LONG(v->u32); break;
292 case PSI_T_INT64: RETVAL_LONG(v->i64); break;
293 case PSI_T_UINT64: RETVAL_LONG_STR(v->u64, 0); break;
294 #ifdef HAVE_INT128
295 case PSI_T_INT128: RETVAL_LONG_STR(v->i128, 1); break;
296 case PSI_T_UINT128: RETVAL_LONG_STR(v->u128, 0); break;
297 #endif
298 case PSI_T_FLOAT:
299 RETVAL_DOUBLE((double) v->fval);
300 convert_to_long(return_value);
301 break;
302 case PSI_T_DOUBLE:
303 RETVAL_DOUBLE(v->dval);
304 convert_to_long(return_value);
305 break;
306 #ifdef HAVE_LONG_DOUBLE
307 case PSI_T_LONG_DOUBLE:
308 RETVAL_DOUBLE((double) v->ldval);
309 convert_to_long(return_value);
310 break;
311 #endif
312 EMPTY_SWITCH_DEFAULT_CASE();
313 }
314 }
315
316 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
317 switch (real_type) {
318 case PSI_T_INT8: tmp->i8 = intval; break;
319 case PSI_T_UINT8: tmp->u8 = intval; break;
320 case PSI_T_INT16: tmp->i16 = intval; break;
321 case PSI_T_UINT16: tmp->u16 = intval; break;
322 case PSI_T_ENUM:
323 case PSI_T_INT32: tmp->i32 = intval; break;
324 case PSI_T_UINT32: tmp->u32 = intval; break;
325 case PSI_T_INT64: tmp->i64 = intval; break;
326 case PSI_T_UINT64: tmp->u64 = intval; break;
327 #if HAVE_INT128
328 case PSI_T_INT128: tmp->i128 = intval; break;
329 case PSI_T_UINT128: tmp->u128 = intval; break;
330 #endif
331 case PSI_T_FLOAT: tmp->fval = intval; break;
332 case PSI_T_DOUBLE: tmp->dval = intval; break;
333 #ifdef HAVE_LONG_DOUBLE
334 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
335 #endif
336 EMPTY_SWITCH_DEFAULT_CASE();
337 }
338
339 return tmp;
340 }
341
342 #if HAVE_INT128
343 void psi_strto_i128(char *ptr, char *end, token_t real_type, impl_val *val) {
344 unsigned __int128 i = 0;
345 bool oct = false, hex = false, sign = false;
346
347 if (*ptr == '+') {
348 ++ptr;
349 } else if (*ptr == '-') {
350 sign = true;
351 ++ptr;
352 } else if (*ptr == '\\') {
353 switch (*++ptr) {
354 case 'x':
355 hex = true;
356 ++ptr;
357 break;
358 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
359 oct = true;
360 break;
361 default:
362 goto fail;
363 }
364 }
365 while (ptr < end) {
366 switch (*ptr) {
367 case '8':case '9':
368 if (oct) {
369 goto fail;
370 }
371 /* no break */
372 case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':
373 if (oct) {
374 i <<= 3;
375 } else if (hex) {
376 i <<= 4;
377 } else {
378 i *= 10;
379 }
380 i += *ptr - '0';
381 break;
382 case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
383 if (!hex) {
384 goto fail;
385 }
386 i <<= 4;
387 i += 10 + (*ptr - 'a');
388 break;
389 case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
390 if (!hex) {
391 goto fail;
392 }
393 i <<= 4;
394 i += 10 + (*ptr - 'A');
395 break;
396 default:
397 fail:
398 zend_error(E_WARNING, "A non well formed numeric value encountered");
399 goto stop;
400 }
401 ++ptr;
402 }
403
404 stop:
405 if (real_type == PSI_T_UINT128) {
406 if (sign) {
407 val->u128 = -i;
408 } else {
409 val->u128 = i;
410 }
411 } else {
412 if (sign) {
413 val->i128 = -i;
414 } else {
415 val->i128 = i;
416 }
417 }
418 }
419 #endif
420
421 /*
422 * let dvar = intval($ivar)
423 */
424 impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
425 {
426 int64_t intval;
427 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_INT64;
428
429
430 if (ival && impl_type == PSI_T_INT) {
431 intval = ival->zend.lval;
432 #if HAVE_INT128
433 } else if ((real_type == PSI_T_UINT128 || real_type == PSI_T_INT128) &&
434 !((Z_TYPE_P(zvalue) == IS_TRUE || Z_TYPE_P(zvalue) == IS_FALSE || Z_TYPE_P(zvalue) == IS_LONG || Z_TYPE_P(zvalue) == IS_DOUBLE || Z_TYPE_P(zvalue) == IS_NULL))) {
435 zend_string *str = zval_get_string(zvalue);
436 psi_strto_i128(str->val, str->val + str->len, real_type, tmp);
437 zend_string_release(str);
438 return tmp;
439 #endif
440 } else {
441 intval = zval_get_long(zvalue);
442 }
443
444 return psi_val_intval(tmp, real_type, intval);
445 }
446
447 /*
448 * set $ivar = to_float(dvar)
449 */
450 void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
451 {
452 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
453 token_t t = psi_decl_type_get_real(var->arg->type)->type;
454 impl_val *v = deref_impl_val(ret_val, var);
455
456 switch (t) {
457 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
458 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
459 #ifdef HAVE_LONG_DOUBLE
460 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
461 #endif
462 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
463 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
464 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
465 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
466 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
467 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
468 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
469 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
470 #if HAVE_INT128
471 case PSI_T_INT128: RETVAL_DOUBLE((double) v->i128); break;
472 case PSI_T_UINT128: RETVAL_DOUBLE((double) v->u128); break;
473 #endif
474 EMPTY_SWITCH_DEFAULT_CASE();
475 }
476 }
477
478 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
479 switch (real_type) {
480 case PSI_T_INT8: tmp->i8 = floatval; break;
481 case PSI_T_UINT8: tmp->u8 = floatval; break;
482 case PSI_T_INT16: tmp->i16 = floatval; break;
483 case PSI_T_UINT16: tmp->u16 = floatval; break;
484 case PSI_T_INT32: tmp->i32 = floatval; break;
485 case PSI_T_UINT32: tmp->u32 = floatval; break;
486 case PSI_T_INT64: tmp->i64 = floatval; break;
487 case PSI_T_UINT64: tmp->u64 = floatval; break;
488 #if HAVE_INT128
489 case PSI_T_INT128: tmp->i128 = floatval; break;
490 case PSI_T_UINT128: tmp->u128 = floatval; break;
491 #endif
492 case PSI_T_FLOAT: tmp->fval = floatval; break;
493 case PSI_T_DOUBLE: tmp->dval = floatval; break;
494 #ifdef HAVE_LONG_DOUBLE
495 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
496 #endif
497 EMPTY_SWITCH_DEFAULT_CASE();
498 }
499
500 return tmp;
501 }
502
503 /*
504 * let dvar = floatval($ivar)
505 */
506 impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
507 {
508 double floatval;
509 token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE;
510
511 if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
512 floatval = ival->dval;
513 } else {
514 floatval = zval_get_double(zvalue);
515 }
516
517 return psi_val_floatval(tmp, real_type, floatval);
518 }
519
520 /*
521 * set $ivar = to_string(dvar)
522 */
523 void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
524 {
525 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
526 impl_val *ptr = deref_impl_val(ret_val, var);
527 char *str;
528
529 /* holy moly, this breaks arrays of pointers to char,
530 * like e.g. tzname */
531 if (var->arg->var->array_size && var->arg->var->pointer_level == 1) {
532 str = (char *) ptr;
533 } else {
534 str = ptr->ptr;
535 }
536
537 if (str) {
538 RETVAL_STRING(str);
539 } else {
540 RETVAL_EMPTY_STRING();
541 }
542 }
543
544 /*
545 * set $ivar = to_string(dvar, num_exp)
546 */
547 void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
548 {
549 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
550 char *str = deref_impl_val(ret_val, var)->ptr;
551
552 if (str) {
553 struct psi_set_exp *sub_exp;
554
555 psi_plist_get(set->inner, 0, &sub_exp);
556 RETVAL_STRINGL(str, psi_num_exp_get_long(sub_exp->data.num, frame, NULL));
557 } else {
558 RETVAL_EMPTY_STRING();
559 }
560 }
561
562 /*
563 * let dvar = strval($ivar)
564 */
565 impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
566 {
567 if (ival && impl_type == PSI_T_STRING) {
568 if (ival->zend.str) {
569 tmp->ptr = ival->zend.str->val;
570 } else {
571 tmp->ptr = "";
572 }
573 } else {
574 zend_string *zs = zval_get_string(zvalue);
575 tmp->ptr = estrdup(zs->val);
576 *to_free = tmp->ptr;
577 zend_string_release(zs);
578 }
579
580 return tmp;
581 }
582
583 /*
584 * let dvar = pathval($ivar)
585 */
586 impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
587 {
588 tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
589 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
590 efree(tmp->ptr);
591 tmp->ptr = NULL;
592 return *to_free = NULL;
593 }
594 return tmp;
595 }
596
597 /*
598 * let dvar = strlen($ivar)
599 */
600 impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
601 {
602 if (ival && impl_type == PSI_T_STRING) {
603 if (ival->zend.str) {
604 tmp->u64 = ival->zend.str->len;
605 } else {
606 tmp->u64 = 0;
607 }
608 } else {
609 zend_string *zs = zval_get_string(zvalue);
610 tmp->u64 = zs->len;
611 zend_string_release(zs);
612 }
613
614 if (spec) {
615 psi_calc_cast(PSI_T_UINT64, tmp, psi_decl_type_get_real(spec->type)->type, tmp);
616 }
617 return tmp;
618 }
619
620 #if 0
621 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
622 {
623 memset(tmp, 0, sizeof(*tmp));
624 memcpy(tmp, ((char *) val) + size * i, size);
625 return tmp;
626 }
627 #endif
628
629 /*
630 * set $ivar = to_array(dvar,
631 * $foo = to_int(d_foo),
632 * $bar = to_string(d_bar),
633 * $baz = to_array(*d_next, ...)
634 */
635 void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
636 set->outer->data.func->handler(return_value, set, r_val, frame);
637 }
638
639 /*
640 * set $ivar = to_array(dvar, to_string(*dvar));
641 */
642 void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
643 {
644 struct psi_set_exp *sub_exp;
645 struct psi_decl_var *var;
646 impl_val *ret_val;
647 char *ptr;
648 size_t size;
649
650 array_init(return_value);
651
652 var = psi_set_exp_get_decl_var(set);
653 ret_val = deref_impl_val(r_val, var);
654 if ((intptr_t) ret_val <= (intptr_t) 0) {
655 return;
656 }
657
658 psi_plist_get(set->inner, 0, &sub_exp);
659
660 size = psi_decl_arg_get_size(var->arg);
661 for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
662 zval ele;
663
664 ZVAL_NULL(&ele);
665 sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
666 add_next_index_zval(return_value, &ele);
667 }
668 }
669
670 /*
671 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
672 */
673 void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
674 {
675 struct psi_set_exp *sub_exp;
676 struct psi_decl_var *var;
677 impl_val *ret_val;
678 char *ptr;
679 size_t size;
680 zend_long count;
681
682 array_init(return_value);
683
684 var = psi_set_exp_get_decl_var(set);
685 ret_val = deref_impl_val(r_val, var);
686 if ((intptr_t) ret_val <= (intptr_t) 0) {
687 return;
688 }
689
690 psi_plist_get(set->inner, 0, &sub_exp);
691 count = psi_num_exp_get_long(sub_exp->data.num, frame, NULL);
692 psi_plist_get(set->inner, 1, &sub_exp);
693
694 size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
695 for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
696 zval ele;
697
698 ZVAL_NULL(&ele);
699 sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
700 add_next_index_zval(return_value, &ele);
701 }
702 }
703
704 #include "call.h"
705
706 /*
707 * set $ivar = to_array(dvar,
708 * $foo = to_int(d_foo),
709 * $bar = to_string(d_bar));
710 */
711 void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
712 {
713 struct psi_set_exp *sub_exp;
714 struct psi_decl_var *var;
715 impl_val *ret_val;
716 size_t i = 0;
717
718 array_init(return_value);
719
720 var = psi_set_exp_get_decl_var(set);
721 ret_val = deref_impl_val(r_val, var);
722 if ((intptr_t) ret_val <= (intptr_t) 0) {
723 return;
724 }
725
726 while (psi_plist_get(set->inner, i++, &sub_exp)) {
727 zval ele;
728 struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
729 struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
730 struct psi_call_frame_symbol *sym;
731
732 sym = psi_call_frame_fetch_symbol(frame, dvar);
733 sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
734
735 ZVAL_NULL(&ele);
736 psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
737 add_assoc_zval(return_value, ivar->name + 1, &ele);
738 }
739 }
740
741 /*
742 * let dvar = count($ivar)
743 */
744 impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
745 {
746 return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue));
747 }
748
749 /*
750 * set $ivar = to_object(dvar)
751 */
752 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
753 {
754 struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
755 impl_val *ret_val = deref_impl_val(r_val, var);
756
757 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
758 object_init_ex(return_value, psi_object_get_class_entry());
759 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
760 } else {
761 RETVAL_NULL();
762 }
763 }
764
765 /*
766 * let dvar = objval($ivar)
767 */
768 impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
769 {
770 psi_object *obj;
771
772 if (Z_TYPE_P(zvalue) != IS_OBJECT
773 || !instanceof_function(Z_OBJCE_P(zvalue), psi_object_get_class_entry())) {
774 return NULL;
775 }
776
777 obj = PSI_OBJ(zvalue, NULL);
778 tmp->ptr = obj->data;
779
780 return tmp;
781 }
782