vt: add ucs_get_fallback()
authorNicolas Pitre <npitre@baylibre.com>
Wed, 7 May 2025 14:13:21 +0000 (10:13 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 May 2025 11:39:45 +0000 (13:39 +0200)
This is the code querying the newly introduced tables.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Link: https://lore.kernel.org/r/20250507141535.40655-7-nico@fluxnic.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/vt/Makefile
drivers/tty/vt/ucs.c
include/linux/consolemap.h

index 509362a3e11e96ae57713ac87f4a304c8d56bdc7..ae746dcdeec8c8f10693350c6abbf2c75e1309d1 100644 (file)
@@ -36,7 +36,8 @@ $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
 
 endif
 
-$(obj)/ucs.o: $(src)/ucs.c $(obj)/ucs_width_table.h $(obj)/ucs_recompose_table.h
+$(obj)/ucs.o:  $(src)/ucs.c $(obj)/ucs_width_table.h \
+               $(obj)/ucs_recompose_table.h $(obj)/ucs_fallback_table.h
 
 # You may uncomment one of those to have the UCS tables be regenerated
 # during the build process. By default the _shipped versions are used.
index b0b23830170d1908d68399f233b2eb8d8cabcd11..6c15c5deda5b89d8dfbe9c203348a4de439ea5cb 100644 (file)
@@ -157,3 +157,87 @@ u32 ucs_recompose(u32 base, u32 mark)
 
        return result ? result->recomposed : 0;
 }
+
+/*
+ * The fallback table structures implement a 2-level lookup.
+ */
+
+struct ucs_page_desc {
+       u8 page;        /* Page index (high byte of code points) */
+       u8 count;       /* Number of entries in this page */
+       u16 start;      /* Start index in entries array */
+};
+
+struct ucs_page_entry {
+       u8 offset;      /* Offset within page (0-255) */
+       u8 fallback;    /* Fallback character or range start marker */
+};
+
+#include "ucs_fallback_table.h"
+
+static int ucs_page_desc_cmp(const void *key, const void *element)
+{
+       u8 page = *(u8 *)key;
+       const struct ucs_page_desc *entry = element;
+
+       if (page < entry->page)
+               return -1;
+       if (page > entry->page)
+               return 1;
+       return 0;
+}
+
+static int ucs_page_entry_cmp(const void *key, const void *element)
+{
+       u8 offset = *(u8 *)key;
+       const struct ucs_page_entry *entry = element;
+
+       if (offset < entry->offset)
+               return -1;
+       if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER) {
+               if (offset > entry[1].offset)
+                       return 1;
+       } else {
+               if (offset > entry->offset)
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * ucs_get_fallback() - Get a substitution for the provided Unicode character
+ * @base: Base Unicode code point (UCS-4)
+ *
+ * Get a simpler fallback character for the provided Unicode character.
+ * This is used for terminal display when corresponding glyph is unavailable.
+ * The substitution may not be as good as the actual glyph for the original
+ * character but still way more helpful than a squared question mark.
+ *
+ * Return: Fallback Unicode code point, or 0 if none is available
+ */
+u32 ucs_get_fallback(u32 cp)
+{
+       const struct ucs_page_desc *page;
+       const struct ucs_page_entry *entry;
+       u8 page_idx = cp >> 8, offset = cp;
+
+       if (!UCS_IS_BMP(cp))
+               return 0;
+
+       page = __inline_bsearch(&page_idx, ucs_fallback_pages,
+                               ARRAY_SIZE(ucs_fallback_pages),
+                               sizeof(*ucs_fallback_pages),
+                               ucs_page_desc_cmp);
+       if (!page)
+               return 0;
+
+       entry = __inline_bsearch(&offset, ucs_fallback_entries + page->start,
+                                page->count, sizeof(*ucs_fallback_entries),
+                                ucs_page_entry_cmp);
+       if (!entry)
+               return 0;
+
+       if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER)
+               entry++;
+       return entry->fallback;
+}
index 8167494229db65df5ed6df985d88c3041f24d832..6180b803795c44300acb9cb531ac1f5e3f6ecfea 100644 (file)
@@ -31,6 +31,7 @@ void console_map_init(void);
 bool ucs_is_double_width(uint32_t cp);
 bool ucs_is_zero_width(uint32_t cp);
 u32 ucs_recompose(u32 base, u32 mark);
+u32 ucs_get_fallback(u32 cp);
 #else
 static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph,
                bool use_unicode)
@@ -75,6 +76,11 @@ static inline u32 ucs_recompose(u32 base, u32 mark)
 {
        return 0;
 }
+
+static inline u32 ucs_get_fallback(u32 cp)
+{
+       return 0;
+}
 #endif /* CONFIG_CONSOLE_TRANSLATIONS */
 
 #endif /* __LINUX_CONSOLEMAP_H__ */