From 16f7c8f6d372c4a5fe209cafdcec0def95d69169 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 8 May 2013 11:09:08 +0200 Subject: [PATCH] * grub-core/commands/cat.c: Show UTF-8 characters. --- ChangeLog | 4 ++ grub-core/commands/cat.c | 85 ++++++++++++++++++++++++++++++++++------ include/grub/charset.h | 16 ++++++++ 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0da7177af..a57d103b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-05-08 Vladimir Serbinenko + + * grub-core/commands/cat.c: Show UTF-8 characters. + 2013-05-08 Vladimir Serbinenko * conf/Makefile.common: Poison float and double on non-emu. diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c index cd2d76099..8a7f1af78 100644 --- a/grub-core/commands/cat.c +++ b/grub-core/commands/cat.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -39,9 +40,15 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) struct grub_arg_list *state = ctxt->state; int dos = 0; grub_file_t file; - char buf[GRUB_DISK_SECTOR_SIZE]; + unsigned char buf[GRUB_DISK_SECTOR_SIZE]; grub_ssize_t size; int key = GRUB_TERM_NO_KEY; + grub_uint32_t code = 0; + int count = 0; + unsigned char utbuf[GRUB_MAX_UTF8_PER_CODEPOINT + 1]; + int utcount = 0; + int is_0d = 0; + int j; if (state[0].set) dos = 1; @@ -60,21 +67,65 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) for (i = 0; i < size; i++) { - unsigned char c = buf[i]; + utbuf[utcount++] = buf[i]; - if ((grub_isprint (c) || grub_isspace (c)) && c != '\r') - grub_printf ("%c", c); - else if (dos && c == '\r' && i + 1 < size && buf[i + 1] == '\n') - { - grub_printf ("\n"); - i++; - } - else + if (is_0d && buf[i] != '\n') { grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); - grub_printf ("<%x>", (int) c); + grub_printf ("<%x>", (int) '\r'); grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); } + + is_0d = 0; + + if (!grub_utf8_process (buf[i], &code, &count)) + { + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + for (j = 0; j < utcount - 1; j++) + grub_printf ("<%x>", (unsigned int) utbuf[j]); + code = 0; + count = 0; + if (utcount == 1 || !grub_utf8_process (buf[i], &code, &count)) + { + grub_printf ("<%x>", (unsigned int) buf[i]); + code = 0; + count = 0; + utcount = 0; + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + continue; + } + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + utcount = 1; + } + if (count) + continue; + + if ((code >= 0xa1 || grub_isprint (code) + || grub_isspace (code)) && code != '\r') + { + grub_printf ("%C", code); + count = 0; + code = 0; + utcount = 0; + continue; + } + + if (dos && code == '\r') + { + is_0d = 1; + count = 0; + code = 0; + utcount = 0; + continue; + } + + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + for (j = 0; j < utcount; j++) + grub_printf ("<%x>", (unsigned int) utbuf[j]); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + count = 0; + code = 0; + utcount = 0; } do @@ -82,6 +133,18 @@ grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) while (key != GRUB_TERM_ESC && key != GRUB_TERM_NO_KEY); } + if (is_0d) + { + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("<%x>", (unsigned int) '\r'); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + } + + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + for (j = 0; j < utcount; j++) + grub_printf ("<%x>", (unsigned int) utbuf[j]); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + grub_xputs ("\n"); grub_refresh (); grub_file_close (file); diff --git a/include/grub/charset.h b/include/grub/charset.h index ab9202884..d14faea32 100644 --- a/include/grub/charset.h +++ b/include/grub/charset.h @@ -41,6 +41,7 @@ You need at least three UTF-8 bytes to have 2 UTF-16 words (surrogate pairs). */ #define GRUB_MAX_UTF16_PER_UTF8 1 +#define GRUB_MAX_UTF8_PER_CODEPOINT 4 #define GRUB_UCS2_LIMIT 0x10000 #define GRUB_UTF16_UPPER_SURROGATE(code) \ @@ -67,6 +68,14 @@ grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) *code <<= 6; *code |= (c & GRUB_UINT8_6_TRAILINGBITS); (*count)--; + /* Overlong. */ + if ((*count == 1 && *code <= 0x1f) + || (*count == 2 && *code <= 0xf)) + { + *code = 0; + *count = 0; + return 0; + } return 1; } } @@ -80,6 +89,13 @@ grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) { *count = 1; *code = c & GRUB_UINT8_5_TRAILINGBITS; + /* Overlong */ + if (*code <= 1) + { + *count = 0; + *code = 0; + return 0; + } return 1; } if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS)