grid: adding a new URI range now handles overlapping URIs

If the URI being added overlaps with pre-existing URIs, the
pre-existing URIs are either removed, split or truncated, depending on
_how_ they overlap.

Closes #801
This commit is contained in:
Daniel Eklöf 2021-11-19 19:59:26 +01:00
parent 7522c2d211
commit e9d6ec2a87
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 120 additions and 0 deletions

View file

@ -53,6 +53,8 @@
* Regression: `pipe-*` key bindings not being parsed correctly, * Regression: `pipe-*` key bindings not being parsed correctly,
resulting in invalid error messages resulting in invalid error messages
(https://codeberg.org/dnkl/foot/issues/809). (https://codeberg.org/dnkl/foot/issues/809).
* Incorrect handling of one OSC-8 URI overwriting another OSC-8 URI
(https://codeberg.org/dnkl/foot/issues/801).
### Security ### Security

118
grid.c
View file

@ -848,11 +848,129 @@ void
grid_row_add_uri_range(struct row *row, struct row_uri_range range) grid_row_add_uri_range(struct row *row, struct row_uri_range range)
{ {
ensure_row_has_extra_data(row); ensure_row_has_extra_data(row);
/* Handle overlapping URIs */
tll_foreach(row->extra->uri_ranges, it) {
struct row_uri_range *old = &it->item;
if (range.start <= old->start && range.end >= old->end) {
/* New URI replaces old URI completely */
grid_row_uri_range_destroy(old);
tll_remove(row->extra->uri_ranges, it);
}
else if (range.start > old->start && range.end < old->end) {
/* New URI replaces a part in the middle of the old URI */
struct row_uri_range old_tail = {
.start = range.end + 1,
.end = old->end,
.id = old->id,
.uri = old->uri != NULL ? xstrdup(old->uri) : NULL,
};
tll_insert_after(row->extra->uri_ranges, it, old_tail);
old->end = range.start - 1;
break; /* There can be no more overlapping URIs */
}
else if (range.start <= old->end && range.end >= old->end) {
/* New URI replaces the tail of the old URI */
xassert(range.end >= old->end);
old->end = range.start - 1;
}
else if (range.start <= old->start && range.end >= old->start) {
/* New URI replaces the head of the old URI */
xassert(range.start <= old->start);
old->start = range.end + 1;
break; /* There can be no more overlapping URIs */
}
}
tll_rforeach(row->extra->uri_ranges, it) { tll_rforeach(row->extra->uri_ranges, it) {
if (it->item.end < range.start) { if (it->item.end < range.start) {
tll_insert_after(row->extra->uri_ranges, it, range); tll_insert_after(row->extra->uri_ranges, it, range);
return; return;
} }
} }
tll_push_front(row->extra->uri_ranges, range); tll_push_front(row->extra->uri_ranges, range);
} }
UNITTEST
{
struct row_data row_data = {.uri_ranges = tll_init()};
struct row row = {.extra = &row_data};
#define row_has_no_overlapping_uris(row) \
do { \
tll_foreach((row)->extra->uri_ranges, it1) { \
tll_foreach((row)->extra->uri_ranges, it2) { \
if (&it1->item == &it2->item) \
continue; \
xassert(it1->item.start != it2->item.start); \
xassert(it1->item.start != it2->item.end); \
xassert(it1->item.end != it2->item.start); \
xassert(it1->item.end != it2->item.end); \
} \
} \
} while (0)
grid_row_add_uri_range(&row, (struct row_uri_range){1, 10});
xassert(tll_length(row_data.uri_ranges) == 1);
xassert(tll_front(row_data.uri_ranges).start == 1);
xassert(tll_front(row_data.uri_ranges).end == 10);
row_has_no_overlapping_uris(&row);
grid_row_add_uri_range(&row, (struct row_uri_range){11, 20});
xassert(tll_length(row_data.uri_ranges) == 2);
xassert(tll_back(row_data.uri_ranges).start == 11);
xassert(tll_back(row_data.uri_ranges).end == 20);
row_has_no_overlapping_uris(&row);
/* Add URI that completely covers both the old rows */
grid_row_add_uri_range(&row, (struct row_uri_range){1, 20});
xassert(tll_length(row_data.uri_ranges) == 1);
xassert(tll_front(row_data.uri_ranges).start == 1);
xassert(tll_front(row_data.uri_ranges).end == 20);
row_has_no_overlapping_uris(&row);
/* One more URI, directly after the previous one */
grid_row_add_uri_range(&row, (struct row_uri_range){21, 30});
/* This URI covers second half of the first URI, and first half of
* the second URI */
grid_row_add_uri_range(&row, (struct row_uri_range){5, 25});
xassert(tll_length(row_data.uri_ranges) == 3);
xassert(tll_front(row_data.uri_ranges).start == 1);
xassert(tll_front(row_data.uri_ranges).end == 4);
xassert(tll_back(row_data.uri_ranges).start == 26);
xassert(tll_back(row_data.uri_ranges).end == 30);
row_has_no_overlapping_uris(&row);
/* This URI splits the second of the three pre-existing URIs in
* the middle */
grid_row_add_uri_range(&row, (struct row_uri_range){11, 20});
xassert(tll_length(row_data.uri_ranges) == 5);
row_has_no_overlapping_uris(&row);
xassert(tll_front(row_data.uri_ranges).start == 1);
xassert(tll_front(row_data.uri_ranges).end == 4);
tll_pop_front(row_data.uri_ranges);
xassert(tll_front(row_data.uri_ranges).start == 5);
xassert(tll_front(row_data.uri_ranges).end == 10);
tll_pop_front(row_data.uri_ranges);
xassert(tll_front(row_data.uri_ranges).start == 11);
xassert(tll_front(row_data.uri_ranges).end == 20);
tll_pop_front(row_data.uri_ranges);
xassert(tll_front(row_data.uri_ranges).start == 21);
xassert(tll_front(row_data.uri_ranges).end == 25);
tll_pop_front(row_data.uri_ranges);
xassert(tll_front(row_data.uri_ranges).start == 26);
xassert(tll_front(row_data.uri_ranges).end == 30);
tll_pop_front(row_data.uri_ranges);
xassert(tll_length(row_data.uri_ranges) == 0);
#undef row_has_no_overlapping_uris
tll_free(row_data.uri_ranges);
}