Preliminary support for UTF-8 console

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-03-16 00:48:34 +01:00
parent 9a3355cfde
commit f10331edf2
3 changed files with 69 additions and 39 deletions

View file

@ -117,7 +117,9 @@ grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize);
int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position);
void
grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size,
grub_uint8_t *dest, grub_size_t destsize);
grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t **srcend);

View file

@ -120,6 +120,45 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
return p - dest;
}
/* Convert UCS-4 to UTF-8. */
void
grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size,
grub_uint8_t *dest, grub_size_t destsize)
{
/* Keep last char for \0. */
grub_uint8_t *destend = dest + destsize - 1;
while (size-- && dest < destend)
{
grub_uint32_t code = *src++;
if (code <= 0x007F)
*dest++ = code;
else if (code <= 0x07FF)
{
if (dest + 1 >= destend)
break;
*dest++ = (code >> 6) | 0xC0;
*dest++ = (code & 0x3F) | 0x80;
}
else if ((code >= 0xDC00 && code <= 0xDFFF)
|| (code >= 0xD800 && code <= 0xDBFF))
{
/* No surrogates in UCS-4... */
*dest++ = '?';
}
else
{
if (dest + 2 >= destend)
break;
*dest++ = (code >> 12) | 0xE0;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
}
*dest = 0;
}
/* Convert UCS-4 to UTF-8. */
char *
grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
@ -127,7 +166,7 @@ grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
grub_size_t remaining;
grub_uint32_t *ptr;
grub_size_t cnt = 0;
grub_uint8_t *ret, *dest;
grub_uint8_t *ret;
remaining = size;
ptr = src;
@ -152,34 +191,7 @@ grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
if (!ret)
return 0;
dest = ret;
remaining = size;
ptr = src;
while (remaining--)
{
grub_uint32_t code = *ptr++;
if (code <= 0x007F)
*dest++ = code;
else if (code <= 0x07FF)
{
*dest++ = (code >> 6) | 0xC0;
*dest++ = (code & 0x3F) | 0x80;
}
else if ((code >= 0xDC00 && code <= 0xDFFF)
|| (code >= 0xD800 && code <= 0xDBFF))
{
/* No surrogates in UCS-4... */
*dest++ = '?';
}
else
{
*dest++ = (code >> 12) | 0xE0;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
}
*dest = 0;
grub_ucs4_to_utf8 (src, size, ret, cnt);
return (char *) ret;
}
@ -953,8 +965,9 @@ map_code (grub_uint32_t in, struct grub_term_output *term)
if (in <= 0x7f)
return in;
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) == GRUB_TERM_CODE_TYPE_VGA)
switch (term->flags & GRUB_TERM_CODE_TYPE_MASK)
{
case GRUB_TERM_CODE_TYPE_VGA:
switch (in)
{
case GRUB_TERM_DISP_LEFT:
@ -979,9 +992,7 @@ map_code (grub_uint32_t in, struct grub_term_output *term)
return 0xd9;
}
return '?';
}
else
{
case GRUB_TERM_CODE_TYPE_ASCII:
/* Better than nothing. */
switch (in)
{
@ -990,7 +1001,7 @@ map_code (grub_uint32_t in, struct grub_term_output *term)
case GRUB_TERM_DISP_UP:
return '^';
case GRUB_TERM_DISP_RIGHT:
return '>';
@ -1017,8 +1028,7 @@ map_code (grub_uint32_t in, struct grub_term_output *term)
/* Put a Unicode character. */
void
grub_putcode (grub_uint32_t code,
struct grub_term_output *term)
grub_putcode (grub_uint32_t code, struct grub_term_output *term)
{
struct grub_unicode_glyph c =
{
@ -1042,9 +1052,25 @@ grub_putcode (grub_uint32_t code,
return;
}
c.base = map_code (code, term);
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
== GRUB_TERM_CODE_TYPE_UTF8_LOGICAL)
{
grub_uint8_t str[20], *ptr;
grub_ucs4_to_utf8 (&code, 1, str, sizeof (str));
for (ptr = str; *ptr; ptr++)
{
c.base = *ptr;
(term->putchar) (&c);
}
}
else
{
c.base = map_code (code, term);
(term->putchar) (&c);
}
(term->putchar) (&c);
if (code == '\n')
grub_putcode ('\r', term);
}

View file

@ -343,6 +343,8 @@ grub_serial_putchar (const struct grub_unicode_glyph *c)
break;
default:
if ((c->base & 0xC0) == 0xC0)
break;
if (xpos >= TEXT_WIDTH)
{
xpos = 0;