tUse UTF-8 for output in text-mode Windows client - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 4f094716ada1246cf9fb320593932bcd68526cd3
 (DIR) parent 94c1db7f281d242555fb3345ce192e1d4a0068db
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Sun, 15 Nov 2020 00:18:49 -0800
       
       Use UTF-8 for output in text-mode Windows client
       
       Make our Windows curses-like interface work with
       UTF-8 text, using Windows Unicode APIs for the actual
       output. This should make accented characters, in the
       various non-English translations, show up correctly
       regardless of which code page is set. Closes #50.
       
       Diffstat:
         M src/curses_client/curses_client.c   |       7 +++++++
         M src/cursesport/Makefile.am          |       2 +-
         M src/cursesport/cursesport.c         |      47 +++++++++++++++++++++++--------
         M src/cursesport/cursesport.h         |      28 ++++++++++++++--------------
       
       4 files changed, 58 insertions(+), 26 deletions(-)
       ---
 (DIR) diff --git a/src/curses_client/curses_client.c b/src/curses_client/curses_client.c
       t@@ -2650,6 +2650,13 @@ void CursesLoop(struct CMDLINE *cmdline)
          char c;
          Player *Play;
        
       +#ifdef CYGWIN
       +  /* On Windows, force UTF-8 rather than the non-Unicode codepage */
       +  bind_textdomain_codeset(PACKAGE, "UTF-8");
       +  Conv_SetInternalCodeset("UTF-8");
       +  WantUTF8Errors(TRUE);
       +#endif
       +
          InitConfiguration(cmdline);
          if (!CheckHighScoreFileConfig())
            return;
 (DIR) diff --git a/src/cursesport/Makefile.am b/src/cursesport/Makefile.am
       t@@ -1,4 +1,4 @@
        noinst_LIBRARIES = libcursesport.a
        libcursesport_a_SOURCES = cursesport.c cursesport.h
       -AM_CPPFLAGS= -I../../intl -I${srcdir} -I${srcdir}/.. -I../..
       +AM_CPPFLAGS= -I../../intl -I${srcdir} -I${srcdir}/.. -I../.. @GLIB_CFLAGS@
        DEFS       = @DEFS@
 (DIR) diff --git a/src/cursesport/cursesport.c b/src/cursesport/cursesport.c
       t@@ -26,6 +26,7 @@
        #endif
        
        #include "cursesport.h"
       +#include <glib.h>
        
        #ifdef CYGWIN                   /* Code for native Win32 build under Cygwin */
        
       t@@ -34,7 +35,7 @@ int COLS, LINES;
        static int Width, Depth;
        static CHAR_INFO RealScreen[25][80], VirtualScreen[25][80];
        static HANDLE hOut, hIn;
       -static WORD CurAttr = 0;
       +static int CurAttr = 0;
        static int CurX, CurY;
        static WORD Attr[10];
        
       t@@ -57,8 +58,8 @@ void refresh(void)
              screenpos.Top = y;
              screenpos.Right = Width - 1;
              screenpos.Bottom = y;
       -      WriteConsoleOutput(hOut, &VirtualScreen[y][0], size,
       -                         offset, &screenpos);
       +      WriteConsoleOutputW(hOut, &VirtualScreen[y][0], size,
       +                          offset, &screenpos);
            }
          }
        }
       t@@ -81,7 +82,7 @@ SCREEN *newterm(void *a, void *b, void *c)
        
          Width = COLS = 80;
          Depth = LINES = 25;
       -  CurAttr = 1 << 8;
       +  CurAttr = 1 << 16;
          CurX = 0;
          CurY = 0;
          for (i = 0; i < 10; i++)
       t@@ -181,7 +182,7 @@ void move(int y, int x)
          SetConsoleCursorPosition(hOut, coord);
        }
        
       -void attrset(WORD newAttr)
       +void attrset(int newAttr)
        {
          CurAttr = newAttr;
        }
       t@@ -189,21 +190,45 @@ void attrset(WORD newAttr)
        void addstr(const char *str)
        {
          int i;
       -
          for (i = 0; i < strlen(str); i++)
       -    addch(str[i]);
       +    addch((guchar)str[i]);
        }
        
       -void addch(int ch)
       +void addch(unsigned ch_and_attr)
        {
          int attr;
       +  unsigned int ch;
       +  gunichar gch;
       +  /* Keep track of a UTF-8-encoded character */
       +  static char utf8_str[4];
       +  static int utf8_width = 0;
       +  static int utf8_pos = 0;
       +
       +  ch = ch_and_attr & 0xFFFF;
       +
       +  if (ch > 0xFF || ch <= 0x7F) {
       +    /* Already Unicode (e.g. box-drawing character), or ASCII */
       +    VirtualScreen[CurY][CurX].Char.UnicodeChar = ch;
       +  } else if (ch & 64) {
       +    /* UTF-8 encoded; first byte (get the width) */
       +    utf8_width = ch & 16 ? 4 : ch & 32 ? 3 : 2;
       +    utf8_pos = 0;
       +    utf8_str[utf8_pos++] = ch;
       +    return;
       +  } else {
       +    /* UTF-8 encoded; intermediate or last byte */
       +    utf8_str[utf8_pos++] = ch;
       +    if (utf8_pos < utf8_width) return;
       +    gch = g_utf8_get_char(utf8_str);
       +    /* Windows console can only handle 2-byte Unicode */
       +    VirtualScreen[CurY][CurX].Char.UnicodeChar = gch > 0xFFFF ? '?' : gch;
       +  }
        
       -  VirtualScreen[CurY][CurX].Char.AsciiChar = ch % 256;
       -  attr = ch >> 8;
       +  attr = ch_and_attr >> 16;
          if (attr > 0)
            VirtualScreen[CurY][CurX].Attributes = Attr[attr];
          else
       -    VirtualScreen[CurY][CurX].Attributes = Attr[CurAttr >> 8];
       +    VirtualScreen[CurY][CurX].Attributes = Attr[CurAttr >> 16];
          if (++CurX >= Width) {
            CurX = 0;
            if (++CurY >= Depth)
 (DIR) diff --git a/src/cursesport/cursesport.h b/src/cursesport/cursesport.h
       t@@ -44,18 +44,18 @@ extern int COLS, LINES;
        #define COLOR_BLUE    4
        #define COLOR_RED     5
        
       -#define COLOR_PAIR(i) ((i) << 8)
       -
       -#define ACS_VLINE       179
       -#define ACS_ULCORNER    218
       -#define ACS_HLINE       196
       -#define ACS_URCORNER    191
       -#define ACS_TTEE        194
       -#define ACS_LLCORNER    192
       -#define ACS_LRCORNER    217
       -#define ACS_BTEE        193
       -#define ACS_LTEE        195
       -#define ACS_RTEE        180
       +#define COLOR_PAIR(i) ((i) << 16)
       +
       +#define ACS_VLINE       0x2502
       +#define ACS_ULCORNER    0x250c
       +#define ACS_HLINE       0x2500
       +#define ACS_URCORNER    0x2510
       +#define ACS_TTEE        0x252c
       +#define ACS_LLCORNER    0x2514
       +#define ACS_LRCORNER    0x2518
       +#define ACS_BTEE        0x2534
       +#define ACS_LTEE        0x251c
       +#define ACS_RTEE        0x2524
        
        typedef int SCREEN;
        
       t@@ -77,9 +77,9 @@ void keypad(void *, char);
        void curs_set(BOOL visible);
        void endwin(void);
        void move(int y, int x);
       -void attrset(WORD newAttr);
       +void attrset(int newAttr);
        void addstr(const char *str);
       -void addch(int ch);
       +void addch(unsigned ch);
        void mvaddstr(int x, int y, const char *str);
        void mvaddch(int x, int y, int ch);