From f415f038198cee6fcd9d16d228b85a6095a5c92f Mon Sep 17 00:00:00 2001
From: Chen Weijie <nocsmctg@gmail.com>
Date: Mon, 5 Aug 2024 14:11:37 +0800
Subject: [PATCH] term: Fix the calculation on character width when setting
 LANG="zh_CN"

Under an environment with the simplified Chinese language support, BIOS
enables the PXE module to load GRUB bootstrap files, it will invoke the
grub_normal_parse_line() function to parse and execute the grub.cfg
file. The recursive error printing occurs as follows:

> ?????????cannot allocate pages???
> ?????????cannot allocate pages???
> ?????????cannot allocate pages???

The reason is that when GRUB executes the command "terminal_output
gfxterm" to set the terminal type, the width of characters cannot be
correctly calculated in calculate_normal_character_width() due to the
lack of consideration for simplified Chinese encoding support. This
leads to a recursive loop printing error behavior after GRUB calls the
grub_print_error() API function. This commit adds the simplified Chinese
support, fixes character calculation, and resolves this issue.

Signed-off-by: Chen Weijie <nocsmctg@gmail.com>
Signed-off-by: Su Weiqiang <suweiqian@wxiat.com>
Signed-off-by: Zhao Yihan <zhaoyihan@wxiat.com>
---
 grub-core/term/gfxterm.c | 43 +++++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c
index 3c468f459..1fb637de1 100644
--- a/grub-core/term/gfxterm.c
+++ b/grub-core/term/gfxterm.c
@@ -936,26 +936,45 @@ grub_gfxterm_putchar (struct grub_term_output *term,
     draw_cursor (1);
 }
 
-/* Use ASCII characters to determine normal character width.  */
+/* Iterate character width  */
 static unsigned int
-calculate_normal_character_width (grub_font_t font)
+iterate_character_width (grub_font_t font, unsigned int width, unsigned int start, unsigned int end)
 {
   struct grub_font_glyph *glyph;
-  unsigned int width = 0;
   unsigned int i;
 
+  for (i = start; i < end; i++) {
+    glyph = grub_font_get_glyph (font, i);
+
+    if (!glyph)
+      continue;
+
+    if (glyph->device_width > width)
+      width = glyph->device_width;
+  }
+
+  return width;
+}
+
+/* Use ASCII characters or simplified Chinese characters to determine 
+ * normal character width.  */
+static unsigned int
+calculate_normal_character_width (grub_font_t font)
+{
+  unsigned int width = 0;
+  const char *lang_name;
+
   /* Get properties of every printable ASCII character.  */
-  for (i = 32; i < 127; i++)
-    {
-      glyph = grub_font_get_glyph (font, i);
+  lang_name = grub_env_get ("lang");
 
-      /* Skip unknown characters.  Should never happen on normal conditions.  */
-      if (! glyph)
-	continue;
+  if (!grub_strcmp (lang_name, "zh_CN")) {
+    width = iterate_character_width (font, width, 0x3000, 0x3002);
+    width = iterate_character_width (font, width, 0x4E00, 0x9FFF);
+    width = iterate_character_width (font, width, 0xFF00, 0xFFEF);
+  }
+
+  width = iterate_character_width (font, width, 32, 127);
 
-      if (glyph->device_width > width)
-	width = glyph->device_width;
-    }
   if (!width)
     return 8;
 
-- 
2.24.3 (Apple Git-128)

