shithub: choc

Download patch

ref: 40d1ce5541da78b93348f7102c05f92e8df69062
parent: 0aece203e8fdb2848f7b19885c07f477bc03130a
author: Simon Howard <fraggle@soulsphere.org>
date: Sat Jan 21 10:46:04 EST 2017

textscreen: Refactor code page mapping.

We were duplicating the Unicode/code page mapping table between
txt_gui.c and txt_sdl.c, but in an incomplete and inconsistent way. It
makes sense that the code page mapping should be kept with the font
files that represent the code page anyway, as there may be projects like
Julian Nechaevsky's Russian Doom which may want to change the code page.

--- a/textscreen/fonts/Makefile.am
+++ b/textscreen/fonts/Makefile.am
@@ -1,4 +1,4 @@
-FONT_HDRS = small.h normal.h large.h
+FONT_HDRS = small.h normal.h large.h codepage.h
 EXTRA_DIST = small.png normal.png large.png convert-font $(FONT_HDRS)
 
 noinst_DATA = $(FONT_HDRS)
--- /dev/null
+++ b/textscreen/fonts/codepage.h
@@ -1,0 +1,113 @@
+//
+// Copyright(C) 2017 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+
+// This file contains a #define macro mapping from the characters
+// in the CP437 code page to the equivalent Unicode characters. It
+// therefore defines which Unicode characters can be represented on
+// a text screen using such a code page.
+//
+// If you're changing the textscreen font to show a different code
+// page, you should update the mapping in this file to match. The
+// Wikipedia pages for DOS code pages are a good place to look for
+// this information.
+
+#define CODE_PAGE_TO_UNICODE {                      \
+                                                    \
+       /* CP437 control codes: */                   \
+                                                    \
+    0x0000, 0x263a, 0x263b, 0x2665,  /* 00 - 0f */  \
+    0x2666, 0x2663, 0x2660, 0x2022,                 \
+    0x25d8, 0x25cb, 0x25d9, 0x2642,                 \
+    0x2640, 0x266a, 0x266b, 0x263c,                 \
+                                                    \
+    0x25ba, 0x25c4, 0x2195, 0x203c,  /* 10 - 1f */  \
+    0x00b6, 0x00a7, 0x25ac, 0x21a8,                 \
+    0x2191, 0x2193, 0x2192, 0x2190,                 \
+    0x221f, 0x2194, 0x25b2, 0x25bc,                 \
+                                                    \
+       /* Standard ASCII range: */                  \
+                                                    \
+    0x0020, 0x0021, 0x0022, 0x0023,  /* 20 - 2f */  \
+    0x0024, 0x0025, 0x0026, 0x0027,                 \
+    0x0028, 0x0029, 0x002a, 0x002b,                 \
+    0x002c, 0x002d, 0x002e, 0x002f,                 \
+                                                    \
+    0x0030, 0x0031, 0x0032, 0x0033,  /* 30 - 3f */  \
+    0x0034, 0x0035, 0x0036, 0x0037,                 \
+    0x0038, 0x0039, 0x003a, 0x003b,                 \
+    0x003c, 0x003d, 0x003e, 0x003f,                 \
+                                                    \
+    0x0040, 0x0041, 0x0042, 0x0043,  /* 40 - 4f */  \
+    0x0044, 0x0045, 0x0046, 0x0047,                 \
+    0x0048, 0x0049, 0x004a, 0x004b,                 \
+    0x004c, 0x004d, 0x004e, 0x004f,                 \
+                                                    \
+    0x0050, 0x0051, 0x0052, 0x0053,  /* 50 - 5f */  \
+    0x0054, 0x0055, 0x0056, 0x0057,                 \
+    0x0058, 0x0059, 0x005a, 0x005b,                 \
+    0x005c, 0x005d, 0x005e, 0x005f,                 \
+                                                    \
+    0x0060, 0x0061, 0x0062, 0x0063,  /* 60 - 6f */  \
+    0x0064, 0x0065, 0x0066, 0x0067,                 \
+    0x0068, 0x0069, 0x006a, 0x006b,                 \
+    0x006c, 0x006d, 0x006e, 0x006f,                 \
+                                                    \
+    0x0070, 0x0071, 0x0072, 0x0073,  /* 70 - 7f */  \
+    0x0074, 0x0075, 0x0076, 0x0077,                 \
+    0x0078, 0x0079, 0x007a, 0x007b,                 \
+    0x007c, 0x007d, 0x007e, 0x007f,                 \
+                                                    \
+       /* CP437 Extended ASCII range: */            \
+                                                    \
+    0x00c7, 0x00fc, 0x00e9, 0x00e2,  /*  80-8f */   \
+    0x00e4, 0x00e0, 0x00e5, 0x00e7,                 \
+    0x00ea, 0x00eb, 0x00e8, 0x00ef,                 \
+    0x00ee, 0x00ec, 0x00c4, 0x00c5,                 \
+                                                    \
+    0x00c9, 0x00e6, 0x00c6, 0x00f4,  /*  90-9f */   \
+    0x00f6, 0x00f2, 0x00fb, 0x00f9,                 \
+    0x00ff, 0x00d6, 0x00dc, 0x00a2,                 \
+    0x00a3, 0x00a5, 0x20a7, 0x0192,                 \
+                                                    \
+    0x00e1, 0x00ed, 0x00f3, 0x00fa,  /*  a0-af */   \
+    0x00f1, 0x00d1, 0x00aa, 0x00ba,                 \
+    0x00bf, 0x2310, 0x00ac, 0x00bd,                 \
+    0x00bc, 0x00a1, 0x00ab, 0x00bb,                 \
+                                                    \
+    0x2591, 0x2592, 0x2593, 0x2502,  /*  b0-bf */   \
+    0x2524, 0x2561, 0x2562, 0x2556,                 \
+    0x2555, 0x2563, 0x2551, 0x2557,                 \
+    0x255d, 0x255c, 0x255b, 0x2510,                 \
+                                                    \
+    0x2514, 0x2534, 0x252c, 0x251c,  /*  c0-cf */   \
+    0x2500, 0x253c, 0x255e, 0x255f,                 \
+    0x255a, 0x2554, 0x2569, 0x2566,                 \
+    0x2560, 0x2550, 0x256c, 0x2567,                 \
+                                                    \
+    0x2568, 0x2564, 0x2565, 0x2559,  /*  d0-df */   \
+    0x2558, 0x2552, 0x2553, 0x256b,                 \
+    0x256a, 0x2518, 0x250c, 0x2588,                 \
+    0x2584, 0x258c, 0x2590, 0x2580,                 \
+                                                    \
+    0x03b1, 0x00df, 0x0393, 0x03c0,  /*  e0-ef */   \
+    0x03a3, 0x03c3, 0x00b5, 0x03c4,                 \
+    0x03a6, 0x0398, 0x03a9, 0x03b4,                 \
+    0x221e, 0x03c6, 0x03b5, 0x2229,                 \
+                                                    \
+    0x2261, 0x00b1, 0x2265, 0x2264,  /*  f0-ff */   \
+    0x2320, 0x2321, 0x00f7, 0x2248,                 \
+    0x00b0, 0x2219, 0x00b7, 0x221a,                 \
+    0x207f, 0x00b2, 0x25a0, 0x00a0,                 \
+}
+
--- a/textscreen/txt_gui.c
+++ b/textscreen/txt_gui.c
@@ -22,51 +22,6 @@
 
 typedef struct txt_cliparea_s txt_cliparea_t;
 
