/* filepath.c * * Copyright (c) 2014 Tharre * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #include #include #include #include #include #include "util.h" #define _FILENAME "build.c" #include "dbg.h" /* Check if the given path is absolute. */ bool is_absolute(const char* path) { return path[0] == '/'; } /* Returns a new copy of str with the extension removed, where the extension is everything behind the last dot, including the dot. */ char *remove_ext(const char *str) { assert(str); size_t len; char *ret, *dot = NULL; for (len = 0; str[len]; ++len) if (str[len] == '.') dot = (char*) &str[len]; if (dot) /* recalculate length to only reach just before the last dot */ len = dot - str; ret = safe_malloc(len+1); memcpy(ret, str, len); ret[len] = '\0'; return ret; } /* Returns the extension of the target or the empty string if none was found. */ char *take_extension(const char *target) { assert(target); char *temp = strrchr(target, '.'); if (temp) return temp; else return ""; } /* Make one path relative to another i.e. some/path to some/path/a/b/c would yield a/b/c as result. Prints '.' if the 2 paths match. */ // TODO: nameing, requires absolute paths, doesn't MALLOC const char *make_relative(const char *target, const char *to) { int i; for (i = 0; target[i] && to[i]; ++i) if (target[i] != to[i]) { /* the paths do not match */ return to; } if (!target[i] && !to[i]) { /* both paths match completely */ return "."; } /* skip any leading seperators */ while (to[i] == '/') ++i; return &to[i]; } /* Transforms target into a safe filename, replacing all '/' with '!'. */ char *transform_path(const char *target) { char *ptr = (char*) target; size_t escape = 0, i = 0; while (*ptr++) if (*ptr == '!') escape++; ptr = safe_malloc((ptr-target) + escape + 1); do { if (*target == '/') ptr[i++] = '!'; else if (*target == '!') { ptr[i++] = '!'; ptr[i++] = '!'; } else ptr[i++] = *target; } while (*target++); ptr[i] = '\0'; return ptr; } /* Sane and portable basename implementation. */ char *xbasename(const char *path) { assert(path); char *ptr = strrchr(path, '/'); return ptr? ptr+1 : (char*) path; } /* Checks if target exists and prints a debug message if access() failed except if it failed with ENOENT. */ bool fexists(const char *target) { assert(target); if (!access(target, F_OK)) return true; if (errno != ENOENT) debug("Failed to access %s: %s\n", target, strerror(errno)); return false; } /* Returns the size of fn, or -1 if the file doesn't exist. */ off_t fsize(const char *fn) { struct stat st; if (stat(fn, &st)) { if (errno != ENOENT) fatal(ERRM_STAT, fn); return -1; } return st.st_size; } /* Create the directory dir, while removing other 'files' with the same name. */ void mkdirp(const char *dir) { struct stat st; if (stat(dir, &st)) { if (errno != ENOENT) fatal(ERRM_STAT, dir); if (mkdir(dir, 0755)) fatal(ERRM_MKDIR, dir); } else { if (!S_ISDIR(st.st_mode)) { if (remove(dir)) fatal(ERRM_REMOVE, dir); if (mkdir(dir, 0755)) fatal(ERRM_MKDIR, dir); } } }