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
;
247 /* fail early if library is not found */
248 if (!psi_decl_file_validate(dst
, src
, &dlopened
)) {
252 dst
->flags
|= PSI_SILENT
;
254 while (check_count
) {
255 struct psi_plist
*recheck_types
;
256 struct psi_plist
*recheck_structs
;
257 struct psi_plist
*recheck_unions
;
258 struct psi_plist
*recheck_enums
;
259 size_t count_types
= psi_plist_count(check_types
);
260 size_t count_structs
= psi_plist_count(check_structs
);
261 size_t count_unions
= psi_plist_count(check_unions
);
262 size_t count_enums
= psi_plist_count(check_enums
);
263 size_t count_all
= count_types
+ count_structs
+ count_unions
266 if (check_count
== count_all
) {
267 /* nothing changed; bail out */
268 if (count_all
&& (dst
->flags
& PSI_SILENT
) && !(flags
& PSI_SILENT
)) {
269 /* one last error-spitting round, if not explicitly suppressed */
270 dst
->flags
^= PSI_SILENT
;
273 PSI_DEBUG_PRINT(dst
, "PSI: validation bail out with %zu"
274 " type checks remaining, errors follow\n", count_all
);
279 recheck_types
= count_types
? psi_plist_init(NULL
) : NULL
;
280 recheck_structs
= count_structs
? psi_plist_init(NULL
) : NULL
;
281 recheck_unions
= count_unions
? psi_plist_init(NULL
) : NULL
;
282 recheck_enums
= count_enums
? psi_plist_init(NULL
) : NULL
;
284 check_count
= count_all
;
285 src
->errors
= errors
+ check_count
;
287 PSI_DEBUG_PRINT(dst
, "PSI: validate data(%p) %zu type checks remaining\n",
292 struct psi_decl_arg
*def
;
294 while (psi_plist_get(check_types
, i
++, &def
)) {
295 *dst
->last_error
= 0;
296 PSI_DEBUG_PRINT(dst
, "PSI: validate typedef %s ", def
->var
->name
);
297 if (psi_decl_arg_validate_typedef(PSI_DATA(dst
), def
)) {
298 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
299 dst
->types
= psi_plist_add(dst
->types
, &def
);
301 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
302 recheck_types
= psi_plist_add(recheck_types
, &def
);
308 struct psi_decl_struct
*str
;
310 while (psi_plist_get(check_structs
, i
++, &str
)) {
311 *dst
->last_error
= 0;
312 dst
->structs
= psi_plist_add(dst
->structs
, &str
);
313 PSI_DEBUG_PRINT(dst
, "PSI: validate struct %s ", str
->name
);
314 if (psi_decl_struct_validate(PSI_DATA(dst
), str
)) {
315 PSI_DEBUG_PRINT(dst
, "%s ::(%zu, %zu)\n", "✔", str
->align
, str
->size
);
317 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
318 recheck_structs
= psi_plist_add(recheck_structs
, &str
);
319 psi_plist_pop(dst
->structs
, NULL
);
325 struct psi_decl_union
*unn
;
327 while (psi_plist_get(check_unions
, i
++, &unn
)) {
328 *dst
->last_error
= 0;
329 dst
->unions
= psi_plist_add(dst
->unions
, &unn
);
330 PSI_DEBUG_PRINT(dst
, "PSI: validate union %s ", unn
->name
);
331 if (psi_decl_union_validate(PSI_DATA(dst
), unn
)) {
332 PSI_DEBUG_PRINT(dst
, "%s ::(%zu, %zu)\n", "✔", unn
->align
, unn
->size
);
335 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
336 recheck_unions
= psi_plist_add(recheck_unions
, &unn
);
337 psi_plist_pop(dst
->unions
, NULL
);
343 struct psi_decl_enum
*enm
;
345 while (psi_plist_get(check_enums
, i
++, &enm
)) {
346 *dst
->last_error
= 0;
347 PSI_DEBUG_PRINT(dst
, "PSI: validate enum %s ", enm
->name
);
348 if (psi_decl_enum_validate(PSI_DATA(dst
), enm
)) {
349 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
350 dst
->enums
= psi_plist_add(dst
->enums
, &enm
);
352 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
353 recheck_enums
= psi_plist_add(recheck_enums
, &enm
);
359 if (check_types
&& check_types
!= src
->types
) {
360 psi_plist_free(check_types
);
362 check_types
= recheck_types
;
363 if (check_structs
&& check_structs
!= src
->structs
) {
364 psi_plist_free(check_structs
);
366 check_structs
= recheck_structs
;
367 if (check_unions
&& check_unions
!= src
->unions
) {
368 psi_plist_free(check_unions
);
370 check_unions
= recheck_unions
;
371 if (check_enums
&& check_enums
!= src
->enums
) {
372 psi_plist_free(check_enums
);
374 check_enums
= recheck_enums
;
377 /* reset original flags */
382 struct psi_const
*cnst
;
384 while (psi_plist_get(src
->consts
, i
++, &cnst
)) {
385 *dst
->last_error
= 0;
386 PSI_DEBUG_PRINT(dst
, "PSI: validate const %s ", cnst
->name
);
387 if (psi_const_validate(PSI_DATA(dst
), cnst
)) {
388 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
389 dst
->consts
= psi_plist_add(dst
->consts
, &cnst
);
391 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
399 struct psi_decl
*decl
;
401 while (psi_plist_get(src
->decls
, i
++, &decl
)) {
402 *dst
->last_error
= 0;
403 PSI_DEBUG_PRINT(dst
, "PSI: validate decl %s ", decl
->func
->var
->name
);
404 if (psi_decl_validate(PSI_DATA(dst
), decl
, dlopened
)) {
405 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
406 dst
->decls
= psi_plist_add(dst
->decls
, &decl
);
408 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);
416 struct psi_impl
*impl
;
418 while (psi_plist_get(src
->impls
, i
++, &impl
)) {
419 *dst
->last_error
= 0;
420 PSI_DEBUG_PRINT(dst
, "PSI: validate impl %s ", impl
->func
->name
);
421 if (psi_impl_validate(PSI_DATA(dst
), impl
)) {
422 PSI_DEBUG_PRINT(dst
, "%s\n", "✔");
423 dst
->impls
= psi_plist_add(dst
->impls
, &impl
);
425 PSI_DEBUG_PRINT(dst
, "%s (%s)\n", "✘", dst
->last_error
);