]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Preliminary support for UTF-8 console
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 15 Mar 2010 23:48:34 +0000 (00:48 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 15 Mar 2010 23:48:34 +0000 (00:48 +0100)
include/grub/charset.h
normal/charset.c
term/serial.c

index 6fdc2aa37969d83428d56404155b6ff54ca1e168..1d79d5d2ce6baf15195072c6f3e40addb6d5bd2e 100644 (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);
index db72a9026bcb2965ebed8a6c5485992f6019c90e..20c47e2ba23f08428ecc580615a6fe28b57503e9 100644 (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);
 }
index d98ca4c9e1a12d1438ca4ea22d5420486ac83703..14d1f4501c7be7ba706f09b85ac8dc5527873124 100644 (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;