void CFCC_write_man_pages(CFCC *self) { CFCHierarchy *hierarchy = self->hierarchy; CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); size_t num_classes = 0; for (size_t i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (!CFCClass_included(klass)) { ++num_classes; } } char **man_pages = (char**)CALLOCATE(num_classes, sizeof(char*)); // Generate man pages, but don't write. That way, if there's an error // while generating the pages, we leak memory but don't clutter up the file // system. for (size_t i = 0, j = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_included(klass)) { continue; } char *man_page = CFCCMan_create_man_page(klass); man_pages[j++] = man_page; } const char *dest = CFCHierarchy_get_dest(hierarchy); char *man3_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "man" CHY_DIR_SEP "man3", dest); if (!CFCUtil_is_dir(man3_path)) { CFCUtil_make_path(man3_path); if (!CFCUtil_is_dir(man3_path)) { CFCUtil_die("Can't make path %s", man3_path); } } // Write out any man pages that have changed. for (size_t i = 0, j = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; if (CFCClass_included(klass)) { continue; } char *raw_man_page = man_pages[j++]; if (!raw_man_page) { continue; } char *man_page = CFCUtil_sprintf("%s%s%s", self->man_header, raw_man_page, self->man_footer); const char *full_struct_sym = CFCClass_full_struct_sym(klass); char *filename = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.3", man3_path, full_struct_sym); CFCUtil_write_if_changed(filename, man_page, strlen(man_page)); FREEMEM(filename); FREEMEM(man_page); FREEMEM(raw_man_page); } FREEMEM(man3_path); FREEMEM(man_pages); FREEMEM(ordered); }
static void S_find_prereq(CFCHierarchy *self, CFCParcel *parent, CFCPrereq *prereq) { const char *name = CFCPrereq_get_name(prereq); CFCVersion *min_version = CFCPrereq_get_version(prereq); // Check whether prereq was processed already. CFCParcel **parcels = CFCParcel_all_parcels(); for (int i = 0; parcels[i]; ++i) { CFCParcel *parcel = parcels[i]; const char *other_name = CFCParcel_get_name(parcel); if (strcmp(other_name, name) == 0) { CFCVersion *other_version = CFCParcel_get_version(parcel); CFCVersion *major_version = CFCParcel_get_major_version(parcel); if (CFCVersion_compare_to(major_version, min_version) <= 0 && CFCVersion_compare_to(min_version, other_version) <= 0 ) { // Compatible version found. return; } else { CFCUtil_die("Parcel %s %s required by %s not compatible with" " version %s required by %s", name, other_version, "[TODO]", CFCVersion_get_vstring(min_version), CFCParcel_get_name(parent)); } } } CFCParcel *parcel = NULL; // TODO: Decide whether to prefer higher versions from directories // that come later in the list of include dirs or stop processing once // a suitable version was found in a dir. for (size_t i = 0; self->includes[i] != NULL; i++) { char *name_dir = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", self->includes[i], name); if (CFCUtil_is_dir(name_dir)) { void *dirhandle = CFCUtil_opendir(name_dir); const char *entry = NULL; while (NULL != (entry = CFCUtil_dirnext(dirhandle))) { if (!CFCVersion_is_vstring(entry)) { continue; } char *version_dir = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", name_dir, entry); if (CFCUtil_is_dir(version_dir)) { parcel = S_audition_parcel(version_dir, entry, min_version, parcel); } FREEMEM(version_dir); } CFCUtil_closedir(dirhandle, name_dir); } FREEMEM(name_dir); } if (parcel == NULL) { CFCUtil_die("Parcel %s %s required by %s not found", name, CFCVersion_get_vstring(min_version), CFCParcel_get_name(parent)); } // Make sure to register prereq parcels first, so that prereq // parent classes precede subclasses. S_find_prereqs(self, parcel); CFCParcel_register(parcel); CFCBase_decref((CFCBase*)parcel); }
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); }