Clownfish-CFC

 view release on metacpan or  search on metacpan

src/CFCUtil.c  view on Meta::CPAN

}

void
CFCUtil_wrapped_free(void *ptr) {
    free(ptr);
}

// Avoid -Wtype-limits warning.
#if CHAR_MAX <= 127
  #define IS_ASCII(c) ((c) >= 0)
#else
  #define IS_ASCII(c) ((c) >= 0 && (c) <= 127)
#endif

int
CFCUtil_isalnum(char c) {
    return IS_ASCII(c) && isalnum(c);
}

int
CFCUtil_isalpha(char c) {
    return IS_ASCII(c) && isalpha(c);
}

int
CFCUtil_isdigit(char c) {
    return IS_ASCII(c) && isdigit(c);
}

int
CFCUtil_islower(char c) {
    return IS_ASCII(c) && islower(c);
}

int
CFCUtil_isspace(char c) {
    return IS_ASCII(c) && isspace(c);
}

int
CFCUtil_isupper(char c) {
    return IS_ASCII(c) && isupper(c);
}

char
CFCUtil_tolower(char c) {
    if (!IS_ASCII(c)) { return c; }
    return (char)tolower(c);
}

char
CFCUtil_toupper(char c) {
    if (!IS_ASCII(c)) { return c; }
    return (char)toupper(c);
}

int
CFCUtil_current(const char *orig, const char *dest) {
    // If the destination file doesn't exist, we're not current.
    struct stat dest_stat;
    if (stat(dest, &dest_stat) == -1) {
        return false;
    }

    // If the source file is newer than the dest, we're not current.
    struct stat orig_stat;
    if (stat(orig, &orig_stat) == -1) {
        CFCUtil_die("Missing source file '%s': %s", orig, strerror(errno));
    }
    if (orig_stat.st_mtime > dest_stat.st_mtime) {
        return false;
    }

    // Current!
    return 1;
}

void
CFCUtil_write_file(const char *filename, const char *content, size_t len) {
    const char *last_sep = strrchr(filename, CHY_DIR_SEP_CHAR);
    if (last_sep != NULL && last_sep != filename) {
        char *dir = CFCUtil_strndup(filename, last_sep - filename);
        if (!CFCUtil_is_dir(dir) && !CFCUtil_make_path(dir)) {
            CFCUtil_die("Couldn't create directory '%s'", dir);
        }
        FREEMEM(dir);
    }

    FILE *fh = fopen(filename, "w+");
    if (fh == NULL) {
        CFCUtil_die("Couldn't open '%s': %s", filename, strerror(errno));
    }
    fwrite(content, sizeof(char), len, fh);
    if (fclose(fh)) {
        CFCUtil_die("Error when closing '%s': %s", filename, strerror(errno));
    }
}

char*
CFCUtil_slurp_text(const char *file_path, size_t *len_ptr) {
    FILE   *const file = fopen(file_path, "r");
    char   *contents;
    size_t  binary_len;
    size_t  text_len;

    /* Sanity check. */
    if (file == NULL) {
        CFCUtil_die("Error opening file '%s': %s", file_path, strerror(errno));
    }

    /* Find length; return NULL if the file has a zero-length. */
    binary_len = (size_t)CFCUtil_flength(file);
    if (binary_len == 0) {
        *len_ptr = 0;
        return NULL;
    }

    /* Allocate memory and read the file. */
    contents = (char*)MALLOCATE(binary_len * sizeof(char) + 1);
    text_len = fread(contents, sizeof(char), binary_len, file);

    /* Weak error check, because CRLF might result in fewer chars read. */
    if (text_len <= 0) {
        CFCUtil_die("Tried to read %ld bytes of '%s', got return code %ld",
                    (long)binary_len, file_path, (long)text_len);
    }

    /* NULL-terminate. */
    contents[text_len] = '\0';

    /* Set length pointer for benefit of caller. */
    *len_ptr = text_len;

    /* Clean up. */
    if (fclose(file)) {
        CFCUtil_die("Error closing file '%s': %s", file_path, strerror(errno));
    }

    return contents;
}

int
CFCUtil_write_if_changed(const char *path, const char *content, size_t len) {
    FILE *f = fopen(path, "r");
    if (f) { // Does file exist?
        if (fclose(f)) {
            CFCUtil_die("Error closing file '%s': %s", path, strerror(errno));
        }
        size_t existing_len;
        char *existing = CFCUtil_slurp_text(path, &existing_len);
        int changed = true;
        if (existing_len == len && strcmp(content, existing) == 0) {
            changed = false;
        }
        FREEMEM(existing);
        if (changed == false) {
            return false;
        }
    }
    CFCUtil_write_file(path, content, len);
    return true;
}

