Convert ancient encodings on the game's output.

Neither old Crawl nor NetHack accept non-ASCII input, so I didn't bother
    implementing that.
    (Adam Borowski <kilobyte@angband.pl>)


git-svn-id: svn://katsu.triplehelix.org/dgamelaunch/trunk@598 db0b04b0-f4d1-0310-9a6d-de3e77497b0e
This commit is contained in:
Pasi Kallinen 2011-10-03 15:28:49 +00:00
parent 47cfe66d43
commit d497cb4529
1 changed files with 180 additions and 7 deletions

187
ttyrec.c
View File

@ -62,6 +62,7 @@
# include <stropts.h>
#endif
#include <stdlib.h>
#include <stdint.h>
#include "ttyrec.h"
#include "io.h"
@ -84,6 +85,8 @@ int master;
struct termios tt;
struct winsize win;
int ancient_encoding = 0;
void
ttyrec_id(int game, char *username, char *ttyrec_filename)
{
@ -151,6 +154,7 @@ ttyrec_main (int game, char *username, char *ttyrec_path, char* ttyrec_filename)
snprintf (dirname, 100, "%s%s", ttyrec_path, ttyrec_filename);
else
snprintf (dirname, 100, "%s/%s", ttyrec_path, ttyrec_filename);
ancient_encoding = myconfig[game]->encoding;
atexit(&remove_ipfile);
if ((fscript = fopen (dirname, "w")) == NULL)
@ -258,12 +262,119 @@ game_idle_kill(int signal)
kill(dgl_parent, SIGHUP);
}
static unsigned short charset_vt100[128] =
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
#if 0
0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0xf800,
0xf801, 0x2500, 0xf803, 0xf804, 0x251c, 0x2524, 0x2534, 0x252c,
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
#endif
0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020,
};
static unsigned short charset_cp437[256] =
{
// Real IBM charset has no control codes, but they are needed by
// terminals.
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
#if 0
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
#endif
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
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, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
};
// there must be at least 4 bytes free, NOT CHECKED!
static int wctoutf8(char *d, uint32_t s)
{
if (s < 0x80)
{
d[0] = s;
return 1;
}
if (s < 0x800)
{
d[0] = ( s >> 6) | 0xc0;
d[1] = ( s & 0x3f) | 0x80;
return 2;
}
if (s < 0x10000)
{
d[0] = ( s >> 12) | 0xe0;
d[1] = ((s >> 6) & 0x3f) | 0x80;
d[2] = ( s & 0x3f) | 0x80;
return 3;
}
if (s < 0x110000)
{
d[0] = ( s >> 18) | 0xf0;
d[1] = ((s >> 12) & 0x3f) | 0x80;
d[2] = ((s >> 6) & 0x3f) | 0x80;
d[3] = ( s & 0x3f) | 0x80;
return 4;
}
// Invalid char marker (U+FFFD).
d[0] = 0xef;
d[1] = 0xbf;
d[2] = 0xbd;
return 3;
}
void
dooutput (int max_idle_time)
{
int cc;
int cc, i, len;
time_t tvec, time ();
char obuf[BUFSIZ], *ctime ();
char obuf[BUFSIZ], ubuf[BUFSIZ*4+2], *ctime (), *out;
int galt = 0; // vt100 G switch
setbuf (stdout, NULL);
(void) close (0);
@ -281,11 +392,73 @@ dooutput (int max_idle_time)
if (max_idle_time)
alarm(max_idle_time);
h.len = cc;
gettimeofday (&h.tv, NULL);
(void) write (1, obuf, cc);
(void) write_header (fscript, &h);
(void) fwrite (obuf, 1, cc, fscript);
switch (ancient_encoding)
{
case 0: // UTF-8
default:
h.len = cc;
gettimeofday (&h.tv, NULL);
(void) write (1, obuf, cc);
(void) write_header (fscript, &h);
(void) fwrite (obuf, 1, cc, fscript);
break;
case 1: // IBM
out = ubuf;
// Old Crawl emits useless toggles of vt100 mode, even though it
// never uses them in this mode. And they break stuff...
for (i = 0; i < cc; i++)
{
if (galt == 2) // ignore "ESC ( 0", "ESC ( B" and anything such
{
galt = 0;
continue;
}
else if (galt == 1)
if (obuf[i] == '(')
{
galt = 2;
continue;
}
else
{
galt = 0; // false alarm, emit ESC and continue
*out ++ = 27;
}
else if (obuf[i] == 27)
{
galt = 1;
continue;
}
out += wctoutf8(out, charset_cp437[(unsigned char)obuf[i]]);
}
h.len = len = out - ubuf;
gettimeofday(&h.tv, NULL);
write(1, ubuf, len);
write_header(fscript, &h);
fwrite(ubuf, 1, len, fscript);
break;
case 2: // DEC
out = ubuf;
for (i = 0; i < cc; i++)
{
if (obuf[i] == 14)
galt = 1;
else if (obuf[i] == 15)
galt = 0;
else if (obuf[i] & 0x80) // strictly 7-bit
out += wctoutf8(out, 0xFFFD); // or we could assume some other charset
else if (galt)
out += wctoutf8(out, charset_vt100[(int)obuf[i]]);
else
*out++ = obuf[i];
}
h.len = len = out - ubuf;
gettimeofday(&h.tv, NULL);
write(1, ubuf, len);
write_header(fscript, &h);
fwrite(ubuf, 1, len, fscript);
break;
}
}
done ();
}