aboutsummaryrefslogtreecommitdiff
path: root/src/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/path.c')
-rw-r--r--src/path.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/path.c b/src/path.c
index be2b347..930fbb7 100644
--- a/src/path.c
+++ b/src/path.c
@@ -114,6 +114,92 @@ char *ecex_path_normalize(const char *path) {
return joined;
}
+static int ecex_project_root_has_marker(const char *dir) {
+ static const char *const markers[] = {
+ ".git",
+ "compile_commands.json",
+ "compile_flags.txt",
+ ".ecex-project",
+ };
+
+ for (size_t i = 0; i < sizeof(markers) / sizeof(markers[0]); i++) {
+ char *path = ecex_path_join(dir, markers[i]);
+ if (!path) continue;
+ int found = ecex_path_exists(path);
+ free(path);
+ if (found) return 1;
+ }
+
+ return 0;
+}
+
+static char *ecex_path_parent_dup(const char *path) {
+ if (!path || !path[0]) return NULL;
+
+ char *parent = ecex_strdup(path);
+ if (!parent) return NULL;
+
+ size_t len = strlen(parent);
+ while (len > 1 && parent[len - 1] == '/') parent[--len] = '\0';
+ if (strcmp(parent, "/") == 0) return parent;
+
+ char *slash = strrchr(parent, '/');
+ if (!slash) {
+ free(parent);
+ return NULL;
+ }
+
+ if (slash == parent) parent[1] = '\0';
+ else *slash = '\0';
+ return parent;
+}
+
+char *ecex_project_root_for_file(const char *path) {
+ char *start = NULL;
+
+ if (path && path[0]) {
+ if (ecex_path_is_dir(path)) {
+ start = ecex_path_normalize(path);
+ } else {
+ char *dir = ecex_path_dirname(path);
+ if (dir) {
+ start = ecex_path_normalize(dir);
+ free(dir);
+ }
+ }
+ } else {
+ char cwd[4096];
+ if (ecex_path_cwd(cwd, sizeof(cwd)) == 0) start = ecex_path_normalize(cwd);
+ }
+
+ if (!start) return NULL;
+ char *fallback = ecex_strdup(start);
+ if (!fallback) {
+ free(start);
+ return NULL;
+ }
+
+ char *dir = start;
+ while (dir && dir[0]) {
+ if (ecex_project_root_has_marker(dir)) {
+ free(fallback);
+ return dir;
+ }
+
+ char *parent = ecex_path_parent_dup(dir);
+ if (!parent || strcmp(parent, dir) == 0) {
+ free(parent);
+ break;
+ }
+
+ free(dir);
+ dir = parent;
+ }
+
+ free(dir);
+ return fallback;
+}
+
int ecex_path_exists(const char *path) {
if (!path) return 0;
char *expanded = ecex_path_expand_user(path);