Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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);
}