col: make input to tolerate invalid wide characters
The getwchar(3) will choke and exit if invalid character is encountered. This change will make col(1) to print broken multibyte characters as \x{hex} string. Reported-by: Vitaly Lipatov <lav@etersoft.ru> Addresses: https://github.com/karelzak/util-linux/issues/1198 Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
parent
77d44c1e51
commit
14a36f96ee
|
@ -1 +0,0 @@
|
||||||
col: failed on line 1: EILSEQ
|
|
|
@ -0,0 +1 @@
|
||||||
|
abc\x80\x80jkl
|
|
@ -0,0 +1 @@
|
||||||
|
Dateiname der Versandh\xfclle
|
|
@ -24,8 +24,17 @@ ts_init "$*"
|
||||||
ts_check_test_command "$TS_CMD_COL"
|
ts_check_test_command "$TS_CMD_COL"
|
||||||
ts_check_test_command "$TS_HELPER_STRERROR"
|
ts_check_test_command "$TS_HELPER_STRERROR"
|
||||||
|
|
||||||
|
ts_init_subtest "valid"
|
||||||
cat $TS_SELF/multibyte.data |
|
cat $TS_SELF/multibyte.data |
|
||||||
LC_ALL=C.UTF-8 ts_run $TS_CMD_COL 2>&1 > /dev/null |
|
LC_ALL=C ts_run $TS_CMD_COL 2>&1 |
|
||||||
sed -e "s@$($TS_HELPER_STRERROR EILSEQ)@EILSEQ@" > $TS_OUTPUT
|
sed -e "s@$($TS_HELPER_STRERROR EILSEQ)@EILSEQ@" > $TS_OUTPUT
|
||||||
|
ts_finalize_subtest
|
||||||
|
|
||||||
|
ts_init_subtest "invalid"
|
||||||
|
printf '%s\n' $'abc\200\200jkl' |
|
||||||
|
LC_ALL=C ts_run $TS_CMD_COL 2>&1 |
|
||||||
|
sed -e "s@$($TS_HELPER_STRERROR EILSEQ)@EILSEQ@" > $TS_OUTPUT
|
||||||
|
ts_finalize_subtest
|
||||||
|
|
||||||
|
|
||||||
ts_finalize
|
ts_finalize
|
||||||
|
|
107
text-utils/col.c
107
text-utils/col.c
|
@ -599,6 +599,49 @@ static void free_line_allocations(struct col_alloc *root)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void process_char(struct col_ctl *ctl, struct col_lines *lns)
|
||||||
|
{
|
||||||
|
/* Deal printable characters */
|
||||||
|
if (!iswgraph(lns->ch) && handle_not_graphic(ctl, lns))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Must stuff ch in a line - are we at the right one? */
|
||||||
|
if ((size_t)lns->cur_line != lns->this_line - lns->adjust)
|
||||||
|
update_cur_line(ctl, lns);
|
||||||
|
|
||||||
|
/* Does line buffer need to grow? */
|
||||||
|
if (ctl->l->l_lsize <= ctl->l->l_line_len + 1) {
|
||||||
|
size_t need;
|
||||||
|
|
||||||
|
need = ctl->l->l_lsize ? ctl->l->l_lsize * 2 : NALLOC;
|
||||||
|
ctl->l->l_line = xrealloc(ctl->l->l_line, need * sizeof(struct col_char));
|
||||||
|
ctl->l->l_lsize = need;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store character */
|
||||||
|
lns->c = &ctl->l->l_line[ctl->l->l_line_len++];
|
||||||
|
lns->c->c_char = lns->ch;
|
||||||
|
lns->c->c_set = lns->cur_set;
|
||||||
|
|
||||||
|
if (0 < lns->cur_col)
|
||||||
|
lns->c->c_column = lns->cur_col;
|
||||||
|
else
|
||||||
|
lns->c->c_column = 0;
|
||||||
|
lns->c->c_width = wcwidth(lns->ch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If things are put in out of order, they will need sorting
|
||||||
|
* when it is flushed.
|
||||||
|
*/
|
||||||
|
if (lns->cur_col < ctl->l->l_max_col)
|
||||||
|
ctl->l->l_needs_sort = 1;
|
||||||
|
else
|
||||||
|
ctl->l->l_max_col = lns->cur_col;
|
||||||
|
if (0 < lns->c->c_width)
|
||||||
|
lns->cur_col += lns->c->c_width;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct col_ctl ctl = {
|
struct col_ctl ctl = {
|
||||||
|
@ -623,52 +666,30 @@ int main(int argc, char **argv)
|
||||||
while (feof(stdin) == 0) {
|
while (feof(stdin) == 0) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
/* Get character */
|
/* Get character */
|
||||||
if ((lns.ch = getwchar()) == WEOF) {
|
lns.ch = getwchar();
|
||||||
|
|
||||||
|
if (lns.ch == WEOF) {
|
||||||
if (errno == EILSEQ) {
|
if (errno == EILSEQ) {
|
||||||
warn(_("failed on line %lu"), lns.max_line + 1);
|
/* Illegal multibyte sequence */
|
||||||
ret = EXIT_FAILURE;
|
int c;
|
||||||
}
|
char buf[5];
|
||||||
|
size_t len, i;
|
||||||
|
|
||||||
|
c = getchar();
|
||||||
|
if (c == EOF)
|
||||||
break;
|
break;
|
||||||
|
sprintf(buf, "\\x%02x", (unsigned char) c);
|
||||||
|
len = strlen(buf);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
lns.ch = buf[i];
|
||||||
|
process_char(&ctl, &lns);
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
/* Deal printable characters */
|
/* end of file */
|
||||||
if (!iswgraph(lns.ch) && handle_not_graphic(&ctl, &lns))
|
break;
|
||||||
continue;
|
} else
|
||||||
|
/* the common case */
|
||||||
/* Must stuff ch in a line - are we at the right one? */
|
process_char(&ctl, &lns);
|
||||||
if ((size_t)lns.cur_line != lns.this_line - lns.adjust)
|
|
||||||
update_cur_line(&ctl, &lns);
|
|
||||||
|
|
||||||
/* Does line buffer need to grow? */
|
|
||||||
if (ctl.l->l_lsize <= ctl.l->l_line_len + 1) {
|
|
||||||
size_t need;
|
|
||||||
|
|
||||||
need = ctl.l->l_lsize ? ctl.l->l_lsize * 2 : NALLOC;
|
|
||||||
ctl.l->l_line = xrealloc(ctl.l->l_line, need * sizeof(struct col_char));
|
|
||||||
ctl.l->l_lsize = need;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store character */
|
|
||||||
lns.c = &ctl.l->l_line[ctl.l->l_line_len++];
|
|
||||||
lns.c->c_char = lns.ch;
|
|
||||||
lns.c->c_set = lns.cur_set;
|
|
||||||
|
|
||||||
if (0 < lns.cur_col)
|
|
||||||
lns.c->c_column = lns.cur_col;
|
|
||||||
else
|
|
||||||
lns.c->c_column = 0;
|
|
||||||
lns.c->c_width = wcwidth(lns.ch);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If things are put in out of order, they will need sorting
|
|
||||||
* when it is flushed.
|
|
||||||
*/
|
|
||||||
if (lns.cur_col < ctl.l->l_max_col)
|
|
||||||
ctl.l->l_needs_sort = 1;
|
|
||||||
else
|
|
||||||
ctl.l->l_max_col = lns.cur_col;
|
|
||||||
if (0 < lns.c->c_width)
|
|
||||||
lns.cur_col += lns.c->c_width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* goto the last line that had a character on it */
|
/* goto the last line that had a character on it */
|
||||||
|
|
Loading…
Reference in New Issue