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 )