types: missing 'long double' in psi_t_size() and psi_t_alignment()
[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
247 /* fail early if library is not found */
248 if (!psi_decl_file_validate(dst, src, &dlopened)) {
249 return false;
250 }
251
252 dst->flags |= PSI_SILENT;
253
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
264 + count_enums;
265
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;
271 check_count = ~0;
272
273 PSI_DEBUG_PRINT(dst, "PSI: validation bail out with %zu"
274 " type checks remaining, errors follow\n", count_all);
275 continue;
276 }
277 check_count = 0;
278 } else {
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;
283
284 check_count = count_all;
285 src->errors = errors + check_count;
286
287 PSI_DEBUG_PRINT(dst, "PSI: validate data(%p) %zu type checks remaining\n",
288 src, check_count);
289
290 if (count_types) {
291 size_t i = 0;
292 struct psi_decl_arg *def;
293
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);
300 } else {
301 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
302 recheck_types = psi_plist_add(recheck_types, &def);
303 }
304 }
305 }
306 if (count_structs) {
307 size_t i = 0;
308 struct psi_decl_struct *str;
309
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);
316 } else {
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);
320 }
321 }
322 }
323 if (count_unions) {
324 size_t i = 0;
325 struct psi_decl_union *unn;
326
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);
333
334 } else {
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);
338 }
339 }
340 }
341 if (count_enums) {
342 size_t i = 0;
343 struct psi_decl_enum *enm;
344
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);
351 } else {
352 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
353 recheck_enums = psi_plist_add(recheck_enums, &enm);
354 }
355 }
356 }
357 }
358
359 if (check_types && check_types != src->types) {
360 psi_plist_free(check_types);
361 }
362 check_types = recheck_types;
363 if (check_structs && check_structs != src->structs) {
364 psi_plist_free(check_structs);
365 }
366 check_structs = recheck_structs;
367 if (check_unions && check_unions != src->unions) {
368 psi_plist_free(check_unions);
369 }
370 check_unions = recheck_unions;
371 if (check_enums && check_enums != src->enums) {
372 psi_plist_free(check_enums);
373 }
374 check_enums = recheck_enums;
375 }
376
377 /* reset original flags */
378 dst->flags = flags;
379
380 if (src->consts) {
381 size_t i = 0;
382 struct psi_const *cnst;
383
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);
390 } else {
391 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
392 ++src->errors;
393 }
394 }
395 }
396
397 if (src->decls) {
398 size_t i = 0;
399 struct psi_decl *decl;
400
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);
407 } else {
408 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
409 ++src->errors;
410 }
411 }
412 }
413
414 if (src->impls) {
415 size_t i = 0;
416 struct psi_impl *impl;
417
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);
424 } else {
425 PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
426 ++src->errors;
427 }
428 }
429 }
430
431 return true;
432 }
433