[experimental] Unicode mode

This adds "Unicode mode", in which scenarios can be written in any
language. xsys35c 1.2.0 and later can produce Unicode scenarios.

- nact->encoding represents the current scenario encoding. The initial
  value is SJIS, and ZU command changes it to UTF8.

- Use conversion macros that switch the behavior by the scenario
  encoding. For example, toUTF8() calls sjis2utf() if the scenario
  encoding is SJIS, and calls strdup() if it is UTF8.

- Fix various string processing functions to work with UTF8.
This commit is contained in:
kichikuou
2020-08-09 21:24:56 +09:00
parent d8fbf9a8b1
commit bc9fc924ed
22 changed files with 379 additions and 110 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ void ntmsg_init() {
// 主人公名前
nt_sstr_regist_replace(utf2sjis(SNAME_RYO), utf2sjis(SNAME_RYO_DEF));
nt_sstr_regist_replace(fromUTF8(SNAME_RYO), fromUTF8(SNAME_RYO_DEF));
night.msg.cbmove = cb_mousemove;
night.msg.cbrelease = cb_keyrelease;
+5 -5
View File
@@ -43,7 +43,7 @@
#define LOGMSG_LINES 6
static const char *logmsg[LOGMSG_LINES] = {
static const char *logmsg_utf8[LOGMSG_LINES] = {
"\n",
"※バックログ操作方法※",
"[ESC]またはマウス右クリックでゲームに戻る",
@@ -110,15 +110,15 @@ static void draw_log() {
int sblog_start(void) {
static char *logmsg_sjis[6];
if (!logmsg_sjis[0]) {
static char *logmsg[LOGMSG_LINES];
if (!logmsg[0]) {
for (int i = 0; i < LOGMSG_LINES; i++)
logmsg_sjis[i] = utf2sjis(logmsg[i]);
logmsg[i] = fromUTF8(logmsg_utf8[i]);
}
// 説明文章を追加
for (int i = 0; i < LOGMSG_LINES; i++)
sact.log = list_append(sact.log, logmsg_sjis[i]);
sact.log = list_append(sact.log, logmsg[i]);
back = sf_dup(sf0);
chr = sf_create_surface(sf0->width, sf0->height, 8);
+7 -7
View File
@@ -186,16 +186,16 @@ void ags_setViewArea(int x, int y, int width, int height) {
void ags_setWindowTitle(const char *src) {
#define TITLEHEAD "XSystem35 Version "VERSION":"
BYTE *dst, *d;
BYTE *utf, *d;
dst = sjis2utf(src);
if (NULL == (d = malloc(strlen(dst) + strlen(TITLEHEAD) + 1))) {
utf = toUTF8(src);
if (NULL == (d = malloc(strlen(utf) + strlen(TITLEHEAD) + 1))) {
NOMEMERR();
}
strcpy(d, TITLEHEAD);
strcat(d, dst);
strcat(d, utf);
SetWindowTitle(d);
free(dst);
free(utf);
free(d);
}
@@ -402,7 +402,7 @@ int ags_drawString(int x, int y, const char *src, int col) {
if (!check_param_xy(&x, &y)) return 0;
DspDeviceSync();
char *utf8 = sjis2utf(src);
char *utf8 = toUTF8(src);
w = DrawString(x, y, utf8, col);
free(utf8);
@@ -410,7 +410,7 @@ int ags_drawString(int x, int y, const char *src, int col) {
}
agsurface_t *ags_drawStringToSurface(const char *str) {
char *utf8 = sjis2utf(str);
char *utf8 = toUTF8(str);
agsurface_t *sf = nact->ags.font->get_glyph(utf8);
free(utf8);
return sf;
+16 -16
View File
@@ -367,7 +367,7 @@ void commands2F23() {
int y = getCaliValue();
char *vFileName = sys_getString(0);
char *fname_utf8 = sjis2utf(vFileName);
char *fname_utf8 = toUTF8(vFileName);
sysVar[0] = cg_load_with_filename(fname_utf8, x, y);
free(fname_utf8);
@@ -380,7 +380,7 @@ void commands2F24() {
int *var = NULL, _var = 0;
int num = 0;
char *fname_utf8 = sjis2utf(file_name);
char *fname_utf8 = toUTF8(file_name);
switch(type) {
case 0:
var = getCaliVariable();
@@ -412,8 +412,8 @@ void commands2F26() {
char *title = sys_getString(0);
char *t1, *t2, *t3;
t1 = sjis2utf(title);
t2 = sjis2utf(v_str(dst_no -1));
t1 = toUTF8(title);
t2 = toUTF8(v_str(dst_no -1));
mi_param.title = t1;
mi_param.oldstring = t2;
@@ -426,10 +426,10 @@ void commands2F26() {
return;
}
t3 = utf2sjis(mi_param.newstring);
t3 = fromUTF8(mi_param.newstring);
/* 全角文字以外は不可 */
if (!sjis_has_hankaku(t3)) {
if (nact->encoding != SHIFT_JIS || !sjis_has_hankaku(t3)) {
v_strcpy(dst_no -1, t3);
}
free(t1);
@@ -457,7 +457,7 @@ void commands2F28() {
if (nact->game_title_utf8)
free(nact->game_title_utf8);
nact->game_title_utf8 = sjis2utf(title);
nact->game_title_utf8 = toUTF8(title);
ags_setWindowTitle(title);
@@ -478,7 +478,7 @@ void commands2F29() {
if (ni_param.title != NULL) {
free(ni_param.title);
}
t = sjis2utf(title);
t = toUTF8(title);
ni_param.title = t;
DEBUG_COMMAND("NT(new) %s:\n", title);
@@ -489,7 +489,7 @@ void commands2F2A() {
char *file_name = sys_getString(0);
int *var, _var = 0, cnt;
char *fname_utf8 = sjis2utf(file_name);
char *fname_utf8 = toUTF8(file_name);
switch(type) {
case 0:
var = getCaliVariable();
@@ -924,8 +924,8 @@ void commands2F57() {
char *t1, *t2, *t3;
INPUTSTRING_PARAM p;
t1 = sjis2utf(sTitle);
t2 = sjis2utf(v_str(eStrVar -1));
t1 = toUTF8(sTitle);
t2 = toUTF8(v_str(eStrVar -1));
p.title = t1;
p.oldstring = t2;
p.max = eLength;
@@ -934,10 +934,10 @@ void commands2F57() {
if (p.newstring == NULL) {
*vResult = 65535;
} else {
t3 = utf2sjis(p.newstring);
if (!sjis_has_hankaku(t3)) {
t3 = fromUTF8(p.newstring);
if (nact->encoding != SHIFT_JIS || !sjis_has_hankaku(t3)) {
v_strcpy(eStrVar -1, t3);
*vResult = sjis_count_char(t3);
*vResult = v_strlen(eStrVar -1);
} else {
*vResult = 65535;
}
@@ -971,7 +971,7 @@ void commands2F5A() {
char *sText = sys_getString(0);
char *t1;
t1 = sjis2utf(sText);
t1 = toUTF8(sText);
menu_msgbox_open(t1);
free(t1);
@@ -982,7 +982,7 @@ void commands2F5B() {
int eNum = getCaliValue();
char *t1;
t1 = sjis2utf(v_str(eNum) - 1);
t1 = toUTF8(v_str(eNum) - 1);
menu_msgbox_open(t1);
free(t1);
+2
View File
@@ -1098,6 +1098,8 @@ void check_command(int c0) {
undeferr();
}
break;
case 'U':
commandZU(); break;
case 'Z':
switch(sl_getc()) {
case 0:
+1
View File
@@ -304,6 +304,7 @@ extern void commandZI();
extern void commandZA();
extern void commandZK();
extern void commandZR();
extern void commandZU();
/* define in cmd2F.c */
extern void commands2F00();
+5 -1
View File
@@ -22,9 +22,11 @@
/* $Id: cmdh.c,v 1.5 2000/09/10 10:39:48 chikama Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portab.h"
#include "xsystem35.h"
#include "utfsjis.h"
#include "hankaku.h"
void commandH() {
@@ -32,7 +34,9 @@ void commandH() {
int num = getCaliValue();
char buf[512];
sys_addMsg(format_number_zenkaku(num, fig, buf));
char *s = fromSJIS(format_number_zenkaku(num, fig, buf));
sys_addMsg(s);
free(s);
DEBUG_COMMAND("H %d,%d:\n",fig,num);
}
+2 -2
View File
@@ -112,7 +112,7 @@ void commandLE() {
int *var, _var = 0;
int num;
char *fname_utf8 = sjis2utf(filename);
char *fname_utf8 = toUTF8(filename);
switch(type) {
case 0: /* T2 */
var = getCaliVariable();
@@ -246,7 +246,7 @@ void commandLC() {
int y = getCaliValue();
char *filename = sys_getString(':');
char *fname_utf8 = sjis2utf(filename);
char *fname_utf8 = toUTF8(filename);
sysVar[0] = cg_load_with_filename(fname_utf8, x, y);
free(fname_utf8);
+20 -15
View File
@@ -62,34 +62,37 @@ void commandMP() {
/* 指定の文字列を指定文字数だけ表示する(Xコマンドの桁数指定) */
int num1 = getCaliValue();
int num2 = getCaliValue();
const char bstr[3] = "\x81\x40"; // full-width whitespace
const char *fullwidth_blank[CHARACTER_ENCODING_MAX + 1] = {
[SHIFT_JIS] = "\x81\x40",
[UTF8] = " ",
};
const char *src = v_str(num1 - 1);
int chars = num2;
char *str;
/* Patched English executable appends num2 spaces instead of truncating */
if (have_eng_mp_patch) {
str = calloc(strlen(src) + num2 * 2 + 1, 1);
str = calloc(strlen(src) + num2 * strlen(fullwidth_blank[nact->encoding]) + 1, 1);
if (NULL == str) {
NOMEMERR();
}
strcpy(str, src);
}
else {
str = calloc(num2 * 2 + 1, 1);
str = calloc(num2 * MAX_BYTES_PAR_CHAR(nact->encoding) + 1, 1);
if (NULL == str) {
NOMEMERR();
}
const char *p = src;
while (*p && chars > 0) {
p += CHECKSJIS1BYTE(*p) ? 2 : 1;
p = advance_char(p, nact->encoding);
chars--;
}
strncpy(str, src, p - src);
}
while (chars-- > 0) {
strcat(str, bstr);
strcat(str, fullwidth_blank[nact->encoding]);
}
sys_addMsg(str);
@@ -105,8 +108,8 @@ void commandMI() { /* T2 */
char *title = sys_getString(':');
char *t1, *t2, *t3;
t1 = sjis2utf(title);
t2 = sjis2utf(v_str(dst_no -1));
t1 = toUTF8(title);
t2 = toUTF8(v_str(dst_no -1));
mi_param.title = t1;
mi_param.oldstring = t2;
@@ -119,10 +122,10 @@ void commandMI() { /* T2 */
return;
}
t3 = utf2sjis(mi_param.newstring);
t3 = fromUTF8(mi_param.newstring);
/* 全角文字以外は不可 */
if (!sjis_has_hankaku(t3)) {
if (nact->encoding != SHIFT_JIS ||!sjis_has_hankaku(t3)) {
v_strcpy(dst_no -1, t3);
}
free(t1);
@@ -163,7 +166,7 @@ void commandMT() {
if (nact->game_title_utf8)
free(nact->game_title_utf8);
nact->game_title_utf8 = sjis2utf(str);
nact->game_title_utf8 = toUTF8(str);
ags_setWindowTitle(str);
/* 闘神都市II 対策 */
@@ -197,7 +200,9 @@ void commandMH() {
int num2 = getCaliValue();
char buf[512];
v_strcpy(num1 - 1, format_number_zenkaku(num2, fig, buf));
char *s = fromSJIS(format_number_zenkaku(num2, fig, buf));
v_strcpy(num1 - 1, s);
free(s);
DEBUG_COMMAND("MH %d,%d,%d:\n",num1,fig,num2);
}
@@ -215,7 +220,7 @@ void commandML() {
int *var = getCaliVariable();
int str_no = getCaliValue();
*var = sjis_count_char(v_str(str_no -1));
*var = v_strlen(str_no -1);
DEBUG_COMMAND("ML %p,%d:\n",var, str_no);
}
@@ -338,7 +343,7 @@ void commandMJ() {
INPUTSTRING_PARAM mj_param;
char *t1, *t2;
t1 = sjis2utf(v_str(num -1));
t1 = toUTF8(v_str(num -1));
mj_param.max = max_len;
mj_param.x = x;
mj_param.y = y;
@@ -349,8 +354,8 @@ void commandMJ() {
menu_inputstring2(&mj_param);
if (mj_param.newstring == NULL) return;
t2 = utf2sjis(mj_param.newstring);
if (!sjis_has_hankaku(t2)) {
t2 = fromUTF8(mj_param.newstring);
if (nact->encoding != SHIFT_JIS || !sjis_has_hankaku(t2)) {
v_strcpy(num -1, t2);
}
free(t1);
+2 -6
View File
@@ -375,13 +375,9 @@ void commandNI() { /* From Panyo */
void commandNT() { /* From Panyo */
/* NIコマンドで表示するタイトルを設定する。*/
char *str = sys_getString(':');
char *t;
if (ni_param.title != NULL) {
free(ni_param.title);
}
t = sjis2utf(str);
ni_param.title = t;
free(ni_param.title);
ni_param.title = toUTF8(str);
DEBUG_COMMAND("NT %p:\n", str);
}
+1 -1
View File
@@ -87,7 +87,7 @@ void commandQE() {
char *filename = sys_getString(':');
int *var, _var = 0, cnt;
char *fname_utf8 = sjis2utf(filename);
char *fname_utf8 = toUTF8(filename);
switch(type) {
case 0:
var = getCaliVariable();
+10
View File
@@ -525,3 +525,13 @@ void commandZR() {
DEBUG_COMMAND("ZR %d,%d:\n", num, *var);
}
void commandZU() {
/* xsystem35 extension: sets unicode mode */
int sw = getCaliValue();
if (sw <= CHARACTER_ENCODING_MAX)
sys_setCharacterEncoding(sw);
DEBUG_COMMAND("ZU %d:\n",sw);
}
+1 -29
View File
@@ -34,6 +34,7 @@
#include "system.h"
#include "font.h"
#include "ags.h"
#include "utfsjis.h"
extern const unsigned short *s2u[];
@@ -59,35 +60,6 @@ static FONT *this;
static void pixmap2comimg(BYTE *src, int x, int y, int w, int h, int src_bpl);
static void pixmapmono2comimg(BYTE *src, int x, int y, int w, int h, int src_bpl);
static int utf8_next_codepoint(const char **msg) {
int code;
const unsigned char *s = (const unsigned char *)*msg;
if (*s <= 0x7f) {
code = *s++;
} else if (*s <= 0xbf) {
WARNING("Invalid UTF-8 sequence %02x\n", *s);
code = '?';
s++;
} else if (*s <= 0xdf) {
code = (s[0] & 0x1f) << 6 | (s[1] & 0x3f);
s += 2;
} else if (*s <= 0xef) {
code = (s[0] & 0xf) << 12 | (s[1] & 0x3f) << 6 | (s[2] & 0x3f);
s += 3;
} else if (*s <= 0xf7) {
code = (s[0] & 0x7) << 18 | (s[1] & 0x3f) << 12 | (s[2] & 0x3f) << 6 | (s[3] & 0x3f);
s += 4;
} else {
code = 0xfffd; // REPLACEMENT CHARACTER
s++;
while (0x80 <= *s && *s <= 0xbf)
s++;
}
*msg = (const char *)s;
return code;
}
static boolean select_charmap(FT_Face f, int type) {
int i;
+196 -2
View File
@@ -140,7 +140,7 @@ static const char zenkaku_digits[][3] = {
0x81,0x40,0x00, /* space */
};
BYTE *zen2han(const BYTE *src) {
static BYTE *zen2han_sjis(const BYTE *src) {
BYTE c0, c1;
char *dst, *_dst;
@@ -173,7 +173,201 @@ BYTE *zen2han(const BYTE *src) {
return _dst;
}
BYTE *han2zen(const BYTE *src) {
static char *zen2han_utf8(const char *src) {
char *dst, *_dst;
dst = _dst = malloc(strlen(src) + 1);
if (dst == NULL) {
fprintf(stderr, "zen2han(): Out of Memory (size %zu)", strlen(src) + 1);
return NULL;
}
const char *p = src;
while (*p) {
const char *prev = p;
switch (utf8_next_codepoint(&p)) {
case L'': *dst++ = '\''; break;
case L'': *dst++ = '"'; break;
case L' ': *dst++ = ' '; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, "ソ"); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': strcpy(dst, ""); dst += 3; break;
case L'': *dst++ = '!'; break;
case L'': *dst++ = '#'; break;
case L'': *dst++ = '$'; break;
case L'': *dst++ = '%'; break;
case L'': *dst++ = '&'; break;
case L'': *dst++ = '('; break;
case L'': *dst++ = ')'; break;
case L'': *dst++ = '*'; break;
case L'': *dst++ = '+'; break;
case L'': *dst++ = ','; break;
case L'': *dst++ = '-'; break;
case L'': *dst++ = '.'; break;
case L'': *dst++ = '/'; break;
case L'': *dst++ = '0'; break;
case L'': *dst++ = '1'; break;
case L'': *dst++ = '2'; break;
case L'': *dst++ = '3'; break;
case L'': *dst++ = '4'; break;
case L'': *dst++ = '5'; break;
case L'': *dst++ = '6'; break;
case L'': *dst++ = '7'; break;
case L'': *dst++ = '8'; break;
case L'': *dst++ = '9'; break;
case L'': *dst++ = ':'; break;
case L'': *dst++ = ';'; break;
case L'': *dst++ = '<'; break;
case L'': *dst++ = '='; break;
case L'': *dst++ = '>'; break;
case L'': *dst++ = '?'; break;
case L'': *dst++ = '@'; break;
case L'': *dst++ = 'A'; break;
case L'': *dst++ = 'B'; break;
case L'': *dst++ = 'C'; break;
case L'': *dst++ = 'D'; break;
case L'': *dst++ = 'E'; break;
case L'': *dst++ = 'F'; break;
case L'': *dst++ = 'G'; break;
case L'': *dst++ = 'H'; break;
case L'': *dst++ = 'I'; break;
case L'': *dst++ = 'J'; break;
case L'': *dst++ = 'K'; break;
case L'': *dst++ = 'L'; break;
case L'': *dst++ = 'M'; break;
case L'': *dst++ = 'N'; break;
case L'': *dst++ = 'O'; break;
case L'': *dst++ = 'P'; break;
case L'': *dst++ = 'Q'; break;
case L'': *dst++ = 'R'; break;
case L'': *dst++ = 'S'; break;
case L'': *dst++ = 'T'; break;
case L'': *dst++ = 'U'; break;
case L'': *dst++ = 'V'; break;
case L'': *dst++ = 'W'; break;
case L'': *dst++ = 'X'; break;
case L'': *dst++ = 'Y'; break;
case L'': *dst++ = 'Z'; break;
case L'': *dst++ = '['; break;
case L'': *dst++ = ']'; break;
case L'': *dst++ = '^'; break;
case L'_': *dst++ = '_'; break;
case L'': *dst++ = '`'; break;
case L'': *dst++ = 'a'; break;
case L'': *dst++ = 'b'; break;
case L'': *dst++ = 'c'; break;
case L'': *dst++ = 'd'; break;
case L'': *dst++ = 'e'; break;
case L'': *dst++ = 'f'; break;
case L'': *dst++ = 'g'; break;
case L'': *dst++ = 'h'; break;
case L'': *dst++ = 'i'; break;
case L'': *dst++ = 'j'; break;
case L'': *dst++ = 'k'; break;
case L'': *dst++ = 'l'; break;
case L'': *dst++ = 'm'; break;
case L'': *dst++ = 'n'; break;
case L'': *dst++ = 'o'; break;
case L'': *dst++ = 'p'; break;
case L'': *dst++ = 'q'; break;
case L'': *dst++ = 'r'; break;
case L'': *dst++ = 's'; break;
case L'': *dst++ = 't'; break;
case L'': *dst++ = 'u'; break;
case L'': *dst++ = 'v'; break;
case L'': *dst++ = 'w'; break;
case L'': *dst++ = 'x'; break;
case L'': *dst++ = 'y'; break;
case L'': *dst++ = 'z'; break;
case L'': *dst++ = '{'; break;
case L'': *dst++ = '|'; break;
case L'': *dst++ = '}'; break;
case L'': *dst++ = '~'; break;
case L'': *dst++ = '\\'; break;
default:
while (prev < p)
*dst++ = *prev++;
break;
}
}
*dst = 0;
return _dst;
}
BYTE *zen2han(const BYTE *src, CharacterEncoding enc) {
switch (enc) {
case SHIFT_JIS:
return zen2han_sjis(src);
case UTF8:
return zen2han_utf8(src);
default:
return (BYTE *)src;
}
}
BYTE *han2zen(const BYTE *src, CharacterEncoding enc) {
if (enc != SHIFT_JIS)
return (BYTE *)src; // Not implemented
BYTE c0;
BYTE *dst, *_dst;
dst = _dst = malloc(strlen(src) * 2 + 1);
+3 -2
View File
@@ -24,9 +24,10 @@
#define __HANKAKU_H__
#include "portab.h"
#include "utfsjis.h"
extern BYTE *zen2han(const BYTE *src);
extern BYTE *han2zen(const BYTE *src);
extern BYTE *zen2han(const BYTE *src, CharacterEncoding enc);
extern BYTE *han2zen(const BYTE *src, CharacterEncoding enc);
extern char *format_number(int n, int width, char *buf);
extern char *format_number_zenkaku(int n, int width, char *buf);
+4 -2
View File
@@ -52,9 +52,11 @@ static void zen2han_test(void) {
"ベペボポヮヰヱヴヵヶΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩα"
"βγδεζηθικλμνξοπρστυφχψω";
for (const Zen2hanTestCase *tc = testcases; tc->zen; tc++) {
ASSERT_STRCMP(sjis2utf(zen2han(utf2sjis(tc->zen))), tc->han);
ASSERT_STRCMP(sjis2utf(zen2han(utf2sjis(tc->zen), SHIFT_JIS)), tc->han);
ASSERT_STRCMP(zen2han(tc->zen, UTF8), tc->han);
}
ASSERT_STRCMP(sjis2utf(zen2han(utf2sjis(unconvertable))), unconvertable);
ASSERT_STRCMP(sjis2utf(zen2han(utf2sjis(unconvertable), SHIFT_JIS)), unconvertable);
ASSERT_STRCMP(zen2han(unconvertable, UTF8), unconvertable);
}
static void format_number_test(void) {
+5 -2
View File
@@ -326,11 +326,14 @@ void msg_getMessageLocation(MyPoint *loc) {
void msg_hitAnyKey() {
int w;
static BYTE hak[] = {0x81, 0xa5, 0x00}; /* ▼ */
const char *prompt[CHARACTER_ENCODING_MAX + 1] = {
[SHIFT_JIS] = "\x81\xa5",
[UTF8] = "",
};
w = ags_drawString(msg.win->x + msg.win->width - msg.MsgFontSize,
msg.win->y + msg.win->height - msg.MsgFontSize,
hak, msg.HitAnyKeyMsgColor);
prompt[nact->encoding], msg.HitAnyKeyMsgColor);
ags_updateArea(msg.win->x + msg.win->width - msg.MsgFontSize,
msg.win->y + msg.win->height - msg.MsgFontSize,
w, msg.MsgFontSize);
+11 -5
View File
@@ -70,6 +70,10 @@ void sys_setHankakuMode(int mode) {
msg_msgHankakuMode = mode;
}
void sys_setCharacterEncoding(CharacterEncoding encoding) {
nact->encoding = encoding;
}
/* 文字列の取り出し */
char *sys_getString(char term) {
int c0;
@@ -103,9 +107,9 @@ void sys_addMsg(const char *str) {
switch(msg_msgHankakuMode) {
case 0:
msg = han2zen(str); break;
msg = han2zen(str, nact->encoding); break;
case 1:
msg = zen2han(str); break;
msg = zen2han(str, nact->encoding); break;
case 2:
msg = str; break;
default:
@@ -126,7 +130,7 @@ void sys_addMsg(const char *str) {
}
}
if (msg && msg_msgHankakuMode < 2) {
if (msg != str) {
free((char *)msg);
}
}
@@ -136,8 +140,10 @@ static int checkMessage() {
char *index = msgbuf;
int c0 = sl_getc();
while (c0 == 0x20 || c0 > 0x80) {
if (c0 == 0x20) {
while (c0 == 0x20 || c0 >= 0x80) {
if (nact->encoding == UTF8) {
*index++ = (char)c0;
} else if (c0 == 0x20) {
*index++ = (char)c0;
} else if (c0 >= 0xe0) {
*index++ = (char)c0; *index++ = (char)sl_getc();
+8
View File
@@ -32,6 +32,12 @@
#include "selection.h"
#include "message.h"
#include "ags.h"
#include "utfsjis.h"
#define toUTF8(s) codeconv(UTF8, nact->encoding, s)
#define toSJIS(s) codeconv(SHIFT_JIS, nact->encoding, s)
#define fromUTF8(s) codeconv(nact->encoding, UTF8, s)
#define fromSJIS(s) codeconv(nact->encoding, SHIFT_JIS, s)
/* コマンド解析時に参照する */
#define sys_getc sl_getc
@@ -46,6 +52,7 @@ extern int *getVariable();
extern char *sys_getString(char term);
extern void sys_addMsg(const char *str);
extern void sys_setHankakuMode(int mode);
extern void sys_setCharacterEncoding(CharacterEncoding encoding);
extern char *sys_getConstString();
// extern boolean sys_nact_engine();
@@ -61,6 +68,7 @@ typedef struct {
boolean is_message_locked; /* pointer 等の event handler を呼び出さない */
boolean popupmenu_opened; /* popup menu が 開いているか */
boolean mmx_is_ok; /* MMX が有効かどうか */
CharacterEncoding encoding;
char *game_title_utf8;
int scenario_version;
+50 -10
View File
@@ -33,6 +33,18 @@
#include "utfsjis.h"
#include "s2utbl.h"
char* codeconv(CharacterEncoding tocode,
CharacterEncoding fromcode,
const char *str) {
if (tocode == fromcode)
return strdup(str);
if (tocode == UTF8 && fromcode == SHIFT_JIS)
return (char *)sjis2utf((char *)str);
if (tocode == SHIFT_JIS && fromcode == UTF8)
return (char *)utf2sjis((char *)str);
return NULL;
}
BYTE *sjis2utf(const BYTE *src) {
BYTE* dst = malloc(strlen(src) * 3 + 1);
BYTE* dstp = dst;
@@ -147,15 +159,43 @@ boolean sjis_has_zenkaku(const BYTE *src) {
return FALSE;
}
/* src 中の文字数を数える 全角文字も1文字 */
int sjis_count_char(const BYTE *src) {
int c = 0;
while(*src) {
if (CHECKSJIS1BYTE(*src)) {
src++;
}
c++; src++;
int utf8_next_codepoint(const char **msg) {
int code;
const unsigned char *s = (const unsigned char *)*msg;
if (*s <= 0x7f) {
code = *s++;
} else if (*s <= 0xbf) {
// Invalid UTF-8 sequence
code = '?';
s++;
} else if (*s <= 0xdf) {
code = (s[0] & 0x1f) << 6 | (s[1] & 0x3f);
s += 2;
} else if (*s <= 0xef) {
code = (s[0] & 0xf) << 12 | (s[1] & 0x3f) << 6 | (s[2] & 0x3f);
s += 3;
} else if (*s <= 0xf7) {
code = (s[0] & 0x7) << 18 | (s[1] & 0x3f) << 12 | (s[2] & 0x3f) << 6 | (s[3] & 0x3f);
s += 4;
} else {
code = 0xfffd; // REPLACEMENT CHARACTER
s++;
while (0x80 <= *s && *s <= 0xbf)
s++;
}
return c;
*msg = (const char *)s;
return code;
}
char *advance_char(const char *s, CharacterEncoding e) {
switch (e) {
case SHIFT_JIS:
return (char *)s + ((CHECKSJIS1BYTE(*s) && *(s + 1)) ? 2 : 1);
case UTF8:
while (UTF8_TRAIL_BYTE(*++s))
;
return (char *)s;
}
return NULL;
}
+19 -1
View File
@@ -26,12 +26,30 @@
#include "portab.h"
typedef enum {
SHIFT_JIS,
UTF8,
CHARACTER_ENCODING_MAX = UTF8
} CharacterEncoding;
#define MAX_SJIS_BYTES_PAR_CHAR 2
#define MAX_UTF8_BYTES_PAR_CHAR 4
#define MAX_BYTES_PAR_CHAR(encoding) \
((encoding) == SHIFT_JIS ? MAX_SJIS_BYTES_PAR_CHAR : MAX_UTF8_BYTES_PAR_CHAR)
#define UTF8_TRAIL_BYTE(b) ((signed char)(b) < -0x40)
#define CHECKSJIS1BYTE(b) ( ((b) & 0xe0) == 0x80 || ((b) & 0xe0) == 0xe0 )
extern char* codeconv(CharacterEncoding tocode,
CharacterEncoding fromcode,
const char *str);
extern BYTE* sjis2utf(const BYTE *src);
extern BYTE* utf2sjis(const BYTE *src);
extern boolean sjis_has_hankaku(const BYTE *src);
extern boolean sjis_has_zenkaku(const BYTE *src);
extern int sjis_count_char(const BYTE *src);
extern int utf8_next_codepoint(const char **msg);
extern char *advance_char(const char *s, CharacterEncoding e);
#endif /* __UTFSJIS__ */
+10 -3
View File
@@ -45,7 +45,7 @@ int strvar_len = STRVAR_LEN;
static char *advance(const char *s, int n) {
while (*s && n > 0) {
s += (CHECKSJIS1BYTE(*s) && *(s + 1)) ? 2 : 1;
s = advance_char(s, nact->encoding);
n--;
}
return (char *)s;
@@ -175,7 +175,14 @@ void v_strcat(int no, const char *str) {
/* 文字変数の長さ */
size_t v_strlen(int no) {
return sjis_count_char(v_str(no));
const char *s = v_str(no);
int c = 0;
while (*s) {
s = advance_char(s, nact->encoding);
c++;
}
return c;
}
/* Width of a string (2 for full-width characters, 1 for half-width) */
@@ -207,7 +214,7 @@ int v_strstr(int no, int start, const char *str) {
return -1;
int n = start;
while (p < found) {
p += CHECKSJIS1BYTE(*p) ? 2 : 1;
p = advance_char(p, nact->encoding);
n++;
}
return n;