Spaces:
Sleeping
Sleeping
| /* tasks/path/source.c | |
| * Path canonicalization in C. | |
| * Agents must migrate this to Rust using Vec<String> 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 | |
| */ | |
| /* 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; | |
| } | |