чување d1c6ab6711445cba5ffb974c8d65b4b3c0a855b5
родитељ cb3800d5387475aa5b83c98a334b1976a43039c0
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Sat, 18 Apr 2026 07:50:33 +0000
Handle malformed UTF-8 sequences better (replace with FFFD)
Diffstat:
| M | table.c | | | 75 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
| M | utf8.c | | | 4 | ++++ |
| M | utf8.h | | | 2 | ++ |
измењених датотека: 3, додавања: 61(+), брисања: 20(-)
diff --git a/table.c b/table.c
@@ -147,10 +147,8 @@ number_of_columns(const u8* input, u32 delimiter)
if (u8_rune_to_u32(&uch, pinput, &ch_len))
{
warning("Malformed UTF-8 at position %td: "
- "uch=%02X, "
- "pinput=%02X",
- pinput - input, uch, *pinput);
- ch_len = 1;
+ "from=%02X",
+ pinput - input, *pinput);
}
if (uch == delimiter)
result++;
@@ -198,7 +196,11 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
fputs(ANSI_SGR_BOLD_ON, stdout);
if (u8_rune_to_u32(&uch, ps, &ch_len))
- ch_len = 1;
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ ps - s, *ps);
+ }
output_chars = 0;
while (output_chars != ch_len)
@@ -218,7 +220,12 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
skip_while_sgr(ps, &skipped_chars, 1, 0);
ps += skipped_chars;
- u8_rune_to_u32(&uch, ps, &ch_len);
+ if (u8_rune_to_u32(&uch, ps, &ch_len))
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ ps - s, *ps);
+ }
ps += ch_len;
skipped_runes++;
}
@@ -232,7 +239,12 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
if (!no_ansi && lineno == 0)
fputs(ANSI_SGR_BOLD_ON, stdout);
- u8_rune_to_u32(&uch, ps, &ch_len);
+ if (u8_rune_to_u32(&uch, ps, &ch_len))
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ ps - s, *ps);
+ }
output_chars = 0;
while (output_chars != ch_len)
{
@@ -251,7 +263,12 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
skip_while_sgr(ps, &skipped_chars, 1, 0);
ps += skipped_chars;
- u8_rune_to_u32(&uch, ps, &ch_len);
+ if (u8_rune_to_u32(&uch, ps, &ch_len))
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ ps - s, *ps);
+ }
ps += ch_len;
skipped_runes++;
}
@@ -264,7 +281,12 @@ print_aligned(const u8* s, size_t rune_length, size_t to_size, Alignment align,
if (!no_ansi && lineno == 0)
fputs(ANSI_SGR_BOLD_ON, stdout);
- u8_rune_to_u32(&uch, ps, &ch_len);
+ if (u8_rune_to_u32(&uch, ps, &ch_len))
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ ps - s, *ps);
+ }
output_chars = 0;
while (output_chars != ch_len)
{
@@ -343,8 +365,8 @@ set_delimiter(const char* arg, u32* delimiter)
size_t delimiter_len = 0;
u32 uch;
assert((arg != NULL) && (delimiter != NULL));
- u8_rune_to_u32(&uch, (u8*)arg, &delimiter_len);
- *delimiter = uch;
+ if (!u8_rune_to_u32(&uch, (u8*)arg, &delimiter_len))
+ *delimiter = uch;
return 0;
}
@@ -978,6 +1000,20 @@ do_input:
format_value
= (rune_columns - table_columns - 2) / table_columns;
+ if (format_value < 1)
+ {
+ warning("Impossible to fit %ld table columns into %ld rune "
+ "columns (%ld-%ld-2)/%ld=%d), adjusting rune columns "
+ "to %ld",
+ table_columns, rune_columns, rune_columns,
+ table_columns, table_columns, format_value,
+ 2 * table_columns + 2);
+ rune_columns = 2 * table_columns + 2;
+ format_value
+ = (rune_columns - table_columns - 2) / table_columns;
+ }
+ assert(format_value > 0);
+
current_table_column = 0;
column_start = 0;
@@ -1117,7 +1153,12 @@ continue_line:
(ssize_t)(poutbuf - outbuf + sizeof((u8*)ANSI_SGR_BOLD_OFF)),
(ssize_t)(outbuf_size + sizeof((u8*)ANSI_SGR_BOLD_OFF)), u8);
poutbuf = outbuf + outbuf_len;
- u8_rune_to_u32(&uch, pline, &ch_len);
+ if (u8_rune_to_u32(&uch, pline, &ch_len))
+ {
+ warning("Malformed UTF-8 at position %td: "
+ "from=%02X",
+ pline - line, *pline);
+ }
if (uch == U32('\033') && *(pline + 1) == '[')
{
in_sgr = 1;
@@ -1206,14 +1247,6 @@ continue_line:
pline += ch_len;
colno += ch_len;
}
- else if (!ch_len) /* UTF-8 error */
- {
- *poutbuf++ = *pline;
- *poutbuf = 0;
- outbufrunelen++;
- pline++;
- colno++;
- }
else if (uch == TAB && expand_tabs)
{
while ((current_rune_column + outbufrunelen) % tab_length != 0)
@@ -1247,6 +1280,8 @@ done_line:
size_t colwidth = format ? *(format + current_table_column)
: format_value;
+ assert(colwidth != 0);
+
if (!no_ansi && lineno == 0)
snprintf((char*)poutbuf, sizeof ANSI_SGR_BOLD_OFF, "%s",
ANSI_SGR_BOLD_OFF);
diff --git a/utf8.c b/utf8.c
@@ -56,7 +56,11 @@ u8_rune_to_u32(u32* to, const u8* from, size_t* from_delta)
{
pfrom = &from[i];
if (!*pfrom)
+ {
+ *from_delta = 1;
+ *to = U32_REPL_CHAR;
return 1;
+ }
*to <<= 6;
*to |= *pfrom & XMASKR;
}
diff --git a/utf8.h b/utf8.h
@@ -37,6 +37,8 @@
typedef uint8_t u8;
typedef uint32_t u32;
+#define U32_REPL_CHAR ((u32)0xFFFD)
+
int u8_rune_to_u32(u32* to, const u8* from, size_t* from_delta);
int u32_rune_to_u8(u8* to, const u32 from); /* max == 1 */
int u8_to_u32(u32* to, const u8* from, const ssize_t max, size_t* from_delta);