#include <stdlib.h>
#include <string.h>
#include "array.h"
#include "prompt_utils.h"
char const *relative_path(char const *const from_dir, char const *const to_dir) {
// easiest cases first
{
if (strcmp(from_dir, to_dir) == 0) {
char *return_value = malloc(2);
strcpy(return_value, ".");
return return_value;
}
}
{
if (strcmp("/", from_dir) == 0) {
char *return_value = malloc(strlen(to_dir) + 2);
return_value[0] = '.';
memcpy(return_value + 1, to_dir, strlen(to_dir) + 1);
return return_value;
}
}
// splitting path into pieces so we can do strcmp on each of them
size_t const *const from_dir_indices = get_separator_indices(from_dir, '/');
size_t const *const to_dir_indices = get_separator_indices(to_dir, '/');
size_t from_dir_len = arrayLen(from_dir_indices);
size_t to_dir_len = arrayLen(to_dir_indices);
// finding the longest common substring
size_t array_len = from_dir_len < to_dir_len ? from_dir_len : to_dir_len;
size_t i = 0;
size_t common_position = 0;
for (; i < array_len - 1; ++i) {
if (from_dir_indices[i + 1] != to_dir_indices[i + 1]) {
break;
}
size_t index = from_dir_indices[i];
size_t count = from_dir_indices[i + 1] - from_dir_indices[i];
if (strncmp(from_dir + index, to_dir + index, count) != 0) {
break;
}
common_position = from_dir_indices[i + 1];
}
size_t levels_up = from_dir_len - i - 1;
char *return_value;
if (levels_up == 0) {
// equal dirs for whole length of path and not equal => subdir
size_t length = strlen(to_dir + common_position) + strlen("./") + 1;
return_value = malloc(length * sizeof(char));
strcpy(return_value, ".");
strcat(return_value, to_dir + common_position);
} else {
char const *const go_up = "/..";
size_t length = strlen(to_dir + common_position) + strlen("..") +
strlen(go_up) * (levels_up - 1) + 1;
return_value = malloc(length * sizeof(char));
strcpy(return_value, "..");
for (size_t j = 0; j < levels_up - 1; ++j) {
strcat(return_value, go_up);
}
if (strcmp("/", to_dir) != 0) {
strcat(return_value, to_dir + common_position);
}
}
arrayRelease((void *)from_dir_indices);
arrayRelease((void *)to_dir_indices);
return return_value;
}
size_t *get_separator_indices(char const *const text, char seperator) {
size_t *indices;
arrayInit(indices);
char const *current = text;
if (strchr(current, seperator) == NULL) {
arrayRelease(indices);
return NULL;
}
while ((current = strchr(current, seperator)) != NULL) {
arrayPush(indices) = (size_t) (current - text);
++current;
}
arrayPush(indices) = strlen(text);
return indices;
}