-// Mapping table that converts from the Extended ASCII codes in the
-// CP437 codepage to Unicode character numbers.
-
-static const uint16_t cp437_unicode[] = {
-    0x00c7, 0x00fc, 0x00e9, 0x00e2,         // 80-8f
-    0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef,
-    0x00ee, 0x00ec, 0x00c4, 0x00c5,
-
-    0x00c9, 0x00e6, 0x00c6, 0x00f4,         // 90-9f
-    0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2,
-    0x00a3, 0x00a5, 0x20a7, 0x0192,
-
-    0x00e1, 0x00ed, 0x00f3, 0x00fa,         // a0-af
-    0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd,
-    0x00bc, 0x00a1, 0x00ab, 0x00bb,
-
-    0x2591, 0x2592, 0x2593, 0x2502,         // b0-bf
-    0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557,
-    0x255D, 0x255C, 0x255B, 0x2510,
-
-    0x2514, 0x2534, 0x252C, 0x251C,         // c0-cf
-    0x2500, 0x253C, 0x255E, 0x255F,
-    0x255A, 0x2554, 0x2569, 0x2566,
-    0x2560, 0x2550, 0x256C, 0x2567,
-
-    0x2568, 0x2564, 0x2565, 0x2559,         // d0-df
-    0x2558, 0x2552, 0x2553, 0x256B,
-    0x256A, 0x2518, 0x250C, 0x2588,
-    0x2584, 0x258C, 0x2590, 0x2580,
-
-    0x03B1, 0x00DF, 0x0393, 0x03C0,         // e0-ef
-    0x03A3, 0x03C3, 0x00B5, 0x03C4,
-    0x03A6, 0x0398, 0x03A9, 0x03B4,
-    0x221E, 0x03C6, 0x03B5, 0x2229,
-
-    0x2261, 0x00B1, 0x2265, 0x2264,         // f0-ff
-    0x2320, 0x2321, 0x00F7, 0x2248,
-    0x00B0, 0x2219, 0x00B7, 0x221A,
-    0x207F, 0x00B2, 0x25A0, 0x00A0,
-};
-
 struct txt_cliparea_s
 {
     int x1, x2;
@@ -298,51 +253,29 @@
 
 static void PutUnicodeChar(unsigned int c)
 {
-    unsigned int i;
+    int d;
 
-    if (c < 128)
+    // Treat control characters specially.
+    if (c == '\n' || c == '\b')
     {
         TXT_PutChar(c);
         return;
     }
 
-    // We can only display this character if it is in the CP437 codepage.
+    // Map Unicode character into the symbol used to represent it in this
+    // code page. For unrepresentable characters, print a fallback instead.
+    // Note that we use TXT_PutSymbol() here because we just want to do a
+    // raw write into the screen buffer.
+    d = TXT_UnicodeCharacter(c);
 
-    for (i = 0; i < 128; ++i)
+    if (d >= 0)
     {
-        if (cp437_unicode[i] == c)
-        {
-            TXT_PutChar(128 + i);
-            return;
-        }
+        TXT_PutSymbol(d);
     }
-
-    // Otherwise, print a fallback character (inverted question mark):
-
-    TXT_PutChar('\xa8');
-}
-
-int TXT_CanDrawCharacter(unsigned int c)
-{
-    unsigned int i;
-
-    // Standard ASCII range?
-    if (c < 128)
+    else
     {
-        return 1;
+        TXT_PutSymbol('\xa8');
     }
-
-    // Extended ASCII range?
-    for (i = 0; i < 128; ++i)
-    {
-        if (cp437_unicode[i] == c)
-        {
-            return 1;
-        }
-    }
-
-    // Nope.
-    return 0;
 }
 
 void TXT_DrawUTF8String(const char *s)
--- a/textscreen/txt_inputbox.c
+++ b/textscreen/txt_inputbox.c
@@ -253,7 +253,7 @@
     // Add character to the buffer, but only if it's a printable character
     // that we can represent on the screen.
     if (isprint(c)
-     || (c >= 128 && TXT_CanDrawCharacter(c)))
+     || (c >= 128 && TXT_UnicodeCharacter(c) >= 0))
     {
         AddCharacter(inputbox, c);
     }
