#include <errno.h>
#include <sys/stat.h>

int
normalizepath(const char *path, char **normal)
{
  size_t len = strlen(path);
  *normal = (char *)malloc((len + 1) * sizeof(char));
  const char *walk = path;
  const char *match;
  size_t newlen = 0;

  while ((match = strchr(walk, '/'))) {
    // Copy everything between match and walk
    strncpy(*normal + newlen, walk, match - walk);
    newlen += match - walk;
    walk += match - walk;

    // Skip all repeating slashes
    while (*walk == '/')
      walk++;

    // If not last character in path
    if (walk != path + len)
      (*normal)[newlen++] = '/';
  }

  (*normal)[newlen++] = '\0';

  // Copy remaining path
  strcat(*normal, walk);
  newlen += strlen(walk);

  *normal = (char *)realloc(*normal, newlen * sizeof(char));

  return 0;
}

int
parentdir(const char *path, char **parent)
{
  char *normal;
  char *walk;

  normalizepath(path, &normal);

  // Pointer to last '/'
  if (!(walk = strrchr(normal, '/'))) {
    free(normal);
    return -1;
  }

  // Get path up to last '/'
  size_t len = walk - normal;
  *parent = (char *)malloc((len + 1) * sizeof(char));

  // Copy path up to last '/'
  strncpy(*parent, normal, len);
  // Add null char
  (*parent)[len] = '\0';

  free(normal);

  return 0;
}

int
mkdirp(const char *path)
{
  char *normal;
  char *walk;
  size_t normallen;

  normalizepath(path, &normal);
  normallen = strlen(normal);
  walk = normal;

  while (walk < normal + normallen + 1) {
    // Get length from walk to next /
    size_t n = strcspn(walk, "/");

    // Skip path /
    if (n == 0) {
      walk++;
      continue;
    }

    // Length of current path segment
    size_t curpathlen = walk - normal + n;
    char curpath[curpathlen + 1];
    struct stat s;

    // Copy path segment to stat
    strncpy(curpath, normal, curpathlen);
    strcpy(curpath + curpathlen, "");
    int res = stat(curpath, &s);

    if (res < 0) {
      if (errno == ENOENT) {
        DEBUG("Making directory %s\n", curpath);
        if (mkdir(curpath, 0700) < 0) {
          fprintf(stderr, "Failed to make directory %s\n", curpath);
          perror("");
          free(normal);
          return -1;
        }
      } else {
        fprintf(stderr, "Error statting directory %s\n", curpath);
        perror("");
        free(normal);
        return -1;
      }
    }

    // Continue to next path segment
    walk += n;
  }

  free(normal);

  return 0;
}

int
nullterminate(char **str, size_t *len)
{
  if ((*str)[*len - 1] == '\0')
    return 0;

  (*len)++;
  *str = (char*)realloc(*str, *len * sizeof(char));
  (*str)[*len - 1] = '\0';

  return 0;
}