UNIXworkcode

char *make_path_absolute(const char *path) { static const char *cwd = NULL; static size_t cwdlen = 0; static const char fs = FILE_SEPARATOR; char *abspath; if (path_is_relative(path)) { if (cwdlen == 0) { get_working_dir(&cwd, &cwdlen); } size_t pathlen = strlen(path); char *result = malloc(pathlen+cwdlen+1); const char *part = path; size_t partlen = pathlen; if (part[0] == '.' && part[1] == fs) { part += 2; partlen -= 2; } memcpy(result, cwd, cwdlen); memcpy(result+cwdlen, part, partlen); result[cwdlen+partlen] = '\0'; abspath = result; } else { abspath = strdup(path); } /* make path canonical */ size_t abspathlen = strlen(abspath); char *canonical = malloc(abspathlen + 1); size_t canonicallen = 0; for (size_t j = 0; j < abspathlen; j++) { /* collapse consecutive separators */ if (abspath[j] == fs) { while (abspath[j + 1] == fs) j++; } /* add the current char to the canonical path */ canonical[canonicallen++] = abspath[j]; /* check for special dirs after a file separator */ if (abspath[j] == fs && abspath[j + 1] == '.') { if (abspath[j + 2] == fs || abspath[j + 2] == 0) { /* skip '.' segments */ canonicallen--; j++; } else if (abspath[j + 2] == '.' && (abspath[j + 3] == fs || abspath[j + 3] == 0)) { /* trace back '..' segment */ canonicallen--; while (canonical[--canonicallen] != fs) {} j += 2; } } } /* remove trailing slashes */ if (canonical[canonicallen - 1] == fs) canonicallen--; canonical[canonicallen] = '\0'; free(abspath); return canonical; }