summaryrefslogtreecommitdiffstats
path: root/02_exercise/prompt_utils.c
diff options
context:
space:
mode:
Diffstat (limited to '02_exercise/prompt_utils.c')
-rw-r--r--02_exercise/prompt_utils.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/02_exercise/prompt_utils.c b/02_exercise/prompt_utils.c
new file mode 100644
index 0000000..168c088
--- /dev/null
+++ b/02_exercise/prompt_utils.c
@@ -0,0 +1,90 @@
+#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_indeces = get_separator_indices(from_dir, '/');
+ size_t const *const to_dir_indeces = get_separator_indices(to_dir, '/');
+
+ size_t from_dir_len = arrayLen(from_dir_indeces);
+ size_t to_dir_len = arrayLen(to_dir_indeces);
+
+ // 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_indeces[i + 1] != to_dir_indeces[i + 1]) {
+ break;
+ }
+ size_t index = from_dir_indeces[i];
+ size_t count = from_dir_indeces[i + 1] - from_dir_indeces[i];
+ if (strncmp(from_dir + index, to_dir + index, count) != 0) {
+ break;
+ }
+ common_position = from_dir_indeces[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_indeces);
+ arrayRelease((void *)to_dir_indeces);
+
+ 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;
+}