#include "path.h" #include #include #include #include #include #include extern char *realpath(const char *restrict path, char *restrict resolved_path); int ecex_path_copy(char *out, size_t out_size, const char *text) { if (!out || out_size == 0) return -1; if (!text) text = ""; size_t len = strlen(text); if (len >= out_size) { memcpy(out, text, out_size - 1); out[out_size - 1] = '\0'; return -1; } memcpy(out, text, len + 1); return 0; } char *ecex_path_expand_user(const char *path) { if (!path) return NULL; if (path[0] != '~' || (path[1] != '\0' && path[1] != '/')) { char *copy = malloc(strlen(path) + 1); if (copy) strcpy(copy, path); return copy; } const char *home = getenv("HOME"); if (!home || !home[0]) { char *copy = malloc(strlen(path) + 1); if (copy) strcpy(copy, path); return copy; } size_t home_len = strlen(home); size_t rest_len = strlen(path + 1); char *expanded = malloc(home_len + rest_len + 1); if (!expanded) return NULL; memcpy(expanded, home, home_len); memcpy(expanded + home_len, path + 1, rest_len + 1); return expanded; } char *ecex_path_join(const char *dir, const char *name) { if (!name) return NULL; if (name[0] == '/') { char *copy = malloc(strlen(name) + 1); if (copy) strcpy(copy, name); return copy; } if (!dir || !dir[0]) dir = "."; size_t dl = strlen(dir); size_t nl = strlen(name); int need_slash = dl > 0 && dir[dl - 1] != '/'; char *out = malloc(dl + (size_t)need_slash + nl + 1); if (!out) return NULL; memcpy(out, dir, dl); if (need_slash) out[dl++] = '/'; memcpy(out + dl, name, nl + 1); return out; } char *ecex_path_dirname(const char *path) { if (!path || !path[0]) { char *dot = malloc(2); if (dot) strcpy(dot, "."); return dot; } char *expanded = ecex_path_expand_user(path); if (!expanded) return NULL; size_t len = strlen(expanded); while (len > 1 && expanded[len - 1] == '/') expanded[--len] = '\0'; char *slash = strrchr(expanded, '/'); if (!slash) { strcpy(expanded, "."); } else if (slash == expanded) { expanded[1] = '\0'; } else { *slash = '\0'; } return expanded; } char *ecex_path_basename_dup(const char *path) { const char *base = "untitled"; if (path && path[0]) { const char *slash = strrchr(path, '/'); if (slash && slash[1]) base = slash + 1; else if (slash && slash == path) base = "/"; else base = path; } char *out = malloc(strlen(base) + 1); if (out) strcpy(out, base); return out; } char *ecex_path_normalize(const char *path) { char *expanded = ecex_path_expand_user(path); if (!expanded) return NULL; char *resolved = realpath(expanded, NULL); if (resolved) { free(expanded); return resolved; } if (expanded[0] == '/') return expanded; char cwd[4096]; if (!getcwd(cwd, sizeof(cwd))) return expanded; char *joined = ecex_path_join(cwd, expanded); free(expanded); return joined; } int ecex_path_exists(const char *path) { if (!path) return 0; char *expanded = ecex_path_expand_user(path); if (!expanded) return 0; struct stat st; int ok = stat(expanded, &st) == 0; free(expanded); return ok; } int ecex_path_is_dir(const char *path) { if (!path) return 0; char *expanded = ecex_path_expand_user(path); if (!expanded) return 0; struct stat st; int ok = stat(expanded, &st) == 0 && S_ISDIR(st.st_mode); free(expanded); return ok; } int ecex_path_is_file(const char *path) { if (!path) return 0; char *expanded = ecex_path_expand_user(path); if (!expanded) return 0; struct stat st; int ok = stat(expanded, &st) == 0 && S_ISREG(st.st_mode); free(expanded); return ok; } long long ecex_path_file_size(const char *path) { if (!path) return -1; char *expanded = ecex_path_expand_user(path); if (!expanded) return -1; struct stat st; long long size = (stat(expanded, &st) == 0 && S_ISREG(st.st_mode)) ? (long long)st.st_size : -1; free(expanded); return size; } static int ext_eq(const char *path, const char *ext) { if (!path || !ext) return 0; size_t pl = strlen(path), el = strlen(ext); if (pl < el) return 0; const char *p = path + pl - el; for (size_t i = 0; i < el; i++) { if (tolower((unsigned char)p[i]) != tolower((unsigned char)ext[i])) return 0; } return 1; } int ecex_path_is_image(const char *path) { return ext_eq(path, ".png") || ext_eq(path, ".jpg") || ext_eq(path, ".jpeg") || ext_eq(path, ".bmp") || ext_eq(path, ".ppm") || ext_eq(path, ".pnm") || ext_eq(path, ".pgm") || ext_eq(path, ".gif") || ext_eq(path, ".webp") || ext_eq(path, ".tif") || ext_eq(path, ".tiff") || ext_eq(path, ".avif") || ext_eq(path, ".heic") || ext_eq(path, ".heif") || ext_eq(path, ".jxl") || ext_eq(path, ".qoi") || ext_eq(path, ".tga") || ext_eq(path, ".dds") || ext_eq(path, ".exr") || ext_eq(path, ".hdr") || ext_eq(path, ".ico"); } int ecex_path_is_previewable_image(const char *path) { return ecex_path_is_image(path); } int ecex_path_is_video(const char *path) { return ext_eq(path, ".mp4") || ext_eq(path, ".m4v") || ext_eq(path, ".mov") || ext_eq(path, ".mkv") || ext_eq(path, ".webm") || ext_eq(path, ".avi") || ext_eq(path, ".wmv") || ext_eq(path, ".flv") || ext_eq(path, ".gif") || ext_eq(path, ".ogv") || ext_eq(path, ".mpeg") || ext_eq(path, ".mpg"); } int ecex_path_is_media(const char *path) { return ecex_path_is_image(path) || ecex_path_is_video(path); } int ecex_path_cwd(char *out, size_t out_size) { if (!out || out_size == 0) return -1; if (!getcwd(out, out_size)) { ecex_path_copy(out, out_size, "."); return -1; } return 0; }