+ psi_plist_free(data->impls);
+ }
+ if (data->libs) {
+ psi_plist_free(data->libs);
+ }
+
+ psi_decl_file_dtor(&data->file);
+}
+
+void psi_data_dump(int fd, struct psi_data *D)
+{
+ if (D->file.fn) {
+ dprintf(fd, "// filename=%s (%u errors)\n", D->file.fn, D->errors);
+ if (D->file.ln) {
+ dprintf(fd, "lib \"%s\";\n", D->file.ln);
+ }
+ } else {
+ dprintf(fd, "// builtin predef\n");
+ }
+ if (psi_plist_count(D->types)) {
+ size_t i = 0;
+ struct psi_decl_arg *def;
+
+ while (psi_plist_get(D->types, i++, &def)) {
+ dprintf(fd, "typedef ");
+ psi_decl_arg_dump(fd, def, 0);
+ dprintf(fd, ";\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->unions)) {
+ size_t i = 0;
+ struct psi_decl_union *unn;
+
+ while (psi_plist_get(D->unions, i++, &unn)) {
+ if (!psi_decl_type_is_anon(unn->name, "union")) {
+ psi_decl_union_dump(fd, unn);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->structs)) {
+ size_t i = 0;
+ struct psi_decl_struct *strct;
+
+ while (psi_plist_get(D->structs, i++, &strct)) {
+ if (!psi_decl_type_is_anon(strct->name, "struct")) {
+ psi_decl_struct_dump(fd, strct);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->enums)) {
+ size_t i = 0;
+ struct psi_decl_enum *enm;
+
+ while (psi_plist_get(D->enums, i++, &enm)) {
+ if (!psi_decl_type_is_anon(enm->name, "enum")) {
+ psi_decl_enum_dump(fd, enm, 0);
+ dprintf(fd, "\n");
+ }
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->consts)) {
+ size_t i = 0;
+ struct psi_const *c;
+
+ while (psi_plist_get(D->consts, i++, &c)) {
+ psi_const_dump(fd, c);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->decls)) {
+ size_t i = 0;
+ struct psi_decl *decl;
+
+ while (psi_plist_get(D->decls, i++, &decl)) {
+ psi_decl_dump(fd, decl);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+ if (psi_plist_count(D->impls)) {
+ size_t i = 0;
+ struct psi_impl *impl;
+
+ while (psi_plist_get(D->impls, i++, &impl)) {
+ psi_impl_dump(fd, impl);
+ dprintf(fd, "\n");
+ }
+ dprintf(fd, "\n");
+ }
+}
+
+bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
+{
+ void *dlopened = NULL;
+ size_t check_count = ~0;
+ struct psi_plist *check_types = src->types;
+ struct psi_plist *check_structs = src->structs;
+ struct psi_plist *check_unions = src->unions;
+ struct psi_plist *check_enums = src->enums;
+ struct psi_plist *check_decls = src->decls;
+ unsigned flags = dst->flags;
+ unsigned errors = src->errors;
+ struct psi_validate_stack type_stack;
+
+ /* fail early if library is not found */
+ if (!psi_decl_file_validate(dst, src, &dlopened)) {
+ return false;
+ }
+
+ psi_validate_stack_ctor(&type_stack);
+
+ dst->flags |= PSI_SILENT;
+
+ while (check_count) {
+ struct psi_plist *recheck_types;
+ struct psi_plist *recheck_structs;
+ struct psi_plist *recheck_unions;
+ struct psi_plist *recheck_enums;
+ struct psi_plist *recheck_decls;
+ size_t count_types = psi_plist_count(check_types);
+ size_t count_structs = psi_plist_count(check_structs);
+ size_t count_unions = psi_plist_count(check_unions);
+ size_t count_enums = psi_plist_count(check_enums);
+ size_t count_decls = psi_plist_count(check_decls);
+ size_t count_all = count_types + count_structs + count_unions
+ + count_enums + count_decls;
+
+ if (check_count == count_all) {
+ /* nothing changed; bail out */
+ if (count_all && (dst->flags & PSI_SILENT) && !(flags & PSI_SILENT)) {
+ /* one last error-spitting round, if not explicitly suppressed */
+ dst->flags ^= PSI_SILENT;
+ check_count = ~0;
+
+ PSI_DEBUG_PRINT(dst, "PSI: validation bail out with %zu"
+ " type checks remaining, errors follow\n", count_all);
+ continue;
+ }
+ check_count = 0;
+ } else {
+ recheck_types = count_types ? psi_plist_init(NULL) : NULL;
+ recheck_structs = count_structs ? psi_plist_init(NULL) : NULL;
+ recheck_unions = count_unions ? psi_plist_init(NULL) : NULL;
+ recheck_enums = count_enums ? psi_plist_init(NULL) : NULL;
+ recheck_decls = count_decls ? psi_plist_init(NULL) : NULL;
+
+ check_count = count_all;
+ src->errors = errors + check_count;
+
+ PSI_DEBUG_PRINT(dst, "PSI: validate data(%p) %zu type checks remaining\n",
+ src, check_count);
+
+ if (count_types) {
+ size_t i = 0;
+ struct psi_decl_arg *def;
+
+ while (psi_plist_get(check_types, i++, &def)) {
+ *dst->last_error = 0;
+ dst->types = psi_plist_add(dst->types, &def);
+ PSI_DEBUG_PRINT(dst, "PSI: validate typedef %s ", def->var->name);
+ if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def, &type_stack)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_types = psi_plist_add(recheck_types, &def);
+ psi_plist_pop(dst->types, NULL);
+ }
+ }
+ }
+ if (count_structs) {
+ size_t i = 0;
+ struct psi_decl_struct *str;
+
+ while (psi_plist_get(check_structs, i++, &str)) {
+ *dst->last_error = 0;
+ dst->structs = psi_plist_add(dst->structs, &str);
+ PSI_DEBUG_PRINT(dst, "PSI: validate struct %s ", str->name);
+ if (psi_decl_struct_validate(PSI_DATA(dst), str, &type_stack)) {
+ PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", str->align, str->size);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_structs = psi_plist_add(recheck_structs, &str);
+ psi_plist_pop(dst->structs, NULL);
+ }
+ }
+ }
+ if (count_unions) {
+ size_t i = 0;
+ struct psi_decl_union *unn;
+
+ while (psi_plist_get(check_unions, i++, &unn)) {
+ *dst->last_error = 0;
+ dst->unions = psi_plist_add(dst->unions, &unn);
+ PSI_DEBUG_PRINT(dst, "PSI: validate union %s ", unn->name);
+ if (psi_decl_union_validate(PSI_DATA(dst), unn, &type_stack)) {
+ PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", unn->align, unn->size);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_unions = psi_plist_add(recheck_unions, &unn);
+ psi_plist_pop(dst->unions, NULL);
+ }
+ }
+ }
+ if (count_enums) {
+ size_t i = 0;
+ struct psi_decl_enum *enm;
+
+ while (psi_plist_get(check_enums, i++, &enm)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate enum %s ", enm->name);
+ if (psi_decl_enum_validate(PSI_DATA(dst), enm)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->enums = psi_plist_add(dst->enums, &enm);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_enums = psi_plist_add(recheck_enums, &enm);
+ }
+ }
+ }
+ if (count_decls) {
+ size_t i = 0;
+ struct psi_decl *decl;
+
+ while (psi_plist_get(check_decls, i++, &decl)) {
+ *dst->last_error = 0;
+ PSI_DEBUG_PRINT(dst, "PSI: validate decl %s ", decl->func->var->name);
+ if (psi_decl_validate(PSI_DATA(dst), decl, dlopened, &type_stack)) {
+ PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+ dst->decls = psi_plist_add(dst->decls, &decl);
+ } else {
+ PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+ recheck_decls = psi_plist_add(recheck_decls, &decl);
+ }
+ }
+ }
+ }
+
+ if (check_types && check_types != src->types) {
+ psi_plist_free(check_types);
+ }
+ check_types = recheck_types;
+ if (check_structs && check_structs != src->structs) {
+ psi_plist_free(check_structs);
+ }
+ check_structs = recheck_structs;
+ if (check_unions && check_unions != src->unions) {
+ psi_plist_free(check_unions);
+ }
+ check_unions = recheck_unions;
+ if (check_enums && check_enums != src->enums) {
+ psi_plist_free(check_enums);
+ }
+ check_enums = recheck_enums;
+ if (check_decls && check_decls != src->decls) {
+ psi_plist_free(check_decls);
+ }
+ check_decls = recheck_decls;