long
CFCUtil_flength(void *file) {
    FILE *f = (FILE*)file;
    const long bookmark = (long)ftell(f);
    long check_val;
    long len;

    /* Seek to end of file and check length. */
    check_val = fseek(f, 0, SEEK_END);
    if (check_val == -1) { CFCUtil_die("fseek error : %s\n", strerror(errno)); }
    len = (long)ftell(f);
    if (len == -1) { CFCUtil_die("ftell error : %s\n", strerror(errno)); }

    /* Return to where we were. */
    check_val = fseek(f, bookmark, SEEK_SET);
    if (check_val == -1) { CFCUtil_die("fseek error : %s\n", strerror(errno)); }

    return len;
}

// Note: this has to be defined before including the Perl headers because they
// redefine stat() in an incompatible way on certain systems (Windows).
int
CFCUtil_is_dir(const char *path) {
    struct stat stat_buf;
    int stat_check = stat(path, &stat_buf);
    if (stat_check == -1) {
        return false;
    }
    return (stat_buf.st_mode & S_IFDIR) ? true : false;
}

int
CFCUtil_make_path(const char *path) {
    CFCUTIL_NULL_CHECK(path);
    char *target = CFCUtil_strdup(path);
    size_t orig_len = strlen(target);
    size_t len = orig_len;
    for (size_t i = 0; i <= len; i++) {
        if (target[i] == CHY_DIR_SEP_CHAR || i == len) {
            target[i] = 0; // NULL-terminate.
            struct stat stat_buf;
            int stat_check = stat(target, &stat_buf);
            if (stat_check != -1) {
                if (!(stat_buf.st_mode & S_IFDIR)) {
                    CFCUtil_die("%s isn't a directory", target);
                }
            }
            else {
                int success = CFCUtil_make_dir(target);
                if (!success) {
                    FREEMEM(target);
                    return false;
                }
            }
            target[i] = CHY_DIR_SEP_CHAR;
        }
    }

    FREEMEM(target);
    return true;
}

void
CFCUtil_walk(const char *path, CFCUtil_walk_callback_t callback,
             void *context) {
    // If it's a valid file system entry, invoke the callback.
    struct stat stat_buf;
    int stat_check = stat(path, &stat_buf);
    if (stat_check == -1) {
        return;
    }
    callback(path, context);

    // Recurse into directories.
    if (!(stat_buf.st_mode & S_IFDIR)) {
        return;
    }
    void   *dirhandle = CFCUtil_opendir(path);
    const char *entry = NULL;
    while (NULL != (entry = CFCUtil_dirnext(dirhandle))) {
        if (strcmp(entry, ".") == 0 || strcmp(entry, "..") == 0) {
            continue;
        }
        char *subpath = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s", path, entry);
        CFCUtil_walk(subpath, callback, context);
        FREEMEM(subpath);
    }
    CFCUtil_closedir(dirhandle, path);
}

void
CFCUtil_free_string_array(char **strings) {
    if (strings == NULL) { return; }

    for (size_t i = 0; strings[i] != NULL; i++) {
        FREEMEM(strings[i]);
    }
    FREEMEM(strings);
}

int
CFCUtil_make_dir(const char *dir) {
    return !chy_makedir(dir, 0777);
}

/******************************** WINDOWS **********************************/
#if (defined(CHY_HAS_WINDOWS_H) && !defined(__CYGWIN__))

#include <windows.h>

typedef struct WinDH {
    HANDLE handle;
    WIN32_FIND_DATA *find_data;
    char path[MAX_PATH + 1];
    int first_time;
} WinDH;

void*
CFCUtil_opendir(const char *dir) {
    size_t dirlen = strlen(dir);
    if (dirlen >= MAX_PATH - 2) {
        CFCUtil_die("Exceeded MAX_PATH(%d): %s", (int)MAX_PATH, dir);
    }
    WinDH *dh = (WinDH*)CALLOCATE(1, sizeof(WinDH));
    dh->find_data = (WIN32_FIND_DATA*)MALLOCATE(sizeof(WIN32_FIND_DATA));

    // Tack on wildcard needed by FindFirstFile.
    sprintf(dh->path, "%s\\*", dir);



( run in 1.229 second using v1.01-cache-2.11-cpan-39bf76dae61 )