Skip to content

Commit

Permalink
Relative are calculated
Browse files Browse the repository at this point in the history
  • Loading branch information
lygstate committed Dec 16, 2024
1 parent 7fa4d39 commit c9919d9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 25 deletions.
134 changes: 119 additions & 15 deletions src/cpj.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ typedef struct
cpj_size_t segment_count;
} cpj_segment_iterator_t;

typedef struct
{
cpj_size_t segment_count_base;
cpj_size_t segment_count_other;
cpj_size_t equal_segment;
} cpj_path_intersection_t;

bool cpj_path_is_separator(cpj_path_style_t style, const cpj_char_t ch)
{
if (style == CPJ_STYLE_WINDOWS) {
Expand Down Expand Up @@ -507,20 +514,13 @@ static bool cpj_path_is_string_equal(
return true;
}

typedef struct
{
cpj_size_t segment_count_base;
cpj_size_t segment_count_other;
cpj_size_t equal_segment;
} cpj_path_intersection_t;

static cpj_path_intersection_t cpj_path_get_intersection_detial(
cpj_path_style_t path_style, const cpj_string_t *path_base, const cpj_string_t *path_other
static cpj_path_intersection_t cpj_path_get_intersection_segments(
cpj_path_style_t path_style, const cpj_string_t *path_base, const cpj_string_t *path_other, cpj_size_t path_count
)
{
cpj_path_intersection_t intersection;
cpj_segment_iterator_t it_base = cpj_path_interator_init(path_style, false, true, path_base, 1);
cpj_segment_iterator_t it_other = cpj_path_interator_init(path_style, false, true, path_other, 1);
cpj_segment_iterator_t it_base = cpj_path_interator_init(path_style, true, true, path_base, path_count);
cpj_segment_iterator_t it_other = cpj_path_interator_init(path_style, true, true, path_other, path_count);
cpj_size_t k;
intersection.equal_segment = 0;
while (cpj_path_get_prev_segment(path_style, &it_base)) {
Expand All @@ -530,8 +530,8 @@ static cpj_path_intersection_t cpj_path_get_intersection_detial(
intersection.segment_count_base = it_base.segment_count;
intersection.segment_count_other = it_other.segment_count;

it_base = cpj_path_interator_init(path_style, false, true, path_base, 1);
it_other = cpj_path_interator_init(path_style, false, true, path_other, 1);
it_base = cpj_path_interator_init(path_style, true, true, path_base, path_count);
it_other = cpj_path_interator_init(path_style, true, true, path_other, path_count);
if (intersection.segment_count_base > intersection.segment_count_other) {
for (k = intersection.segment_count_base; k > intersection.segment_count_other;) {
k -= 1;
Expand Down Expand Up @@ -568,12 +568,113 @@ static cpj_path_intersection_t cpj_path_get_intersection_detial(
return intersection;
}

static cpj_size_t cpj_path_relative_generate(
cpj_path_style_t path_style, cpj_path_intersection_t *intersection, cpj_char_t *buffer, cpj_size_t buffer_size,
cpj_size_t buffer_index
)
{
cpj_size_t segment_eat_count;
if (intersection->equal_segment == intersection->segment_count_base) {
if (intersection->equal_segment == intersection->segment_count_other) {
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '\0');
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '.');
segment_eat_count = 2;
} else {
segment_eat_count = 0;
}
} else {
cpj_size_t k = intersection->segment_count_base;
segment_eat_count = 0;
if (intersection->equal_segment == intersection->segment_count_other) {
--k;
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '\0');
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '.');
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '.');
segment_eat_count += 3;
}
for (; k > intersection->equal_segment;) {
--k;
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '/');
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '.');
cpj_path_push_front(path_style, buffer, buffer_size, &buffer_index, '.');
segment_eat_count += 3;
}
}
return segment_eat_count;
}

static cpj_size_t cpj_path_relative_to(
cpj_path_style_t path_style, const cpj_string_t *cwd_directory, const cpj_string_t *path_directory,
const cpj_string_t *path, cpj_char_t *buffer, cpj_size_t buffer_size
)
{
const cpj_string_t path_base_original[] = {*cwd_directory, *path_directory};
const cpj_string_t path_other_original[] = {*cwd_directory, *path};
const cpj_string_t *path_base = path_base_original + 2 - 1;
const cpj_string_t *path_other = path_other_original + 2 - 1;
cpj_size_t path_count = 1;
cpj_path_intersection_t
intersection = cpj_path_get_intersection_segments(path_style, path_base, path_other, path_count);
if (intersection.equal_segment == 0) {
path_base = path_base_original;
path_other = path_other_original;
path_count = 2;
intersection = cpj_path_get_intersection_segments(path_style, path_base, path_other, path_count);
if (intersection.equal_segment == 0) {
return cpj_path_join_and_normalize(path_style, true, true, path_other, path_count, buffer, buffer_size);
}
}
{
cpj_segment_iterator_t it_other = cpj_path_interator_init(path_style, true, true, path_other, path_count);
cpj_size_t segment_eat_count = cpj_path_relative_generate(path_style, &intersection, NULL, 0, 0);
cpj_size_t other_path_length;
if (intersection.equal_segment == intersection.segment_count_other) {
other_path_length = 0;
} else {
cpj_size_t k = intersection.segment_count_other;
for (; k > intersection.equal_segment;) {
k -= 1;
cpj_path_get_prev_segment(path_style, &it_other);
}
const cpj_char_t *segment_ptr = cpj_path_get_segment_ptr(&it_other);
cpj_size_t segment_length = cpj_path_get_segment_length(&it_other);
cpj_string_t path_other_normalize[2];
cpj_size_t path_other_normalize_count;
path_other_normalize[0] = it_other.path_list_p[it_other.list_pos];
path_other_normalize[0].ptr = segment_ptr;
path_other_normalize[0].size = it_other.path_list_p[it_other.list_pos].ptr +
it_other.path_list_p[it_other.list_pos].size - segment_ptr;
if (it_other.list_pos == 0 && it_other.path_list_count == 2) {
path_other_normalize_count = 2;
path_other_normalize[1] = it_other.path_list_p[1];
} else {
path_other_normalize_count = 1;
}
cpj_char_t *buffer_other = NULL;
cpj_size_t buffer_size_other = 0;
if (buffer && buffer_size > segment_eat_count) {
buffer_other = buffer + segment_eat_count;
buffer_size_other = buffer_size - segment_eat_count;
}
other_path_length = cpj_path_join_and_normalize(
path_style, true, true, path_other_normalize, path_other_normalize_count, buffer_other, buffer_size_other
);
}
if (buffer) {
cpj_path_relative_generate(path_style, &intersection, buffer, buffer_size, segment_eat_count);
}
return other_path_length == 0 ? segment_eat_count - 1 : segment_eat_count + other_path_length;
}
return 0;
}

cpj_size_t
cpj_path_get_intersection(cpj_path_style_t path_style, const cpj_char_t *path_base, const cpj_char_t *path_other)
{
cpj_string_t path_base_str = cpj_string_create(path_base, cpj_strlen(path_base));
cpj_string_t path_other_str = cpj_string_create(path_other, cpj_strlen(path_other));
cpj_path_intersection_t intersection = cpj_path_get_intersection_detial(path_style, &path_base_str, &path_other_str);
cpj_path_intersection_t
intersection = cpj_path_get_intersection_segments(path_style, &path_base_str, &path_other_str, 1);
cpj_segment_iterator_t it_base = cpj_path_interator_init(path_style, false, true, &path_base_str, 1);
cpj_size_t k;
if (intersection.equal_segment == 0) {
Expand All @@ -593,7 +694,10 @@ cpj_size_t cpj_path_get_relative(
cpj_size_t buffer_size
)
{
return 0;
cpj_string_t base_directory_str = cpj_string_create(base_directory, cpj_strlen(base_directory));
cpj_string_t path_str = cpj_string_create(path, cpj_strlen(path));
cpj_string_t path_cwd = {CPJ_ZSTR_ARG("/")};
return cpj_path_relative_to(path_style, &path_cwd, &base_directory_str, &path_str, buffer, buffer_size);
}

/**
Expand Down
16 changes: 6 additions & 10 deletions test/relative_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,14 @@ int relative_relative_and_absolute(void)
{
char result[FILENAME_MAX];
cpj_size_t length;
char *expected;

*result = 1;

length = cpj_path_get_relative(CPJ_STYLE_UNIX, "./foo", "/bar", result, sizeof(result));

if (length != 0) {
return EXIT_FAILURE;
}

if (*result != '\0') {
expected = "../bar";
if (length != strlen(expected) || strcmp(result, expected) != 0) {
return EXIT_FAILURE;
}

Expand All @@ -107,17 +105,15 @@ int relative_different_roots(void)
{
char result[FILENAME_MAX];
cpj_size_t length;
char *expected;

*result = 1;

length = cpj_path_get_relative(CPJ_STYLE_WINDOWS, "C:/path/same", "D:/path/same", result,
sizeof(result));

if (length != 0) {
return EXIT_FAILURE;
}

if (*result != '\0') {
expected = "D:\\path\\same";
if (length != strlen(expected) || strcmp(result, expected) != 0) {
return EXIT_FAILURE;
}

Expand Down

0 comments on commit c9919d9

Please sign in to comment.