summaryrefslogtreecommitdiffstats
path: root/02_exercise/prompt_utils.c
blob: 168c08850f1d556178a1bfcf28c6f61d05e862bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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;
}