mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-06-13 14:33:17 -04:00
Compare commits
18 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca73ec71d5 | ||
|
|
8b047852f3 | ||
|
|
75e201608b | ||
|
|
c9c448e611 | ||
|
|
35f30e6451 | ||
|
|
7aa880654a | ||
|
|
66ec9fad88 | ||
|
|
382e9a31c5 | ||
|
|
d7742d0312 | ||
|
|
f66a020bba | ||
|
|
8038adedf0 | ||
|
|
4bf60d0fbc | ||
|
|
b18d8aa2f1 | ||
|
|
2eaa7beba1 | ||
|
|
5335cec322 | ||
|
|
f35e60577f | ||
|
|
2d11b36a24 | ||
|
|
ab1660ef62 |
12 changed files with 373 additions and 50 deletions
5
.clangd
Normal file
5
.clangd
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- yaml -*-
|
||||||
|
|
||||||
|
CompileFlags:
|
||||||
|
Add:
|
||||||
|
- -Wno-c2y-extensions
|
||||||
51
CHANGELOG.md
51
CHANGELOG.md
|
|
@ -1,5 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
* [Unreleased](#unreleased)
|
||||||
* [1.27.0](#1-27-0)
|
* [1.27.0](#1-27-0)
|
||||||
* [1.26.1](#1-26-1)
|
* [1.26.1](#1-26-1)
|
||||||
* [1.26.0](#1-26-0)
|
* [1.26.0](#1-26-0)
|
||||||
|
|
@ -69,6 +70,56 @@
|
||||||
* [1.2.0](#1-2-0)
|
* [1.2.0](#1-2-0)
|
||||||
|
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
### Added
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Do not allow codepoints to be merged into grapheme clusters directly
|
||||||
|
after a cursor move ([#2383][2383]).
|
||||||
|
* Dracula theme updated to latest official, and light theme alucard
|
||||||
|
added.
|
||||||
|
* Sixels: pan/pad clamped to 5 ([#2371][2371]).
|
||||||
|
|
||||||
|
[2383]: https://codeberg.org/dnkl/foot/issues/2383
|
||||||
|
[2371]: https://codeberg.org/dnkl/foot/issues/2371
|
||||||
|
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
### Removed
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Out-of-bounds read when parsing URIs with malformed %-encoded
|
||||||
|
content ([#2353][2353]).
|
||||||
|
* DECCRA not clamping or verifying the destination rectangle
|
||||||
|
([#2352][2352]).
|
||||||
|
* Empty selection clearing the clipboard ([#2327][2327]).
|
||||||
|
* Require xkbcommon >= 1.6.0. This has been the case for a while, due
|
||||||
|
to our use of `XKB_KEYSYM_MAX`. Now it is formalized in
|
||||||
|
`meson.build` ([#2379][2379]).
|
||||||
|
* Block selection area incorrectly updated when selecting back
|
||||||
|
across the starting column.
|
||||||
|
* Passing a very large value as CHT/CBT argument hangs the terminal
|
||||||
|
([#2360][2360]).
|
||||||
|
* Sixel: crash when using a shared palette and gamma-correct blending
|
||||||
|
has been enabled, or foot is using 10-bit surface ([#2370][2370]).
|
||||||
|
* Kitty text-size protocol: fix crash when text is zero-length
|
||||||
|
([#2364][2364]).
|
||||||
|
* Escape quotes in file names being DnD:ed on the command line
|
||||||
|
([#2363][2363]).
|
||||||
|
|
||||||
|
[2353]: https://codeberg.org/dnkl/foot/issues/2353
|
||||||
|
[2352]: https://codeberg.org/dnkl/foot/issues/2352
|
||||||
|
[2327]: https://codeberg.org/dnkl/foot/issues/2327
|
||||||
|
[2379]: https://codeberg.org/dnkl/foot/issues/2379
|
||||||
|
[2360]: https://codeberg.org/dnkl/foot/issues/2360
|
||||||
|
[2370]: https://codeberg.org/dnkl/foot/issues/2370
|
||||||
|
[2364]: https://codeberg.org/dnkl/foot/issues/2364
|
||||||
|
|
||||||
|
|
||||||
|
### Security
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
|
||||||
## 1.27.0
|
## 1.27.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
56
csi.c
56
csi.c
|
|
@ -774,7 +774,7 @@ params_to_rectangular_area(const struct terminal *term, int first_idx,
|
||||||
int rel_bottom = vt_param_get(term, first_idx + 2, term->rows) - 1;
|
int rel_bottom = vt_param_get(term, first_idx + 2, term->rows) - 1;
|
||||||
*right = min(vt_param_get(term, first_idx + 3, term->cols) - 1, term->cols - 1);
|
*right = min(vt_param_get(term, first_idx + 3, term->cols) - 1, term->cols - 1);
|
||||||
|
|
||||||
if (rel_top > rel_bottom || *left > *right)
|
if (unlikely(rel_top > rel_bottom || *left > *right))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*top = term_row_rel_to_abs(term, rel_top);
|
*top = term_row_rel_to_abs(term, rel_top);
|
||||||
|
|
@ -1171,37 +1171,40 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
|
|
||||||
case 'I': {
|
case 'I': {
|
||||||
/* CHT - Tab Forward (param is number of tab stops to move through) */
|
/* CHT - Tab Forward (param is number of tab stops to move through) */
|
||||||
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
int count = vt_param_get(term, 0, 1);
|
||||||
int new_col = term->cols - 1;
|
int new_col = term->grid->cursor.point.col;
|
||||||
tll_foreach(term->tab_stops, it) {
|
tll_foreach(term->tab_stops, it) {
|
||||||
if (it->item > term->grid->cursor.point.col) {
|
if (it->item > new_col) {
|
||||||
new_col = it->item;
|
if (--count < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
new_col = it->item;
|
||||||
}
|
}
|
||||||
xassert(new_col >= term->grid->cursor.point.col);
|
|
||||||
|
|
||||||
bool lcf = term->grid->cursor.lcf;
|
|
||||||
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
|
||||||
term->grid->cursor.lcf = lcf;
|
|
||||||
}
|
}
|
||||||
|
xassert(new_col >= term->grid->cursor.point.col);
|
||||||
|
|
||||||
|
bool lcf = term->grid->cursor.lcf;
|
||||||
|
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
||||||
|
term->grid->cursor.lcf = lcf;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Z':
|
case 'Z': {
|
||||||
/* CBT - Back tab (param is number of tab stops to move back through) */
|
/* CBT - Back tab (param is number of tab stops to move back through) */
|
||||||
for (int i = 0; i < vt_param_get(term, 0, 1); i++) {
|
int count = vt_param_get(term, 0, 1);
|
||||||
int new_col = 0;
|
int new_col = term->grid->cursor.point.col;
|
||||||
tll_rforeach(term->tab_stops, it) {
|
tll_rforeach(term->tab_stops, it) {
|
||||||
if (it->item < term->grid->cursor.point.col) {
|
if (it->item < new_col) {
|
||||||
new_col = it->item;
|
if (--count < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
new_col = it->item;
|
||||||
}
|
}
|
||||||
xassert(term->grid->cursor.point.col >= new_col);
|
|
||||||
term_cursor_left(term, term->grid->cursor.point.col - new_col);
|
|
||||||
}
|
}
|
||||||
|
xassert(term->grid->cursor.point.col >= new_col);
|
||||||
|
term_cursor_left(term, term->grid->cursor.point.col - new_col);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'l': {
|
case 'l': {
|
||||||
|
|
@ -2005,9 +2008,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
}
|
}
|
||||||
|
|
||||||
int src_page = vt_param_get(term, 4, 1);
|
int src_page = vt_param_get(term, 4, 1);
|
||||||
|
|
||||||
int dst_rel_top = vt_param_get(term, 5, 1) - 1;
|
int dst_rel_top = vt_param_get(term, 5, 1) - 1;
|
||||||
int dst_left = vt_param_get(term, 6, 1) - 1;
|
int dst_left = min(vt_param_get(term, 6, 1) - 1, term->cols - 1);
|
||||||
int dst_page = vt_param_get(term, 7, 1);
|
int dst_page = vt_param_get(term, 7, 1);
|
||||||
|
|
||||||
if (unlikely(src_page != 1 || dst_page != 1)) {
|
if (unlikely(src_page != 1 || dst_page != 1)) {
|
||||||
|
|
@ -2021,6 +2023,18 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
int dst_top = term_row_rel_to_abs(term, dst_rel_top);
|
int dst_top = term_row_rel_to_abs(term, dst_rel_top);
|
||||||
int dst_bottom = term_row_rel_to_abs(term, dst_rel_bottom);
|
int dst_bottom = term_row_rel_to_abs(term, dst_rel_bottom);
|
||||||
|
|
||||||
|
if (unlikely(dst_left > dst_right || dst_top > dst_bottom))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* src validated by params_to_rectangular_area()
|
||||||
|
* dst validated above
|
||||||
|
*/
|
||||||
|
xassert(src_bottom - src_top >= 0);
|
||||||
|
xassert(dst_bottom - dst_top >= 0);
|
||||||
|
xassert(src_right - src_left >= 0);
|
||||||
|
xassert(dst_right - dst_left >= 0);
|
||||||
|
|
||||||
/* Target area outside the screen is clipped */
|
/* Target area outside the screen is clipped */
|
||||||
const size_t row_count = min(src_bottom - src_top,
|
const size_t row_count = min(src_bottom - src_top,
|
||||||
dst_bottom - dst_top) + 1;
|
dst_bottom - dst_top) + 1;
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ wayland_protocols = dependency('wayland-protocols', version: '>=1.41',
|
||||||
default_options: ['tests=false'])
|
default_options: ['tests=false'])
|
||||||
wayland_client = dependency('wayland-client')
|
wayland_client = dependency('wayland-client')
|
||||||
wayland_cursor = dependency('wayland-cursor')
|
wayland_cursor = dependency('wayland-cursor')
|
||||||
xkb = dependency('xkbcommon', version: '>=1.0.0')
|
xkb = dependency('xkbcommon', version: '>=1.6.0')
|
||||||
fontconfig = dependency('fontconfig')
|
fontconfig = dependency('fontconfig')
|
||||||
utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering'))
|
utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering'))
|
||||||
|
|
||||||
|
|
|
||||||
3
osc.c
3
osc.c
|
|
@ -1149,6 +1149,9 @@ kitty_text_size(struct terminal *term, char *string)
|
||||||
*text = '\0';
|
*text = '\0';
|
||||||
text++;
|
text++;
|
||||||
|
|
||||||
|
if (text[0] == '\0')
|
||||||
|
return;
|
||||||
|
|
||||||
char32_t *wchars = ambstoc32(text);
|
char32_t *wchars = ambstoc32(text);
|
||||||
if (wchars == NULL)
|
if (wchars == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
19
selection.c
19
selection.c
|
|
@ -1145,7 +1145,7 @@ selection_update(struct terminal *term, int col, int row)
|
||||||
struct coord *pivot_end = &term->selection.pivot.end;
|
struct coord *pivot_end = &term->selection.pivot.end;
|
||||||
|
|
||||||
if (term->selection.kind == SELECTION_BLOCK) {
|
if (term->selection.kind == SELECTION_BLOCK) {
|
||||||
if (new_end.col > pivot_start->col)
|
if (new_end.col >= pivot_start->col)
|
||||||
new_direction = SELECTION_RIGHT;
|
new_direction = SELECTION_RIGHT;
|
||||||
else
|
else
|
||||||
new_direction = SELECTION_LEFT;
|
new_direction = SELECTION_LEFT;
|
||||||
|
|
@ -1948,6 +1948,9 @@ static const struct zwp_primary_selection_source_v1_listener primary_selection_s
|
||||||
bool
|
bool
|
||||||
text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
||||||
{
|
{
|
||||||
|
if (text == NULL || text[0] == '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
xassert(serial != 0);
|
xassert(serial != 0);
|
||||||
|
|
||||||
struct wl_clipboard *clipboard = &seat->clipboard;
|
struct wl_clipboard *clipboard = &seat->clipboard;
|
||||||
|
|
@ -2095,7 +2098,16 @@ decode_one_uri(struct clipboard_receive *ctx, char *uri, size_t len)
|
||||||
if (ctx->quote_paths)
|
if (ctx->quote_paths)
|
||||||
ctx->cb("'", 1, ctx->user);
|
ctx->cb("'", 1, ctx->user);
|
||||||
|
|
||||||
ctx->cb(path, strlen(path), ctx->user);
|
char *path_remaining = path;
|
||||||
|
for (char *next_quote = strchr(path_remaining, '\'');
|
||||||
|
next_quote != NULL;
|
||||||
|
path_remaining = next_quote + 1,
|
||||||
|
next_quote = strchr(path_remaining, '\''))
|
||||||
|
{
|
||||||
|
ctx->cb(path_remaining, next_quote - path_remaining, ctx->user);
|
||||||
|
ctx->cb("\\'", 2, ctx->user);
|
||||||
|
}
|
||||||
|
ctx->cb(path_remaining, strlen(path_remaining), ctx->user);
|
||||||
|
|
||||||
if (ctx->quote_paths)
|
if (ctx->quote_paths)
|
||||||
ctx->cb("'", 1, ctx->user);
|
ctx->cb("'", 1, ctx->user);
|
||||||
|
|
@ -2418,6 +2430,9 @@ selection_from_clipboard(struct seat *seat, struct terminal *term, uint32_t seri
|
||||||
bool
|
bool
|
||||||
text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
|
||||||
{
|
{
|
||||||
|
if (text == NULL || text[0] == '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
if (term->wl->primary_selection_device_manager == NULL)
|
if (term->wl->primary_selection_device_manager == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
12
sixel.c
12
sixel.c
|
|
@ -169,10 +169,10 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
|
||||||
|
|
||||||
if (term->sixel.linear_blending || term->sixel.use_10bit) {
|
if (term->sixel.linear_blending || term->sixel.use_10bit) {
|
||||||
for (size_t i = 0; i < active_palette_entries; i++) {
|
for (size_t i = 0; i < active_palette_entries; i++) {
|
||||||
uint8_t r = (term->sixel.private_palette[i] >> 16) & 0xff;
|
uint8_t r = (term->sixel.shared_palette[i] >> 16) & 0xff;
|
||||||
uint8_t g = (term->sixel.private_palette[i] >> 8) & 0xff;
|
uint8_t g = (term->sixel.shared_palette[i] >> 8) & 0xff;
|
||||||
uint8_t b = (term->sixel.private_palette[i] >> 0) & 0xff;
|
uint8_t b = (term->sixel.shared_palette[i] >> 0) & 0xff;
|
||||||
term->sixel.private_palette[i] = color_decode_srgb(term, r, g, b);
|
term->sixel.shared_palette[i] = color_decode_srgb(term, r, g, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1888,8 +1888,8 @@ decgra(struct terminal *term, uint8_t c)
|
||||||
unsigned ph = nparams > 2 ? term->sixel.params[2] : 0;
|
unsigned ph = nparams > 2 ? term->sixel.params[2] : 0;
|
||||||
unsigned pv = nparams > 3 ? term->sixel.params[3] : 0;
|
unsigned pv = nparams > 3 ? term->sixel.params[3] : 0;
|
||||||
|
|
||||||
pan = pan > 0 ? pan : 1;
|
pan = pan > 0 ? min(pan, 5) : 1;
|
||||||
pad = pad > 0 ? pad : 1;
|
pad = pad > 0 ? min(pad, 5) : 1;
|
||||||
|
|
||||||
if (likely(term->sixel.image.width == 0 &&
|
if (likely(term->sixel.image.width == 0 &&
|
||||||
term->sixel.image.height == 0))
|
term->sixel.image.height == 0))
|
||||||
|
|
|
||||||
13
terminal.c
13
terminal.c
|
|
@ -4086,6 +4086,10 @@ term_print(struct terminal *term, char32_t wc, int width, bool insert_mode_disab
|
||||||
xassert(!grid->cursor.lcf);
|
xassert(!grid->cursor.lcf);
|
||||||
|
|
||||||
grid->cursor.point.col = col;
|
grid->cursor.point.col = col;
|
||||||
|
|
||||||
|
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
|
term->vt.codepoint_merging_ok = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -4126,6 +4130,9 @@ ascii_printer_fast(struct terminal *term, char32_t wc)
|
||||||
xassert(!grid->cursor.lcf);
|
xassert(!grid->cursor.lcf);
|
||||||
|
|
||||||
grid->cursor.point.col = col;
|
grid->cursor.point.col = col;
|
||||||
|
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
|
term->vt.codepoint_merging_ok = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (unlikely(row->extra != NULL)) {
|
if (unlikely(row->extra != NULL)) {
|
||||||
grid_row_uri_range_erase(row, uri_start, uri_start);
|
grid_row_uri_range_erase(row, uri_start, uri_start);
|
||||||
|
|
@ -4210,7 +4217,11 @@ term_process_and_print_non_ascii(struct terminal *term, char32_t wc)
|
||||||
{
|
{
|
||||||
int width = c32width(wc);
|
int width = c32width(wc);
|
||||||
bool insert_mode_disable = false;
|
bool insert_mode_disable = false;
|
||||||
const bool grapheme_clustering = term->grapheme_shaping;
|
const bool grapheme_clustering = term->grapheme_shaping
|
||||||
|
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
|
&& term->vt.codepoint_merging_ok
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
#if !defined(FOOT_GRAPHEME_CLUSTERING)
|
#if !defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
xassert(!grapheme_clustering);
|
xassert(!grapheme_clustering);
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,7 @@ struct vt {
|
||||||
char32_t last_printed;
|
char32_t last_printed;
|
||||||
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
utf8proc_int32_t grapheme_state;
|
utf8proc_int32_t grapheme_state;
|
||||||
|
bool codepoint_merging_ok;
|
||||||
#endif
|
#endif
|
||||||
char32_t utf8;
|
char32_t utf8;
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -994,5 +995,6 @@ static inline void term_reset_grapheme_state(struct terminal *term)
|
||||||
{
|
{
|
||||||
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||||
term->vt.grapheme_state = 0;
|
term->vt.grapheme_state = 0;
|
||||||
|
term->vt.codepoint_merging_ok = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
themes/ayu-dark
Normal file
26
themes/ayu-dark
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- conf -*-
|
||||||
|
# theme: Ayu Dark
|
||||||
|
# upstream: https://github.com/ayu-theme/ayu-colors/blob/master/themes/dark.yaml
|
||||||
|
|
||||||
|
[colors-dark]
|
||||||
|
background=0d1017
|
||||||
|
foreground=bfbdb6
|
||||||
|
cursor=0d1017 ffb454
|
||||||
|
|
||||||
|
regular0=0a0000 # black
|
||||||
|
regular1=d75b63 # red
|
||||||
|
regular2=94c230 # green
|
||||||
|
regular3=e79e3a # yellow
|
||||||
|
regular4=40abe7 # blue
|
||||||
|
regular5=bc90e7 # magenta
|
||||||
|
regular6=7ecfb5 # cyan
|
||||||
|
regular7=ffffff # white
|
||||||
|
|
||||||
|
bright0=0a0000 # bright black
|
||||||
|
bright1=f07178 # bright red
|
||||||
|
bright2=aad94c # bright green
|
||||||
|
bright3=ffb454 # bright yellow
|
||||||
|
bright4=59c2ff # bright blue
|
||||||
|
bright5=d2a6ff # bright magenta
|
||||||
|
bright6=95e6cb # bright cyan
|
||||||
|
bright7=ffffff # bright white
|
||||||
|
|
@ -1,23 +1,43 @@
|
||||||
# -*- conf -*-
|
# -*- conf -*-
|
||||||
# Dracula
|
# Dracula / Alucard
|
||||||
|
# Source: https://github.com/dracula/foot
|
||||||
|
|
||||||
[colors-dark]
|
[colors-dark]
|
||||||
cursor=282a36 f8f8f2
|
|
||||||
foreground=f8f8f2
|
foreground=f8f8f2
|
||||||
background=282a36
|
background=282a36
|
||||||
regular0=000000 # black
|
regular0=21222c # black
|
||||||
regular1=ff5555 # red
|
regular1=ff5555 # red
|
||||||
regular2=50fa7b # green
|
regular2=50fa7b # green
|
||||||
regular3=f1fa8c # yellow
|
regular3=f1fa8c # yellow
|
||||||
regular4=bd93f9 # blue
|
regular4=bd93f9 # blue
|
||||||
regular5=ff79c6 # magenta
|
regular5=ff79c6 # magenta
|
||||||
regular6=8be9fd # cyan
|
regular6=8be9fd # cyan
|
||||||
regular7=bfbfbf # white
|
regular7=f8f8f2 # white
|
||||||
bright0=4d4d4d # bright black
|
bright0=6272a4 # bright black
|
||||||
bright1=ff6e67 # bright red
|
bright1=ff6e6e # bright red
|
||||||
bright2=5af78e # bright green
|
bright2=69ff94 # bright green
|
||||||
bright3=f4f99d # bright yellow
|
bright3=ffffa5 # bright yellow
|
||||||
bright4=caa9fa # bright blue
|
bright4=d6acff # bright blue
|
||||||
bright5=ff92d0 # bright magenta
|
bright5=ff92df # bright magenta
|
||||||
bright6=9aedfe # bright cyan
|
bright6=a4ffff # bright cyan
|
||||||
bright7=e6e6e6 # bright white
|
bright7=ffffff # bright white
|
||||||
|
|
||||||
|
[colors-light]
|
||||||
|
foreground=1f1f1f
|
||||||
|
background=fffbeb
|
||||||
|
regular0=fffbeb # white
|
||||||
|
regular1=cb3a2a # red
|
||||||
|
regular2=14710a # green
|
||||||
|
regular3=846e15 # yellow
|
||||||
|
regular4=644ac9 # blue
|
||||||
|
regular5=a3144d # magenta
|
||||||
|
regular6=036a96 # cyan
|
||||||
|
regular7=1f1f1f # white
|
||||||
|
bright0=6c664b # bright black
|
||||||
|
bright1=d74c3d # bright red
|
||||||
|
bright2=198d0c # bright green
|
||||||
|
bright3=9e841a # bright yellow
|
||||||
|
bright4=7862d0 # bright blue
|
||||||
|
bright5=bf185a # bright magenta
|
||||||
|
bright6=047fb4 # bright cyan
|
||||||
|
bright7=2c2b31 # bright white
|
||||||
|
|
|
||||||
178
uri.c
178
uri.c
|
|
@ -195,7 +195,9 @@ uri_parse(const char *uri, size_t len,
|
||||||
encoded_len -= prefix_len;
|
encoded_len -= prefix_len;
|
||||||
decoded_len += prefix_len;
|
decoded_len += prefix_len;
|
||||||
|
|
||||||
if (hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15) {
|
if (encoded_len >= 3 &&
|
||||||
|
hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15)
|
||||||
|
{
|
||||||
*p++ = hex2nibble(next[1]) << 4 | hex2nibble(next[2]);
|
*p++ = hex2nibble(next[1]) << 4 | hex2nibble(next[2]);
|
||||||
decoded_len++;
|
decoded_len++;
|
||||||
encoded_len -= 3;
|
encoded_len -= 3;
|
||||||
|
|
@ -269,3 +271,177 @@ hostname_is_localhost(const char *hostname)
|
||||||
streq(hostname, "localhost") ||
|
streq(hostname, "localhost") ||
|
||||||
streq(hostname, this_host)));
|
streq(hostname, this_host)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Valid URI, all components */
|
||||||
|
const char uri[] = "http://john:wick@www.foobar.com:80/this/is/the%20path?query1=abc&query2=def#fragment";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(streq(user, "john")); free(user);
|
||||||
|
xassert(streq(password, "wick")); free(password);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path")); free(path);
|
||||||
|
xassert(streq(query, "query1=abc&query2=def")); free(query);
|
||||||
|
xassert(streq(fragment, "fragment")); free(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Valid URI, all components. Using file scheme, so query+fragment is treated as part of the path */
|
||||||
|
const char uri[] = "file://john:wick@www.foobar.com:80/this/is/the%20path?query1=abc&query2=def#fragment";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "file")); free(scheme);
|
||||||
|
xassert(streq(user, "john")); free(user);
|
||||||
|
xassert(streq(password, "wick")); free(password);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path?query1=abc&query2=def#fragment")); free(path);
|
||||||
|
xassert(query == NULL);
|
||||||
|
xassert(fragment == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Test a valid URI containing all components, except password */
|
||||||
|
const char uri[] = "http://john@www.foobar.com:80/this/is/the%20path?query1=abc&query2=def#fragment";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(streq(user, "john")); free(user);
|
||||||
|
xassert(password == NULL);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path")); free(path);
|
||||||
|
xassert(streq(query, "query1=abc&query2=def")); free(query);
|
||||||
|
xassert(streq(fragment, "fragment")); free(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Valid URI, all components, except user+password */
|
||||||
|
const char uri[] = "http://www.foobar.com:80/this/is/the%20path?query1=abc&query2=def#fragment";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(user == NULL);
|
||||||
|
xassert(password == NULL);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path")); free(path);
|
||||||
|
xassert(streq(query, "query1=abc&query2=def")); free(query);
|
||||||
|
xassert(streq(fragment, "fragment")); free(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Valid URI, fragment, no query */
|
||||||
|
const char uri[] = "http://www.foobar.com:80/this/is/the%20path#fragment";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(user == NULL);
|
||||||
|
xassert(password == NULL);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path")); free(path);
|
||||||
|
xassert(query == NULL);
|
||||||
|
xassert(streq(fragment, "fragment")); free(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Valid URI, query, no fragment */
|
||||||
|
const char uri[] = "http://www.foobar.com:80/this/is/the%20path?query1=abc&query2=def";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(user == NULL);
|
||||||
|
xassert(password == NULL);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path")); free(path);
|
||||||
|
xassert(streq(query, "query1=abc&query2=def")); free(query);
|
||||||
|
xassert(fragment == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Malformed URI, fragment before query (treated as part of path instead) */
|
||||||
|
const char uri[] = "http://www.foobar.com:80/this/is/the%20path#fragment?query1=abc&query2=def";
|
||||||
|
|
||||||
|
char *scheme, *user, *password, *host, *path, *query, *fragment;
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
uri_parse(
|
||||||
|
uri, sizeof(uri) - 1, &scheme, &user, &password, &host, &port, &path,
|
||||||
|
&query, &fragment);
|
||||||
|
xassert(streq(scheme, "http")); free(scheme);
|
||||||
|
xassert(user == NULL);
|
||||||
|
xassert(password == NULL);
|
||||||
|
xassert(streq(host, "www.foobar.com")); free(host);
|
||||||
|
xassert(port == 80);
|
||||||
|
xassert(streq(path, "/this/is/the path#fragment?query1=abc&query2=def")); free(path);
|
||||||
|
xassert(query == NULL);
|
||||||
|
xassert(fragment == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Malformed URI, trailing '%' */
|
||||||
|
const char uri[] = "file:///%ABNOT-PART-OF-INPUT";
|
||||||
|
char *path;
|
||||||
|
uri_parse(uri, 9, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL);
|
||||||
|
xassert(streq(path, "/%")); free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Malformed URI, trailing '%2' */
|
||||||
|
const char uri[] = "file:///%2ANOT-PART-OF-INPUT";
|
||||||
|
char *path;
|
||||||
|
uri_parse(uri, 10, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL);
|
||||||
|
xassert(streq(path, "/%2")); free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITTEST
|
||||||
|
{
|
||||||
|
/* Malformed URI, trailing '%ag' */
|
||||||
|
const char uri[] = "file:///%ag";
|
||||||
|
char *path;
|
||||||
|
uri_parse(uri, sizeof(uri) - 1, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL);
|
||||||
|
xassert(streq(path, "/%ag")); free(path);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue