marshal: allow casting from/to enum val
[m6w6/ext-psi] / src / data.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
29 #include "php_globals.h"
30
31 #include <dlfcn.h>
32
33 struct psi_data *psi_data_ctor_with_dtors(struct psi_data *data,
34 psi_error_cb error, unsigned flags)
35 {
36 if (!data) {
37 data = calloc(1, sizeof(*data));
38 }
39
40 data->error = error;
41 data->flags = flags;
42
43 if (!data->consts) {
44 data->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
45 }
46 if (!data->types) {
47 data->types = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
48 }
49 if (!data->structs) {
50 data->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
51 }
52 if (!data->unions) {
53 data->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
54 }
55 if (!data->enums) {
56 data->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
57 }
58 if (!data->decls) {
59 data->decls = psi_plist_init((psi_plist_dtor) psi_decl_free);
60 }
61 if (!data->impls) {
62 data->impls = psi_plist_init((psi_plist_dtor) psi_impl_free);
63 }
64 if (!data->libs) {
65 data->libs = psi_plist_init((psi_plist_dtor) psi_libs_free);
66 }
67 return data;
68 }
69
70 struct psi_data *psi_data_ctor(struct psi_data *data, psi_error_cb error,
71 unsigned flags)
72 {
73 if (!data) {
74 data = calloc(1, sizeof(*data));
75 }
76
77 data->error = error;
78 data->flags = flags;
79
80 if (!data->consts) {
81 data->consts = psi_plist_init(NULL);
82 }
83 if (!data->types) {
84 data->types = psi_plist_init(NULL);
85 }
86 if (!data->structs) {
87 data->structs = psi_plist_init(NULL);
88 }
89 if (!data->unions) {
90 data->unions = psi_plist_init(NULL);
91 }
92 if (!data->enums) {
93 data->enums = psi_plist_init(NULL);
94 }
95 if (!data->decls) {
96 data->decls = psi_plist_init(NULL);
97 }
98 if (!data->impls) {
99 data->impls = psi_plist_init(NULL);
100 }
101 if (!data->libs) {
102 data->libs = psi_plist_init(NULL);
103 }
104 return data;
105 }
106
107 struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src)
108 {
109 if (!dest) {
110 dest = malloc(sizeof(*dest));
111 }
112 *dest = *src;
113 memset(src, 0, sizeof(*src));
114 return dest;
115 }
116
117 void psi_data_dtor(struct psi_data *data)
118 {
119 if (data->consts) {
120 psi_plist_free(data->consts);
121 }
122 if (data->types) {
123 psi_plist_free(data->types);
124 }
125 if (data->structs) {
126 psi_plist_free(data->structs);
127 }
128 if (data->unions) {
129 psi_plist_free(data->unions);
130 }
131 if (data->enums) {
132 psi_plist_free(data->enums);
133 }
134 if (data->decls) {
135 psi_plist_free(data->decls);
136 }
137 if (data->impls) {
138 psi_plist_free(data->impls);
139 }
140 if (data->libs) {
141 psi_plist_free(data->libs);
142 }
143
144 psi_decl_file_dtor(&data->file);
145 }
146
147 void psi_data_dump(int fd, struct psi_data *D)
148 {
149 if (D->file.fn) {
150 dprintf(fd, "// filename=%s (%u errors)\n", D->file.fn, D->errors);
151 if (D->file.ln) {
152 dprintf(fd, "lib \"%s\";\n", D->file.ln);
153 }
154 } else {
155 dprintf(fd, "// builtin predef\n");
156 }
157 if (psi_plist_count(D->types)) {
158 size_t i = 0;
159 struct psi_decl_arg *def;
160
161 while (psi_plist_get(D->types, i++, &def)) {
162 dprintf(fd, "typedef ");
163 psi_decl_arg_dump(fd, def, 0);
164 dprintf(fd, ";\n");
165 }
166 dprintf(fd, "\n");
167 }
168 if (psi_plist_count(D->unions)) {
169 size_t i = 0;
170 struct psi_decl_union *unn;
171
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);
175 dprintf(fd, "\n");
176 }
177 }
178 dprintf(fd, "\n");
179 }
180 if (psi_plist_count(D->structs)) {
181 size_t i = 0;
182 struct psi_decl_struct *strct;
183
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);
187 dprintf(fd, "\n");
188 }
189 }
190 dprintf(fd, "\n");
191 }
192 if (psi_plist_count(D->enums)) {
193 size_t i = 0;
194 struct psi_decl_enum *enm;
195
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);
199 dprintf(fd, "\n");
200 }
201 }
202 dprintf(fd, "\n");
203 }
204 if (psi_plist_count(D->consts)) {
205 size_t i = 0;
206 struct psi_const *c;
207
208 while (psi_plist_get(D->consts, i++, &c)) {
209 psi_const_dump(fd, c);
210 dprintf(fd, "\n");
211 }
212 dprintf(fd, "\n");
213 }
214 if (psi_plist_count(D->decls)) {
215 size_t i = 0;
216 struct psi_decl *decl;
217
218 while (psi_plist_get(D->decls, i++, &decl)) {
219 psi_decl_dump(fd, decl);
220 dprintf(fd, "\n");
221 }
222 dprintf(fd, "\n");
223 }
224 if (psi_plist_count(D->impls)) {
225 size_t i = 0;
226 struct psi_impl *impl;
227
228 while (psi_plist_get(D->impls, i++, &impl)) {
229 psi_impl_dump(fd, impl);
230 dprintf(fd, "\n");
231 }
232 dprintf(fd, "\n");
233 }
234 }
235
236 bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
237 {
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;
247
248 /* fail early if library is not found */
249 if (!psi_decl_file_validate(dst, src, &dlopened)) {
250 return false;
251 }
252
253 psi_validate_stack_ctor(&type_stack);
254
255 dst->flags |= PSI_SILENT;
256
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
267 + count_enums;
268
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;
274 check_count = ~0;
275
276 PSI_DEBUG_PRINT(dst, "PSI: validation bail out with %zu"
277 " type checks remaining, errors follow\n", count_all);
278 continue;
279 }
280 check_count = 0;
281 } else {
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;
286
287 check_count = count_all;
288 src->errors = errors + check_count;
289
290 PSI_DEBUG_PRINT(dst, "PSI: validate data(%p) %zu type checks remaining\n",
291 src, check_count);
292
293 if (count_types) {
294 size_t i = 0;
295 struct psi_decl_arg *def;
296
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", "✔");
303 } else {
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);
307 }
308 }
309 }
310 if (count_structs) {
311 size_t i = 0;
312 struct psi_decl_struct *str;
313
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);
320 } else {
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);
324 }
325 }
326 }
327 if (count_unions) {
328 size_t i = 0;
329 struct psi_decl_union *unn;
330
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);
337
338 } else {
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);
342 }
343 }
344 }
345 if (count_enums) {
346 size_t i = 0;
347 struct psi_decl_enum *enm;
348
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);
355 } else {
356 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
357 recheck_enums = psi_plist_add(recheck_enums, &enm);
358 }
359 }
360 }
361 }
362
363 if (check_types && check_types != src->types) {
364 psi_plist_free(check_types);
365 }
366 check_types = recheck_types;
367 if (check_structs && check_structs != src->structs) {
368 psi_plist_free(check_structs);
369 }
370 check_structs = recheck_structs;
371 if (check_unions && check_unions != src->unions) {
372 psi_plist_free(check_unions);
373 }
374 check_unions = recheck_unions;
375 if (check_enums && check_enums != src->enums) {
376 psi_plist_free(check_enums);
377 }
378 check_enums = recheck_enums;
379 }
380
381 /* reset original flags */
382 dst->flags = flags;
383
384 if (src->consts) {
385 size_t i = 0;
386 struct psi_const *cnst;
387
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);
394 } else {
395 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
396 ++src->errors;
397 }
398 }
399 }
400
401 if (src->decls) {
402 size_t i = 0;
403 struct psi_decl *decl;
404
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);
411 } else {
412 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
413 ++src->errors;
414 }
415 }
416 }
417
418 if (src->impls) {
419 size_t i = 0;
420 struct psi_impl *impl;
421
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);
428 } else {
429 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
430 ++src->errors;
431 }
432 }
433 }
434
435 psi_validate_stack_dtor(&type_stack);
436
437 return true;
438 }
439