UNIXworkcode

1 char *make_path_absolute(const char *path) { 2 static const char *cwd = NULL; 3 static size_t cwdlen = 0; 4 static const char fs = FILE_SEPARATOR; 5 char *abspath; 6 if (path_is_relative(path)) { 7 if (cwdlen == 0) { 8 get_working_dir(&cwd, &cwdlen); 9 } 10 size_t pathlen = strlen(path); 11 char *result = malloc(pathlen+cwdlen+1); 12 const char *part = path; 13 size_t partlen = pathlen; 14 if (part[0] == '.' && part[1] == fs) { 15 part += 2; 16 partlen -= 2; 17 } 18 memcpy(result, cwd, cwdlen); 19 memcpy(result+cwdlen, part, partlen); 20 result[cwdlen+partlen] = '\0'; 21 abspath = result; 22 } else { 23 abspath = strdup(path); 24 } 25 /* make path canonical */ 26 size_t abspathlen = strlen(abspath); 27 char *canonical = malloc(abspathlen + 1); 28 size_t canonicallen = 0; 29 for (size_t j = 0; j < abspathlen; j++) { 30 /* collapse consecutive separators */ 31 if (abspath[j] == fs) { 32 while (abspath[j + 1] == fs) j++; 33 } 34 /* add the current char to the canonical path */ 35 canonical[canonicallen++] = abspath[j]; 36 /* check for special dirs after a file separator */ 37 if (abspath[j] == fs && abspath[j + 1] == '.') { 38 if (abspath[j + 2] == fs || abspath[j + 2] == 0) { 39 /* skip '.' segments */ 40 canonicallen--; 41 j++; 42 } else if (abspath[j + 2] == '.' && 43 (abspath[j + 3] == fs || abspath[j + 3] == 0)) { 44 /* trace back '..' segment */ 45 canonicallen--; 46 while (canonical[--canonicallen] != fs) {} 47 j += 2; 48 } 49 } 50 } 51 /* remove trailing slashes */ 52 if (canonical[canonicallen - 1] == fs) canonicallen--; 53 canonical[canonicallen] = '\0'; 54 free(abspath); 55 return canonical; 56 } 57 58