static void S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { CFCHierarchy *hierarchy = self->hierarchy; const char *prefix = CFCParcel_get_prefix(parcel); // Aggregate C code for the parcel. char *privacy_syms = CFCUtil_strdup(""); char *includes = CFCUtil_strdup(""); char *c_data = CFCUtil_strdup(""); CFCBindSpecs *specs = CFCBindSpecs_new(); CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); for (int i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; const char *class_prefix = CFCClass_get_prefix(klass); if (strcmp(class_prefix, prefix) != 0) { continue; } const char *include_h = CFCClass_include_h(klass); includes = CFCUtil_cat(includes, "#include \"", include_h, "\"\n", NULL); CFCBindClass *class_binding = CFCBindClass_new(klass); char *class_c_data = CFCBindClass_to_c_data(class_binding); c_data = CFCUtil_cat(c_data, class_c_data, "\n", NULL); FREEMEM(class_c_data); CFCBindSpecs_add_class(specs, klass); const char *privacy_sym = CFCClass_privacy_symbol(klass); privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym, "\n", NULL); CFCBase_decref((CFCBase*)class_binding); } char *spec_defs = CFCBindSpecs_defs(specs); char *spec_init_func = CFCBindSpecs_init_func_def(specs); FREEMEM(ordered); // Bootstrapping code for prerequisite parcels. // // bootstrap_inheritance() first calls bootstrap_inheritance() for all // parcels from which classes are inherited. Then the Classes of the parcel // are initialized. It aborts on recursive invocation. // // bootstrap_parcel() first calls bootstrap_inheritance() of its own // parcel. Then it calls bootstrap_parcel() for all prerequisite parcels. // Finally, it calls init_parcel(). Recursive invocation is allowed. char *inh_bootstrap = CFCUtil_strdup(""); char *prereq_bootstrap = CFCUtil_strdup(""); CFCParcel **inh_parcels = CFCParcel_inherited_parcels(parcel); for (size_t i = 0; inh_parcels[i]; ++i) { const char *inh_prefix = CFCParcel_get_prefix(inh_parcels[i]); inh_bootstrap = CFCUtil_cat(inh_bootstrap, " ", inh_prefix, "bootstrap_inheritance();\n", NULL); } FREEMEM(inh_parcels); CFCParcel **prereq_parcels = CFCParcel_prereq_parcels(parcel); for (size_t i = 0; prereq_parcels[i]; ++i) { const char *prereq_prefix = CFCParcel_get_prefix(prereq_parcels[i]); prereq_bootstrap = CFCUtil_cat(prereq_bootstrap, " ", prereq_prefix, "bootstrap_parcel();\n", NULL); } FREEMEM(prereq_parcels); char pattern[] = "%s\n" "\n" "#include <stdio.h>\n" "#include <stdlib.h>\n" "\n" "%s" "\n" "#include \"Clownfish/Class.h\"\n" // Needed for bootstrap. "#include \"Clownfish/Err.h\"\n" // Needed for abstract methods. "%s\n" "\n" "%s\n" "\n" "/* ClassSpec and MethSpec structs for initialization.\n" " */\n" "\n" "%s" // spec_defs "\n" "/* Code to initialize ClassSpec and MethSpec structs.\n" " */\n" "\n" "%s" // spec_init_func "\n" "static int bootstrap_state = 0;\n" "\n" "void\n" "%sbootstrap_inheritance() {\n" " if (bootstrap_state == 1) {\n" " fprintf(stderr, \"Cycle in class inheritance between\"\n" " \" parcels detected.\\n\");\n" " abort();\n" " }\n" " if (bootstrap_state >= 2) { return; }\n" " bootstrap_state = 1;\n" "%s" // Bootstrap inherited parcels. " S_bootstrap_specs();\n" " bootstrap_state = 2;\n" "}\n" "\n" "void\n" "%sbootstrap_parcel() {\n" " if (bootstrap_state >= 3) { return; }\n" " %sbootstrap_inheritance();\n" " bootstrap_state = 3;\n" "%s" // Finish bootstrapping of all prerequisite parcels. " %sinit_parcel();\n" "}\n" "\n" "%s\n"; char *file_content = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes, c_data, spec_defs, spec_init_func, prefix, inh_bootstrap, prefix, prefix, prereq_bootstrap, prefix, self->c_footer); // Unlink then open file. const char *src_dest = CFCHierarchy_get_source_dest(hierarchy); char *filepath = CFCUtil_sprintf("%s" CHY_DIR_SEP "%sparcel.c", src_dest, prefix); remove(filepath); CFCUtil_write_file(filepath, file_content, strlen(file_content)); FREEMEM(filepath); CFCBase_decref((CFCBase*)specs); FREEMEM(privacy_syms); FREEMEM(includes); FREEMEM(c_data); FREEMEM(spec_defs); FREEMEM(spec_init_func); FREEMEM(inh_bootstrap); FREEMEM(prereq_bootstrap); FREEMEM(file_content); }
void CFCBindFile_write_h(CFCFile *file, const char *dest, const char *header, const char *footer) { CFCUTIL_NULL_CHECK(file); CFCUTIL_NULL_CHECK(dest); CFCUTIL_NULL_CHECK(header); CFCUTIL_NULL_CHECK(footer); // Make directories. char *h_path = CFCFile_h_path(file, dest); char *h_dir = CFCUtil_strdup(h_path); for (size_t len = strlen(h_dir); len--;) { if (h_dir[len] == CHY_DIR_SEP_CHAR) { h_dir[len] = 0; break; } } if (!CFCUtil_is_dir(h_dir)) { CFCUtil_make_path(h_dir); if (!CFCUtil_is_dir(h_dir)) { CFCUtil_die("Can't make path %s", h_dir); } } FREEMEM(h_dir); // Create the include-guard strings. const char *include_guard_start = CFCFile_guard_start(file); const char *include_guard_close = CFCFile_guard_close(file); // Aggregate block content. char *content = CFCUtil_strdup(""); CFCBase **blocks = CFCFile_blocks(file); for (int i = 0; blocks[i] != NULL; i++) { const char *cfc_class = CFCBase_get_cfc_class(blocks[i]); if (strcmp(cfc_class, "Clownfish::CFC::Model::Parcel") == 0) { CFCParcel *parcel = (CFCParcel*)blocks[i]; const char *prefix = CFCParcel_get_prefix(parcel); content = CFCUtil_cat(content, "#include \"", prefix, "parcel.h\"\n\n", NULL); } else if (strcmp(cfc_class, "Clownfish::CFC::Model::Class") == 0) { CFCBindClass *class_binding = CFCBindClass_new((CFCClass*)blocks[i]); char *c_header = CFCBindClass_to_c_header(class_binding); content = CFCUtil_cat(content, c_header, "\n", NULL); FREEMEM(c_header); CFCBase_decref((CFCBase*)class_binding); } else if (strcmp(cfc_class, "Clownfish::CFC::Model::CBlock") == 0) { const char *block_contents = CFCCBlock_get_contents((CFCCBlock*)blocks[i]); content = CFCUtil_cat(content, block_contents, "\n", NULL); } else { CFCUtil_die("Unexpected class: %s", cfc_class); } } char pattern[] = "%s\n" "\n" "%s\n" "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" "%s\n" "\n" "#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "%s\n" "\n" "%s\n" "\n"; char *file_content = CFCUtil_sprintf(pattern, header, include_guard_start, content, include_guard_close, footer); // Unlink then write file. remove(h_path); CFCUtil_write_file(h_path, file_content, strlen(file_content)); FREEMEM(content); FREEMEM(file_content); FREEMEM(h_path); }