--- a/textscreen/txt_io.c
+++ b/textscreen/txt_io.c
@@ -54,12 +54,34 @@
     }
 }
 
-static void PutChar(unsigned char *screendata, int c)
+static void PutSymbol(unsigned char *screendata, int c)
 {
     unsigned char *p;
 
     p = screendata + cur_y * TXT_SCREEN_W * 2 +  cur_x * 2;
 
+    // Add a new character to the buffer
+
+    p[0] = c;
+    p[1] = fgcolor | (bgcolor << 4);
+
+    ++cur_x;
+
+    if (cur_x >= TXT_SCREEN_W)
+    {
+        NewLine(screendata);
+    }
+}
+
+// "Blind" version of TXT_PutChar() below which doesn't do any interpretation
+// of control signals. Just write a particular symbol to the screen buffer.
+void TXT_PutSymbol(int c)
+{
+    PutSymbol(TXT_GetScreenData(), c);
+}
+
+static void PutChar(unsigned char *screendata, int c)
+{
     switch (c)
     {
         case '\n':
@@ -74,19 +96,7 @@
             break;
 
         default:
-
-            // Add a new character to the buffer
-
-            p[0] = c;
-            p[1] = fgcolor | (bgcolor << 4);
-
-            ++cur_x;
-
-            if (cur_x >= TXT_SCREEN_W) 
-            {
-                NewLine(screendata);
-            }
-
+            PutSymbol(screendata, c);
             break;
     }
 }
