5defbd76d17ea77c3972599c5c741589112938ef
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 *******************************************************************************/
29 # include "php_config.h"
38 set_value
*init_set_value(set_func
*func
, decl_vars
*vars
) {
39 set_value
*val
= calloc(1, sizeof(*val
));
45 set_value
*add_inner_set_value(set_value
*val
, set_value
*inner
) {
46 val
->inner
= add_set_value(val
->inner
, inner
);
47 inner
->outer
.set
= val
;
51 void free_set_value(set_value
*val
) {
53 free_set_func(val
->func
);
56 free_decl_vars(val
->vars
);
59 && (!val
->outer
.set
|| val
->outer
.set
->inner
!= val
->inner
)) {
60 free_set_values(val
->inner
);
63 free_num_exp(val
->num
);
68 void dump_set_value(int fd
, set_value
*set
, unsigned level
, int last
) {
72 /* only if not directly after `set ...` */
73 dprintf(fd
, "%s", psi_t_indent(level
));
76 if (set
->func
->type
== PSI_T_ELLIPSIS
) {
77 dprintf(fd
, "%s(", set
->outer
.set
->func
->name
);
79 dprintf(fd
, "%s(", set
->func
->name
);
82 for (i
= 0; i
< set
->vars
->count
; ++i
) {
83 decl_var
*svar
= set
->vars
->vars
[i
];
87 dump_decl_var(fd
, svar
);
90 if (set
->func
->type
== PSI_T_ELLIPSIS
) {
95 dump_num_exp(fd
, set
->num
);
97 if (set
->inner
&& set
->inner
->vals
&& set
->func
->type
!= PSI_T_ELLIPSIS
) {
99 for (i
= 0; i
< set
->inner
->count
; ++i
) {
100 dump_set_value(fd
, set
->inner
->vals
[i
], level
+1, i
== (set
->inner
->count
- 1));
102 /* only if inner stmts, i.e. with new lines, were dumped */
103 dprintf(fd
, "%s", psi_t_indent(level
));
106 dprintf(fd
, ")%s\n", last
? "" : ",");
112 static inline void decl_var_arg_v(decl_args
*args
, va_list argp
) {
116 memset(args
, 0, sizeof(*args
));
118 while ((argc
= va_arg(argp
, int))) {
119 argv
= va_arg(argp
, decl_arg
**);
121 add_decl_arg(args
, *argv
++);
126 static inline int validate_set_value_handler(set_value
*set
) {
127 switch (set
->func
->type
) {
128 case PSI_T_TO_BOOL
: set
->func
->handler
= psi_to_bool
; break;
129 case PSI_T_TO_INT
: set
->func
->handler
= psi_to_int
; break;
130 case PSI_T_TO_FLOAT
: set
->func
->handler
= psi_to_double
; break;
131 case PSI_T_TO_STRING
: set
->func
->handler
= psi_to_string
; break;
132 case PSI_T_TO_ARRAY
: set
->func
->handler
= psi_to_array
; break;
133 case PSI_T_TO_OBJECT
: set
->func
->handler
= psi_to_object
; break;
134 case PSI_T_VOID
: set
->func
->handler
= psi_to_void
; break;
135 case PSI_T_ZVAL
: set
->func
->handler
= psi_to_zval
; break;
137 if (set
->outer
.set
&& set
->outer
.set
->func
->type
== PSI_T_TO_ARRAY
) {
138 set
->func
->handler
= psi_to_recursive
;
139 set
->inner
= set
->outer
.set
->inner
;
149 int validate_set_value(struct psi_data
*data
, set_value
*set
, ...) {
151 decl_args args
= {0};
155 decl_var_arg_v(&args
, argp
);
158 check
= validate_set_value_ex(data
, set
, NULL
, &args
);
165 int validate_set_value_ex(struct psi_data
*data
, set_value
*set
, decl_arg
*ref
, decl_args
*ref_list
) {
168 decl_var
*set_var
= set
->vars
->vars
[0];
170 if (!validate_set_value_handler(set
)) {
171 data
->error(data
, set
->func
->token
, PSI_WARNING
, "Invalid cast '%s' in `set` statement", set
->func
->name
);
175 for (i
= 0; i
< set
->vars
->count
; ++i
) {
176 decl_var
*svar
= set
->vars
->vars
[i
];
177 if (!svar
->arg
&& !locate_decl_var_arg(svar
, ref_list
, NULL
)) {
178 data
->error(data
, svar
->token
, PSI_WARNING
, "Unknown variable '%s' in `set` statement", svar
->name
);
186 ref_type
= real_decl_type(ref
->type
);
188 if (set
->inner
&& set
->inner
->count
) {
189 int is_to_array
= (set
->func
->type
== PSI_T_TO_ARRAY
);
190 int is_pointer_to_struct
= (ref_type
->type
== PSI_T_STRUCT
&& ref
->var
->pointer_level
);
192 if (!is_to_array
&& !is_pointer_to_struct
) {
193 data
->error(data
, set
->func
->token
, E_WARNING
, "Inner `set` statement casts only work with "
194 "to_array() casts on structs or pointers: %s(%s...", set
->func
->name
, set
->vars
->vars
[0]->name
);
199 if (!validate_num_exp(data
, set
->num
, ref_list
, ref
, NULL
)) {
204 if (set
->inner
&& (ref_type
->type
== PSI_T_STRUCT
|| ref_type
->type
== PSI_T_UNION
)) {
205 /* to_array(struct, to_...) */
206 if (!set
->outer
.set
|| set
->outer
.set
->inner
->vals
!= set
->inner
->vals
) {
207 for (i
= 0; i
< set
->inner
->count
; ++i
) {
208 decl_var
*sub_var
= set
->inner
->vals
[i
]->vars
->vars
[0];
211 switch (ref_type
->type
) {
213 sub_ref
= locate_decl_struct_member(ref_type
->real
.strct
, sub_var
);
216 sub_ref
= locate_decl_union_member(ref_type
->real
.unn
, sub_var
);
221 if (!validate_set_value_ex(data
, set
->inner
->vals
[i
], sub_ref
, ref_type
->real
.strct
->args
)) {
227 } else if (set
->inner
&& set
->inner
->count
== 1) {
228 /* to_array(ptr, to_string(*ptr)) */
229 decl_var
*sub_var
= set
->inner
->vals
[0]->vars
->vars
[0];
230 decl_arg
*sub_ref
= locate_decl_var_arg(sub_var
, ref_list
, ref
);
233 if (strcmp(sub_var
->name
, set_var
->name
)) {
234 data
->error(data
, sub_var
->token
, E_WARNING
, "Inner `set` statement casts on pointers must reference the same variable");
237 if (!validate_set_value_ex(data
, set
->inner
->vals
[0], sub_ref
, ref_list
)) {
241 } else if (set
->inner
&& set
->inner
->count
> 1) {
242 data
->error(data
, set
->func
->token
, E_WARNING
,
243 "Inner `set` statement casts on pointers may only occur once, "
244 "unless the outer type is a struct or union, got '%s%s'",
245 ref_type
->name
, psi_t_indirection(ref
->var
->pointer_level
));