/* filepath.c * * Copyright (c) 2014-2017 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 = xmalloc(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 ""; } /* Returns a pointer to a relative path to `path` from `start`. This pointer may be pointing to either of it's arguments, or to the statically allocated string "." should both paths match. Both paths must be canonicalized. A few examples: relpath("/abc/de", "/abc/de") => "." relpath("some/path/a/b/c", "some/path") => "a/b/c" relpath("some/path", "some/path/a/b/c") => "some/path/a/b/c" relpath("/", "/") => "." relpath("/abc", "/") => "abc" */ char *relpath(char *path, char *start) { int i; for (i = 0; path[i] && start[i]; ++i) { if (path[i] != start[i]) return path; /* paths share nothing */ } if (!path[i] && start[i]) return start; /* path is above start */ if (!path[i] && !start[i]) return "."; /* paths match completely */ if (path[i] == '/') ++i; return &path[i]; } /* 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("redo: failed to aquire stat() information about %s", fn); return -1; } return st.st_size; } /* Create the target directory recursively much like `mkdir -p` */ void mkpath(char *path, mode_t mode) { assert(path && *path); char *p; for (p=strchr(path+1, '/'); p; p=strchr(p+1, '/')) { *p = '\0'; if (mkdir(path, mode) == -1 && errno != EEXIST) fatal("redo: failed to mkdir() '%s'", path); *p = '/'; } } /* Make path absolute by prepending root, if path isn't already absolute. */ char *make_abs(char *root, char *path) { if (!is_absolute(path)) return concat(3, root, "/", path); else return xstrdup(path); }