@@ -93,11 +103,7 @@
 
 void TXT_PutChar(int c)
 {
-    unsigned char *screen;
-
-    screen = TXT_GetScreenData();
-
-    PutChar(screen, c);
+    PutChar(TXT_GetScreenData(), c);
 }
 
 void TXT_Puts(const char *s)
--- a/textscreen/txt_io.h
+++ b/textscreen/txt_io.h
@@ -26,6 +26,7 @@
     int fgcolor;
 } txt_saved_colors_t;
 
+void TXT_PutSymbol(int c);
 void TXT_PutChar(int c);
 void TXT_Puts(const char *s);
 void TXT_GotoXY(int x, int y);
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -141,6 +141,11 @@
 // Read a character from the keyboard
 int TXT_GetChar(void);
 
+// Given a Unicode character, get a character that can be used to represent
+// it on the code page being displayed on the screen. If the character cannot
+// be represented, this returns -1.
+int TXT_UnicodeCharacter(unsigned int c);
+
 // Read the current state of modifier keys that are held down.
 int TXT_GetModifierState(txt_modifier_t mod);
 
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -45,6 +45,7 @@
 #include "fonts/small.h"
 #include "fonts/normal.h"
 #include "fonts/large.h"
+#include "fonts/codepage.h"
 
 // Time between character blinks in ms
 
@@ -72,6 +73,7 @@
 // normal_font otherwise.
 static const txt_font_t highdpi_font = { "normal-highdpi", NULL, 8, 16 };
 
+static const short code_page_to_unicode[] = CODE_PAGE_TO_UNICODE;
 static const int scancode_translate_table[] = SCANCODE_TO_KEYS_ARRAY;
 
 //#define TANGO
@@ -715,35 +717,22 @@
     }
 }
 
-// Unicode characters we allow in key names because they're in the
-// CP437 extended ASCII range.
-static const short unicode_whitelist[] = {
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00f1, 0x00e1, 0x00ed, 0x00f3, 0x00fa,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x03c6, 0x03b5, 0x2229, 0x00d1,
-};
-
-static int PrintableChar(int c)
+int TXT_UnicodeCharacter(unsigned int c)
 {
     unsigned int i;
 
-    if (c < 0x80)
-    {
-        return 1;
-    }
+    // Check the code page mapping to see if this character maps
+    // to anything.
 
-    for (i = 0; i < arrlen(unicode_whitelist); ++i)
+    for (i = 0; i < arrlen(code_page_to_unicode); ++i)
     {
-        if (unicode_whitelist[i] == c)
+        if (code_page_to_unicode[i] == c)
         {
-            return 1;
+            return i;
         }
     }
 
-    return 0;
+    return -1;
 }
 
 // Returns true if the given UTF8 key name is printable to the screen.
@@ -756,7 +745,7 @@
     while (*p != '\0')
     {
         c = TXT_DecodeUTF8(&p);
-        if (!PrintableChar(c))
+        if (TXT_UnicodeCharacter(c) < 0)
         {
             return 0;
         }