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"
29 #include "php_globals.h"
33 struct psi_data
*psi_data_ctor_with_dtors(struct psi_data
*data
,
34 psi_error_cb error
, unsigned flags
)
37 data
= calloc(1, sizeof(*data
));
44 data
->consts
= psi_plist_init((psi_plist_dtor
) psi_const_free
);
47 data
->types
= psi_plist_init((psi_plist_dtor
) psi_decl_arg_free
);
50 data
->structs
= psi_plist_init((psi_plist_dtor
) psi_decl_struct_free
);
53 data
->unions
= psi_plist_init((psi_plist_dtor
) psi_decl_union_free
);
56 data
->enums
= psi_plist_init((psi_plist_dtor
) psi_decl_enum_free
);
59 data
->decls
= psi_plist_init((psi_plist_dtor
) psi_decl_free
);
62 data
->impls
= psi_plist_init((psi_plist_dtor
) psi_impl_free
);
65 data
->libs
= psi_plist_init((psi_plist_dtor
) psi_libs_free
);
70 struct psi_data
*psi_data_ctor(struct psi_data
*data
, psi_error_cb error
,
74 data
= calloc(1, sizeof(*data
));
81 data
->consts
= psi_plist_init(NULL
);
84 data
->types
= psi_plist_init(NULL
);
87 data
->structs
= psi_plist_init(NULL
);
90 data
->unions
= psi_plist_init(NULL
);
93 data
->enums
= psi_plist_init(NULL
);
96 data
->decls
= psi_plist_init(NULL
);
99 data
->impls
= psi_plist_init(NULL
);
102 data
->libs
= psi_plist_init(NULL
);
107 struct psi_data
*psi_data_exchange(struct psi_data
*dest
, struct psi_data
*src
)
110 dest
= malloc(sizeof(*dest
));
113 memset(src
, 0, sizeof(*src
));
117 void psi_data_dtor(struct psi_data
*data
)
120 psi_plist_free(data
->consts
);
123 psi_plist_free(data
->types
);
126 psi_plist_free(data
->structs
);
129 psi_plist_free(data
->unions
);
132 psi_plist_free(data
->enums
);
135 psi_plist_free(data
->decls
);
138 psi_plist_free(data
->impls
);
141 psi_plist_free(data
->libs
);
144 psi_decl_file_dtor(&data
->file
);
147 void psi_data_dump(int fd
, struct psi_data
*D
)
150 dprintf(fd
, "// filename=%s (%u errors)\n", D
->file
.fn
, D
->errors
);
152 dprintf(fd
, "lib \"%s\";\n", D
->file
.ln
);
155 dprintf(fd
, "// builtin predef\n");
157 if (psi_plist_count(D
->types
)) {
159 struct psi_decl_arg
*def
;
161 while (psi_plist_get(D
->types
, i
++, &def
)) {
162 dprintf(fd
, "typedef ");
163 psi_decl_arg_dump(fd
, def
, 0);
168 if (psi_plist_count(D
->unions
)) {
170 struct psi_decl_union
*unn
;
172 while (psi_plist_get(D
->unions
, i
++, &unn
)) {
173 if (!psi_decl_type_is_anon(unn
->name
, "union")) {
174 psi_decl_union_dump(fd
, unn
);
180 if (psi_plist_count(D
->structs
)) {
182 struct psi_decl_struct
*strct
;
184 while (psi_plist_get(D
->structs
, i
++, &strct
)) {
185 if (!psi_decl_type_is_anon(strct
->name
, "struct")) {
186 psi_decl_struct_dump(fd
, strct
);
192 if (psi_plist_count(D
->enums
)) {
194 struct psi_decl_enum
*enm
;
196 while (psi_plist_get(D
->enums
, i
++, &enm
)) {
197 if (!psi_decl_type_is_anon(enm
->name
, "enum")) {
198 psi_decl_enum_dump(fd
, enm
, 0);
204 if (psi_plist_count(D
->consts
)) {
208 while (psi_plist_get(D
->consts
, i
++, &c
)) {
209 psi_const_dump(fd
, c
);
214 if (psi_plist_count(D
->decls
)) {
216 struct psi_decl
*decl
;
218 while (psi_plist_get(D
->decls
, i
++, &decl
)) {
219 psi_decl_dump(fd
, decl
);
224 if (psi_plist_count(D
->impls
)) {
226 struct psi_impl
*impl
;
228 while (psi_plist_get(D
->impls
, i
++, &impl
)) {
229 psi_impl_dump(fd
, impl
);
236 bool psi_data_validate(struct psi_data
*dst
, struct psi_data
*src
)
238 void *dlopened
= NULL
;
239 size_t check_count
= ~0;
240 struct psi_plist
*check_types
= src
->types
;
241 struct psi_plist
*check_structs
= src
->structs
;
242 struct psi_plist
*check_unions
= src
->unions
;
243 struct psi_plist
*check_enums
= src
->enums
;
244 unsigned flags
= dst
->flags
;
245 unsigned errors
= src
->errors
;
246 struct psi_validate_stack type_stack
;
248 /* fail early if library is not found */
249 if (!psi_decl_file_validate(dst
, src
, &dlopened
)) {
253 psi_validate_stack_ctor(&type_stack
);
255 dst
->flags
|= PSI_SILENT
;
257 while (check_count
) {
258 struct psi_plist
*recheck_types
;
259 struct psi_plist
*recheck_structs
;
260 struct psi_plist
*recheck_unions
;
261 struct psi_plist
*recheck_enums
;
262 size_t count_types
= psi_plist_count(check_types
);
263 size_t count_structs
= psi_plist_count(check_structs
);
264 size_t count_unions
= psi_plist_count(check_unions
);
265 size_t count_enums
= psi_plist_count(check_enums
);
266 size_t count_all
= count_types
+ count_structs
+ count_unions
269 if (check_count
== count_all
) {
270 /* nothing changed; bail out */
271 if (count_all
&& (dst
->flags
& PSI_SILENT
) && !(flags
& PSI_SILENT
)) {
272 /* one last error-spitting round, if not explicitly suppressed */
273 dst
->flags
^= PSI_SILENT
;
276 PSI_DEBUG_PRINT(dst
, "PSI: validation bail out with %zu"
277 " type checks remaining, errors follow\n", count_all
);
282 recheck_types
= count_types
? psi_plist_init(NULL
) : NULL
;
283 recheck_structs
= count_structs
? psi_plist_init(NULL
) : NULL
;
284 recheck_unions
= count_unions
? psi_plist_init(NULL
) : NULL
;
285 recheck_enums
= count_enums
? psi_plist_init(NULL
) : NULL
;
287 check_count
= count_all
;
288 src
->errors
= errors
+ check_count
;
290 PSI_DEBUG_PRINT(dst
, "PSI: validate data(%p) %zu type checks remaining\n",
295 struct psi_decl_arg
*def
;
297 while (psi_plist_get(check_types
, i
++, &def
)) {
298 *dst
->last_error
= 0;
299 dst
->types
= psi_plist_add(dst
->types
, &def
);
300 PSI_DEBUG_PRINT(dst
, "PSI: validate typedef %s ", def
->var
->name
);
301 if (psi_decl_arg_validate_typedef(PSI_DATA(dst
), def
, &type_stack
)) {
302 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
304 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
305 recheck_types
= psi_plist_add(recheck_types
, &def
);
306 psi_plist_pop(dst
->types
, NULL
);
312 struct psi_decl_struct
*str
;
314 while (psi_plist_get(check_structs
, i
++, &str
)) {
315 *dst
->last_error
= 0;
316 dst
->structs
= psi_plist_add(dst
->structs
, &str
);
317 PSI_DEBUG_PRINT(dst
, "PSI: validate struct %s ", str
->name
);
318 if (psi_decl_struct_validate(PSI_DATA(dst
), str
, &type_stack
)) {
319 PSI_DEBUG_PRINT(dst
, "%s ::(%zu, %zu)\n", "✔", str
->align
, str
->size
);
321 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
322 recheck_structs
= psi_plist_add(recheck_structs
, &str
);
323 psi_plist_pop(dst
->structs
, NULL
);
329 struct psi_decl_union
*unn
;
331 while (psi_plist_get(check_unions
, i
++, &unn
)) {
332 *dst
->last_error
= 0;
333 dst
->unions
= psi_plist_add(dst
->unions
, &unn
);
334 PSI_DEBUG_PRINT(dst
, "PSI: validate union %s ", unn
->name
);
335 if (psi_decl_union_validate(PSI_DATA(dst
), unn
, &type_stack
)) {
336 PSI_DEBUG_PRINT(dst
, "%s ::(%zu, %zu)\n", "✔", unn
->align
, unn
->size
);
339 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
340 recheck_unions
= psi_plist_add(recheck_unions
, &unn
);
341 psi_plist_pop(dst
->unions
, NULL
);
347 struct psi_decl_enum
*enm
;
349 while (psi_plist_get(check_enums
, i
++, &enm
)) {
350 *dst
->last_error
= 0;
351 PSI_DEBUG_PRINT(dst
, "PSI: validate enum %s ", enm
->name
);
352 if (psi_decl_enum_validate(PSI_DATA(dst
), enm
)) {
353 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
354 dst
->enums
= psi_plist_add(dst
->enums
, &enm
);
356 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
357 recheck_enums
= psi_plist_add(recheck_enums
, &enm
);
363 if (check_types
&& check_types
!= src
->types
) {
364 psi_plist_free(check_types
);
366 check_types
= recheck_types
;
367 if (check_structs
&& check_structs
!= src
->structs
) {
368 psi_plist_free(check_structs
);
370 check_structs
= recheck_structs
;
371 if (check_unions
&& check_unions
!= src
->unions
) {
372 psi_plist_free(check_unions
);
374 check_unions
= recheck_unions
;
375 if (check_enums
&& check_enums
!= src
->enums
) {
376 psi_plist_free(check_enums
);
378 check_enums
= recheck_enums
;
381 /* reset original flags */
386 struct psi_const
*cnst
;
388 while (psi_plist_get(src
->consts
, i
++, &cnst
)) {
389 *dst
->last_error
= 0;
390 PSI_DEBUG_PRINT(dst
, "PSI: validate const %s ", cnst
->name
);
391 if (psi_const_validate(PSI_DATA(dst
), cnst
)) {
392 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
393 dst
->consts
= psi_plist_add(dst
->consts
, &cnst
);
395 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
403 struct psi_decl
*decl
;
405 while (psi_plist_get(src
->decls
, i
++, &decl
)) {
406 *dst
->last_error
= 0;
407 PSI_DEBUG_PRINT(dst
, "PSI: validate decl %s ", decl
->func
->var
->name
);
408 if (psi_decl_validate(PSI_DATA(dst
), decl
, dlopened
, &type_stack
)) {
409 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
410 dst
->decls
= psi_plist_add(dst
->decls
, &decl
);
412 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
420 struct psi_impl
*impl
;
422 while (psi_plist_get(src
->impls
, i
++, &impl
)) {
423 *dst
->last_error
= 0;
424 PSI_DEBUG_PRINT(dst
, "PSI: validate impl %s ", impl
->func
->name
);
425 if (psi_impl_validate(PSI_DATA(dst
), impl
)) {
426 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
427 dst
->impls
= psi_plist_add(dst
->impls
, &impl
);
429 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
435 psi_validate_stack_dtor(&type_stack
);