foxygit / doom Log in
commit 40d1ce5541da78b93348f7102c05f92e8df69062
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Sat Jan 21 15:46:04 2017 +0000
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Sat Jan 21 15:46:04 2017 +0000

    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.
---
 textscreen/fonts/Makefile.am |   2 +-
 textscreen/fonts/codepage.h  | 113 +++++++++++++++++++++++++++++++++++++++++++
 textscreen/txt_gui.c         |  91 +++++-----------------------------
 textscreen/txt_inputbox.c    |   2 +-
 textscreen/txt_io.c          |  44 +++++++++--------
 textscreen/txt_io.h          |   1 +
 textscreen/txt_main.h        |   5 ++
 textscreen/txt_sdl.c         |  31 ++++--------
 8 files changed, 168 insertions(+), 121 deletions(-)

diff --git a/textscreen/fonts/Makefile.am b/textscreen/fonts/Makefile.am
index d659ff45..67ae8a21 100644
--- 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)
diff --git a/textscreen/fonts/codepage.h b/textscreen/fonts/codepage.h
new file mode 100644
index 00000000..8030ef97
--- /dev/null
+++ b/textscreen/fonts/codepage.h
@@ -0,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,                 \
+}
+
diff --git a/textscreen/txt_gui.c b/textscreen/txt_gui.c
index bc7017a8..c85f3b8a 100644
--- 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 @@ void TXT_DrawString(const char *s)

 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.
-
-    for (i = 0; i < 128; ++i)
-    {
-        if (cp437_unicode[i] == c)
-        {
-            TXT_PutChar(128 + i);
-            return;
-        }
-    }
-
-    // Otherwise, print a fallback character (inverted question mark):
+    // 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);

-    TXT_PutChar('\xa8');
-}
-
-int TXT_CanDrawCharacter(unsigned int c)
-{
-    unsigned int i;
-
-    // Standard ASCII range?
-    if (c < 128)
+    if (d >= 0)
     {
-        return 1;
+        TXT_PutSymbol(d);
     }
-
-    // Extended ASCII range?
-    for (i = 0; i < 128; ++i)
+    else
     {
-        if (cp437_unicode[i] == c)
-        {
-            return 1;
-        }
+        TXT_PutSymbol('\xa8');
     }
-
-    // Nope.
-    return 0;
 }

 void TXT_DrawUTF8String(const char *s)
diff --git a/textscreen/txt_inputbox.c b/textscreen/txt_inputbox.c
index 2e3a5d0c..923bda9c 100644
--- a/textscreen/txt_inputbox.c
+++ b/textscreen/txt_inputbox.c
@@ -253,7 +253,7 @@ static int TXT_InputBoxKeyPress(TXT_UNCAST_ARG(inputbox), int key)
     // 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);
     }
diff --git a/textscreen/txt_io.c b/textscreen/txt_io.c
index 0c5e274f..44ffa382 100644
--- a/textscreen/txt_io.c
+++ b/textscreen/txt_io.c
@@ -54,12 +54,34 @@ static void NewLine(unsigned char *screendata)
     }
 }

-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,30 +96,14 @@ static void PutChar(unsigned char *screendata, int c)
             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;
     }
 }

 void TXT_PutChar(int c)
 {
-    unsigned char *screen;
-
-    screen = TXT_GetScreenData();
-
-    PutChar(screen, c);
+    PutChar(TXT_GetScreenData(), c);
 }

 void TXT_Puts(const char *s)
diff --git a/textscreen/txt_io.h b/textscreen/txt_io.h
index 55f56167..54a5e0e6 100644
--- a/textscreen/txt_io.h
+++ b/textscreen/txt_io.h
@@ -26,6 +26,7 @@ typedef struct
     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);
diff --git a/textscreen/txt_main.h b/textscreen/txt_main.h
index 7abc6f1b..b92869d0 100644
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -141,6 +141,11 @@ void TXT_UpdateScreen(void);
 // 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);

diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c
index 2162275b..b6b4e5de 100644
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -45,6 +45,7 @@ typedef struct
 #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 @@ static const txt_font_t *font;
 // 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 @@ int TXT_GetModifierState(txt_modifier_t mod)
     }
 }

-// 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 @@ static int PrintableName(const char *s)
     while (*p != '\0')
     {
         c = TXT_DecodeUTF8(&p);
-        if (!PrintableChar(c))
+        if (TXT_UnicodeCharacter(c) < 0)
         {
             return 0;
         }