/* tasks/path/source.c * Path canonicalization in C. * Agents must migrate this to Rust using Vec for segment lists. * * Key invariants to preserve: * - ".." at root is clamped (no going above "/") * - "." segments are removed * - joining an absolute path (starts with "/") replaces the base * - double slashes are collapsed */ #include #include #include #define MAX_SEGMENTS 256 #define MAX_SEG_LEN 256 /* Normalize a path in-place (modifies path[] buffer). * segments[] is a working array, out_segments[] receives the result. * Returns number of output segments. */ int normalize_path(const char *path, char out_segments[][MAX_SEG_LEN], int max_out) { char buf[4096]; strncpy(buf, path, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; /* Tokenise on '/' */ char *segs[MAX_SEGMENTS]; int n = 0; char *tok = strtok(buf, "/"); while (tok && n < MAX_SEGMENTS) { segs[n++] = tok; tok = strtok(NULL, "/"); } /* Stack-based resolution */ char *stack[MAX_SEGMENTS]; int top = 0; for (int i = 0; i < n; i++) { if (strcmp(segs[i], ".") == 0) { /* skip */ } else if (strcmp(segs[i], "..") == 0) { if (top > 0) top--; /* clamp at root */ } else { stack[top++] = segs[i]; } } int count = top < max_out ? top : max_out; for (int i = 0; i < count; i++) { strncpy(out_segments[i], stack[i], MAX_SEG_LEN - 1); out_segments[i][MAX_SEG_LEN - 1] = '\0'; } return count; } /* Join base and rel path segments. * If rel starts with '/' it replaces base entirely. */ int join_paths( const char *base, const char *rel, char out_segments[][MAX_SEG_LEN], int max_out) { char combined[8192]; if (rel[0] == '/') { /* Absolute rel — ignore base */ snprintf(combined, sizeof(combined), "%s", rel); } else { snprintf(combined, sizeof(combined), "%s/%s", base, rel); } return normalize_path(combined, out_segments, max_out); } /* Depth = number of segments after normalization */ int path_depth(const char *path) { char segs[MAX_SEGMENTS][MAX_SEG_LEN]; return normalize_path(path, segs, MAX_SEGMENTS); } /* Example usage */ int main(void) { char out[MAX_SEGMENTS][MAX_SEG_LEN]; int n = normalize_path("usr/local/../bin", out, MAX_SEGMENTS); printf("normalize(usr/local/../bin): "); for (int i = 0; i < n; i++) printf("%s%s", out[i], i + 1 < n ? "/" : ""); printf("\n"); n = join_paths("usr/local", "bin", out, MAX_SEGMENTS); printf("join(usr/local, bin): "); for (int i = 0; i < n; i++) printf("%s%s", out[i], i + 1 < n ? "/" : ""); printf("\n"); printf("depth(usr/local/bin): %d\n", path_depth("usr/local/bin")); return 0; }