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;
}

