1
0
mirror of https://git.zap.org.au/git/trader.git synced 2024-12-04 14:46:45 -05:00

Use wide-character functions for input routines and most strings

Convert all input routines, and most internal strings, to use
wide-character functions.  All extended characters are supported,
including those having column widths of zero (eg, combining characters),
one (eg, normal Western characters) and two (eg, many East Asian
characters).  This was quite a major undertaking!
This commit is contained in:
John Zaitseff 2011-08-25 13:19:31 +10:00
parent b951b21894
commit 20473ae409
9 changed files with 1261 additions and 805 deletions

View File

@ -97,7 +97,7 @@ void exchange_stock (void)
center(curwin, 1, 0, attr_title, 0, 0, 1,
_(" Interstellar Stock Exchange "));
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
_("Player: ^{%s^}"), player[current_player].name);
_("Player: ^{%ls^}"), player[current_player].name);
all_off_map = true;
for (i = 0; i < MAX_COMPANIES; i++) {
@ -143,19 +143,19 @@ void exchange_stock (void)
- SHARE_RETURN_COLS, attr_subtitle, 0, 0, 2,
/* TRANSLATORS: "Price per share" is a two-line column
label in a table containing the price per share in
any given company. %s is the currency symbol in the
current locale. The maximum column width is 12
any given company. %ls is the currency symbol in
the current locale. The maximum column width is 12
characters INCLUDING the currency symbol (see
SHARE_PRICE_COLS in src/intf.h). */
pgettext("subtitle", "Price per\nshare (%s)"),
lconvinfo.currency_symbol);
pgettext("subtitle", "Price per\nshare (%ls)"),
currency_symbol);
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
if (company[i].on_map) {
mvwaddch(curwin, line, 2, PRINTABLE_MAP_VAL(COMPANY_TO_MAP(i))
| attr_choice);
left(curwin, line, 4, attr_normal, 0, 0, 1, "%s",
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
company[i].name);
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%'ld ",
@ -196,48 +196,61 @@ void exchange_stock (void)
// Get the actual selection made by the player
while (selection == SEL_NONE) {
bool found;
wint_t key;
int key = gettxchar(curwin);
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
bool found;
if (isupper(*keycode_company)) {
key = toupper(key);
} else if (islower(*keycode_company)) {
key = tolower(key);
}
if (iswupper(*keycode_company)) {
key = towupper(key);
} else if (iswlower(*keycode_company)) {
key = towlower(key);
}
for (i = 0, found = false; keycode_company[i] != '\0'; i++) {
if (keycode_company[i] == key) {
found = true;
if (company[i].on_map) {
selection = i;
} else {
for (i = 0, found = false; keycode_company[i] != '\0'; i++) {
if (keycode_company[i] == key) {
found = true;
if (company[i].on_map) {
selection = i;
} else {
beep();
}
break;
}
}
if (! found) {
switch (key) {
case '1':
curs_set(CURS_OFF);
show_status(current_player);
curs_set(CURS_ON);
break;
case '2':
curs_set(CURS_OFF);
show_map(true);
curs_set(CURS_ON);
break;
case '3':
selection = SEL_BANK;
break;
case '4':
case ' ':
selection = SEL_EXIT;
break;
default:
beep();
}
break;
}
}
if (! found) {
} else {
// Function or control key
switch (key) {
case '1':
curs_set(CURS_OFF);
show_status(current_player);
curs_set(CURS_ON);
break;
case '2':
curs_set(CURS_OFF);
show_map(true);
curs_set(CURS_ON);
break;
case '3':
selection = SEL_BANK;
break;
case '4':
case ' ':
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
@ -287,7 +300,7 @@ void visit_bank (void)
{
double credit_limit;
double val, max;
int key;
wint_t key;
bool done;
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
@ -363,27 +376,41 @@ void visit_bank (void)
done = false;
while (! done) {
key = gettxchar(curwin);
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
switch (key) {
case '1':
case '2':
case '3':
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
0, 0, 1, "%lc", key);
wrefresh(curwin);
switch (key) {
case '1':
case '2':
case '3':
wechochar(curwin, key | A_BOLD);
done = true;
break;
done = true;
break;
case ' ':
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
case ' ':
done = true;
break;
default:
beep();
default:
beep();
}
} else {
// Function or control key
switch (key) {
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
default:
beep();
}
}
}
@ -410,8 +437,8 @@ void visit_bank (void)
n = (lconvinfo.p_sep_by_space == 1) ? 1 : 0;
mkchstr(chbuf, BUFSIZE, attr_normal, attr_normal | A_BOLD, 0, 1,
getmaxx(curwin) / 2, &width_cursym, 1, "^{%s^}",
lconvinfo.currency_symbol);
getmaxx(curwin) / 2, &width_cursym, 1, "^{%ls^}",
currency_symbol);
chbuf_cursym = xchstrdup(chbuf);
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
@ -468,8 +495,8 @@ void visit_bank (void)
n = (lconvinfo.p_sep_by_space == 1) ? 1 : 0;
mkchstr(chbuf, BUFSIZE, attr_normal, attr_normal | A_BOLD, 0, 1,
getmaxx(curwin) / 2, &width_cursym, 1, "^{%s^}",
lconvinfo.currency_symbol);
getmaxx(curwin) / 2, &width_cursym, 1, "^{%ls^}",
currency_symbol);
chbuf_cursym = xchstrdup(chbuf);
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin)
@ -527,11 +554,12 @@ void visit_bank (void)
void trade_shares (int num, bool *bid_used)
{
bool done;
int key, ret, w, x;
int ret, w, x;
long int maxshares, val;
double ownership;
chtype *chbuf;
int width;
wint_t key;
assert(num >= 0 && num < MAX_COMPANIES);
@ -548,8 +576,8 @@ void trade_shares (int num, bool *bid_used)
w = getmaxx(curwin);
center(curwin, 1, 0, attr_title, 0, 0, 1,
/* TRANSLATORS: %s represents the company name. */
_(" Stock Transaction in %s "), company[num].name);
/* TRANSLATORS: %ls represents the company name. */
_(" Stock Transaction in %ls "), company[num].name);
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, w / 2, &width, 1,
/* TRANSLATORS: "Shares issued" represents the number of
@ -633,28 +661,42 @@ void trade_shares (int num, bool *bid_used)
done = false;
while (! done) {
key = gettxchar(curwin);
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
switch (key) {
case '1':
case '2':
case '3':
case '4':
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
0, 0, 1, "%lc", key);
wrefresh(curwin);
switch (key) {
case '1':
case '2':
case '3':
case '4':
wechochar(curwin, key | A_BOLD);
done = true;
break;
done = true;
break;
case ' ':
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
case ' ':
done = true;
break;
default:
beep();
default:
beep();
}
} else {
// Function or control key
switch (key) {
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
default:
beep();
}
}
}
@ -755,16 +797,16 @@ void trade_shares (int num, bool *bid_used)
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_error_window,
attr_error_title, attr_error_highlight, 0, 0,
attr_error_waitforkey, _(" No Shares Issued "),
/* TRANSLATORS: %s represents the company name. */
_("%s has refused\nto issue more shares."),
/* TRANSLATORS: %ls represents the company name. */
_("%ls has refused\nto issue more shares."),
company[num].name);
} else {
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_normal_window,
attr_title, attr_normal, attr_highlight, 0,
attr_waitforkey, _(" Shares Issued "),
/* TRANSLATORS: %s represents the company name. */
ngettext("%s has issued\n^{one^} more share.",
"%s has issued\n^{%'ld^} more shares.",
/* TRANSLATORS: %ls represents the company name. */
ngettext("%ls has issued\n^{one^} more share.",
"%ls has issued\n^{%'ld^} more shares.",
maxshares), company[num].name, maxshares);
}
break;

View File

@ -83,7 +83,7 @@ static const unsigned char game_file_crypt_key[] = {
} while (0)
#ifdef USE_UTF8_GAME_FILE
# define load_game_read_string(_var) \
# define load_game_read_string(_var, _var_utf8) \
do { \
char *s; \
int len; \
@ -115,11 +115,14 @@ static const unsigned char game_file_crypt_key[] = {
s[len - 1] = '\0'; \
} \
\
xmbstowcs(wcbuf, s, BUFSIZE); \
(_var) = xwcsdup(wcbuf); \
(_var_utf8) = s; \
\
lineno++; \
(_var) = s; \
} while (0)
#else // ! USE_UTF8_GAME_FILE
# define load_game_read_string(_var) \
# define load_game_read_string(_var, _var_utf8) \
do { \
char *s; \
int len; \
@ -140,8 +143,11 @@ static const unsigned char game_file_crypt_key[] = {
s[len - 1] = '\0'; \
} \
\
xmbstowcs(wcbuf, s, BUFSIZE); \
(_var) = xwcsdup(wcbuf); \
(_var_utf8) = s; \
\
lineno++; \
(_var) = s; \
} while (0)
#endif // ! USE_UTF8_GAME_FILE
@ -165,27 +171,38 @@ static const unsigned char game_file_crypt_key[] = {
save_game_printf("%d", (int) _var)
#ifdef USE_UTF8_GAME_FILE
# define save_game_write_string(_var) \
# define save_game_write_string(_var, _var_utf8) \
do { \
if (need_icd) { \
char *s = str_cd_iconv(_var, icd); \
if (s == NULL) { \
if (errno == EILSEQ) { \
err_exit(_("%s: could not convert string"), \
filename); \
} else { \
errno_exit("str_cd_iconv"); \
} \
} \
save_game_printf("%s", s); \
free(s); \
if ((_var_utf8) != NULL) { \
save_game_printf("%s", _var_utf8); \
} else { \
save_game_printf("%s", _var); \
if (need_icd) { \
snprintf(buf, BUFSIZE, "%ls", _var); \
char *s = str_cd_iconv(buf, icd); \
if (s == NULL) { \
if (errno == EILSEQ) { \
err_exit(_("%s: could not convert string"), \
filename); \
} else { \
errno_exit("str_cd_iconv"); \
} \
} \
save_game_printf("%s", s); \
free(s); \
} else { \
save_game_printf("%ls", _var); \
} \
} \
} while (0)
#else // ! USE_UTF8_GAME_FILE
# define save_game_write_string(_var) \
save_game_printf("%s", _var)
# define save_game_write_string(_var, _var_utf8) \
do { \
if ((_var_utf8) != NULL) { \
save_game_printf("%s", _var_utf8); \
} else { \
save_game_printf("%ls", _var); \
} \
} while (0)
#endif // ! USE_UTF8_GAME_FILE
@ -201,12 +218,15 @@ static const unsigned char game_file_crypt_key[] = {
bool load_game (int num)
{
char *buf, *filename;
char *filename;
FILE *file;
char *codeset, *codeset_nl;
int saved_errno, lineno;
char *prev_locale;
char *buf;
wchar_t *wcbuf;
int crypt_key;
int n, i, j;
@ -219,6 +239,7 @@ bool load_game (int num)
assert(num >= 1 && num <= 9);
buf = xmalloc(BUFSIZE);
wcbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
filename = game_filename(num);
assert(filename != NULL);
@ -246,6 +267,7 @@ bool load_game (int num)
}
free(buf);
free(wcbuf);
free(filename);
return false;
}
@ -332,7 +354,7 @@ bool load_game (int num)
// Read in player data
for (i = 0; i < number_players; i++) {
load_game_read_string(player[i].name);
load_game_read_string(player[i].name, player[i].name_utf8);
load_game_read_double(player[i].cash, player[i].cash >= 0.0);
load_game_read_double(player[i].debt, player[i].debt >= 0.0);
load_game_read_bool(player[i].in_game);
@ -344,7 +366,8 @@ bool load_game (int num)
// Read in company data
for (i = 0; i < MAX_COMPANIES; i++) {
company[i].name = xstrdup(gettext(company_name[i]));
xmbstowcs(wcbuf, gettext(company_name[i]), BUFSIZE);
company[i].name = xwcsdup(wcbuf);
load_game_read_double(company[i].share_price, company[i].share_price >= 0.0);
load_game_read_double(company[i].share_return, true);
load_game_read_long(company[i].stock_issued, company[i].stock_issued >= 0);
@ -391,6 +414,7 @@ bool load_game (int num)
#endif
free(buf);
free(wcbuf);
free(filename);
free(prev_locale);
free(codeset_nl);
@ -514,7 +538,7 @@ bool save_game (int num)
// Write out player data
for (i = 0; i < number_players; i++) {
save_game_write_string(player[i].name);
save_game_write_string(player[i].name, player[i].name_utf8);
save_game_write_double(player[i].cash);
save_game_write_double(player[i].debt);
save_game_write_bool(player[i].in_game);

View File

@ -108,48 +108,6 @@ static int cmp_player (const void *a, const void *b);
void init_game (void)
{
/* Initialise strings used for keycode input and map representations.
Each string must have an ASCII vertical line (U+007C) in the
correct position, followed by context information (such as
"input|Company" and "output|MapVals"). This is done to overcome a
limitation of gettext_noop() and N_() that does NOT allow context
IDs. This vertical line is replaced by a NUL character to
terminate the resulting string. The vertical line MAY appear in
other positions; if so, it is handled correctly. */
keycode_company = xstrdup(gettext(default_keycode_company));
if (strlen(keycode_company) < MAX_COMPANIES + 1
|| keycode_company[MAX_COMPANIES] != '|') {
err_exit(_("keycode string for companies has incorrect format: `%s'"),
keycode_company);
}
keycode_company[MAX_COMPANIES] = '\0';
keycode_game_move = xstrdup(gettext(default_keycode_game_move));
if (strlen(keycode_game_move) < NUMBER_MOVES + 1
|| keycode_game_move[NUMBER_MOVES] != '|') {
err_exit(_("keycode string for game moves has incorrect format: `%s'"),
keycode_game_move);
}
keycode_game_move[NUMBER_MOVES] = '\0';
printable_map_val = xstrdup(gettext(default_printable_map_val));
if (strlen(printable_map_val) < MAX_COMPANIES + 4
|| printable_map_val[MAX_COMPANIES + 3] != '|') {
err_exit(_("output string for companies has incorrect format: `%s'"),
printable_map_val);
}
printable_map_val[MAX_COMPANIES + 3] = '\0';
printable_game_move = xstrdup(gettext(default_printable_game_move));
if (strlen(printable_game_move) < NUMBER_MOVES + 1
|| printable_game_move[NUMBER_MOVES] != '|') {
err_exit(_("output string for game moves has incorrect format: `%s'"),
printable_game_move);
}
printable_game_move[NUMBER_MOVES] = '\0';
// Try to load an old game, if possible
if (game_num != 0) {
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
@ -213,6 +171,8 @@ void init_game (void)
}
if (! game_loaded) {
wchar_t *buf = xmalloc(BUFSIZE * sizeof(wchar_t));
ask_player_names();
deltxwin(); // "Number of players" window
@ -231,7 +191,8 @@ void init_game (void)
// Initialise company data
for (int i = 0; i < MAX_COMPANIES; i++) {
company[i].name = xstrdup(gettext(company_name[i]));
xmbstowcs(buf, gettext(company_name[i]), BUFSIZE);
company[i].name = xwcsdup(buf);
company[i].share_price = 0.0;
company[i].share_return = INITIAL_RETURN;
company[i].stock_issued = 0;
@ -263,10 +224,12 @@ void init_game (void)
txdlgbox(MAX_DLG_LINES, 50, 8, WCENTER, attr_normal_window,
attr_title, attr_normal, attr_highlight, 0,
attr_waitforkey, _(" First Player "),
_("The first player to go is ^{%s^}."),
_("The first player to go is ^{%ls^}."),
player[first_player].name);
txrefresh();
}
free(buf);
}
}
@ -280,15 +243,14 @@ void init_game (void)
static int ask_number_players (void)
{
char *keycode_contgame;
chtype *chbuf;
wchar_t *keycode_contgame = xmalloc(BUFSIZE * sizeof(wchar_t));
chtype *chbuf = xmalloc(BUFSIZE * sizeof(chtype));
int lines, maxwidth;
int widthbuf[2];
int key, ret;
int ret;
bool done;
chbuf = xmalloc(BUFSIZE * sizeof(chtype));
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0, 2,
WIN_COLS - 7, widthbuf, 2,
/* TRANSLATORS: The keycode <C> should be modified to
@ -311,21 +273,33 @@ static int ask_number_players (void)
first character (keyboard input code) is used to print the user's
response if one of those keys is pressed. Both upper and
lower-case versions should be present. */
keycode_contgame = xstrdup(pgettext("input|ContinueGame", "Cc"));
xmbstowcs(keycode_contgame, pgettext("input|ContinueGame", "Cc"), BUFSIZE);
done = false;
while (! done) {
key = gettxchar(curwin);
wint_t key;
if (key >= '1' && key <= MAX_PLAYERS + '0') {
wechochar(curwin, key | A_BOLD);
ret = key - '0';
done = true;
} else if (strchr(keycode_contgame, key) != NULL) {
wechochar(curwin, ((unsigned char) *keycode_contgame) | A_BOLD);
ret = 0;
done = true;
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
if (key >= '1' && key <= MAX_PLAYERS + '0') {
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
0, 0, 1, "%lc", key);
wrefresh(curwin);
ret = key - '0';
done = true;
} else if (wcschr(keycode_contgame, key) != NULL) {
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
0, 0, 1, "%lc", *keycode_contgame);
wrefresh(curwin);
ret = 0;
done = true;
} else {
beep();
}
} else {
// Function or control key
switch (key) {
case KEY_ESC:
case KEY_CANCEL:
@ -357,7 +331,7 @@ int ask_game_number (void)
chtype *chbuf;
int lines, maxwidth;
int widthbuf[2];
int key, ret;
int ret;
bool done;
@ -378,13 +352,22 @@ int ask_game_number (void)
done = false;
while (! done) {
key = gettxchar(curwin);
wint_t key;
if (key >= '1' && key <= '9') {
wechochar(curwin, key | A_BOLD);
ret = key - '0';
done = true;
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
if (key >= '1' && key <= '9') {
left(curwin, getcury(curwin), getcurx(curwin), A_BOLD,
0, 0, 1, "%lc", key);
wrefresh(curwin);
ret = key - '0';
done = true;
} else {
beep();
}
} else {
// Function or control key
switch (key) {
case KEY_ESC:
case KEY_CANCEL:
@ -426,10 +409,11 @@ void ask_player_names (void)
int w = getmaxx(curwin) - x - 2;
player[0].name = NULL;
player[0].name_utf8 = NULL;
while (true) {
int ret = gettxstr(curwin, &player[0].name, NULL, false,
2, x, w, attr_input_field);
if (ret == OK && strlen(player[0].name) != 0) {
if (ret == OK && wcslen(player[0].name) != 0) {
break;
} else {
beep();
@ -460,6 +444,7 @@ void ask_player_names (void)
for (i = 0; i < number_players; i++) {
player[i].name = NULL;
player[i].name_utf8 = NULL;
entered[i] = false;
left(curwin, i + 3, 2, attr_normal, 0, 0, 1,
/* xgettext:c-format, range: 1..8 */
@ -478,7 +463,7 @@ void ask_player_names (void)
switch (ret) {
case OK:
// Make sure name is not an empty string
len = strlen(player[cur].name);
len = wcslen(player[cur].name);
entered[cur] = (len != 0);
if (len == 0) {
beep();
@ -487,7 +472,7 @@ void ask_player_names (void)
// Make sure name has not been entered already
for (i = 0; i < number_players; i++) {
if (i != cur && player[i].name != NULL
&& strcmp(player[i].name, player[cur].name) == 0) {
&& wcscmp(player[i].name, player[cur].name) == 0) {
entered[cur] = false;
beep();
break;
@ -601,10 +586,10 @@ void end_game (void)
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight,
attr_blink, 5, WIN_COLS - 8, widthbuf, 5,
(player[0].sort_value == 0) ?
_("The winner is ^{%s^}\n"
_("The winner is ^{%ls^}\n"
"who is ^[*** BANKRUPT ***^]") :
/* xgettext:c-format */
_("The winner is ^{%s^}\n"
_("The winner is ^{%ls^}\n"
"with a value of ^{%N^}."),
player[0].name, player[0].sort_value);
@ -622,16 +607,15 @@ void end_game (void)
pgettext("subtitle", "Player"));
right(curwin, lines + 4, w - 4, attr_subtitle, 0, 0, 1,
/* TRANSLATORS: "Total Value" refers to the total worth
(shares, cash and debt) of any given player. %s is the
(shares, cash and debt) of any given player. %ls is the
currency symbol of the current locale. */
pgettext("subtitle", "Total Value (%s)"),
lconvinfo.currency_symbol);
pgettext("subtitle", "Total Value (%ls)"), currency_symbol);
for (int i = 0; i < number_players; i++) {
right(curwin, i + lines + 5, ORDINAL_COLS + 2, attr_normal, 0, 0,
1, gettext(ordinal[i + 1]));
left(curwin, i + lines + 5, ORDINAL_COLS + 4, attr_normal, 0, 0,
1, "%s", player[i].name);
1, "%ls", player[i].name);
right(curwin, i + lines + 5, w - 2, attr_normal, 0, 0,
1, " %!N ", player[i].sort_value);
}
@ -659,7 +643,7 @@ void show_map (bool closewin)
// Display current player and turn number
left(curwin, 1, 4, attr_mapwin_title, attr_mapwin_highlight, 0, 1,
_("Player: ^{%s^}"), player[current_player].name);
_("Player: ^{%ls^}"), player[current_player].name);
right(curwin, 1, getmaxx(curwin) - 2, attr_mapwin_title,
attr_mapwin_highlight, attr_mapwin_blink, 1,
(turn_number != max_turn) ? _(" Turn: ^{%d^} ") :
@ -669,26 +653,11 @@ void show_map (bool closewin)
for (int y = 0; y < MAX_Y; y++) {
wmove(curwin, y + 3, 2);
for (int x = 0; x < MAX_X; x++) {
map_val_t m = galaxy_map[x][y];
chtype *mapstr = CHTYPE_MAP_VAL(galaxy_map[x][y]);
switch (m) {
case MAP_EMPTY:
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_empty);
break;
case MAP_OUTPOST:
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_outpost);
break;
case MAP_STAR:
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_star);
break;
default:
waddch(curwin, PRINTABLE_MAP_VAL(m) | attr_map_company);
break;
while (*mapstr != '\0') {
waddch(curwin, *mapstr++);
}
waddch(curwin, ' ' | attr_map_empty);
}
}
@ -724,7 +693,7 @@ void show_status (int num)
attr_normal_window);
center(curwin, 1, 0, attr_title, 0, 0, 1, _(" Stock Portfolio "));
center(curwin, 2, 0, attr_normal, attr_highlight, 0, 1,
_("Player: ^{%s^}"), player[num].name);
_("Player: ^{%ls^}"), player[num].name);
val = total_value(num);
if (val == 0.0) {
@ -780,16 +749,16 @@ void show_status (int num)
- SHARE_RETURN_COLS, attr_subtitle, 0, 0, 2,
/* TRANSLATORS: "Price per share" is a two-line column
label in a table containing the price per share in
any given company. %s is the currency symbol in the
current locale. The maximum column width is 12
any given company. %ls is the currency symbol in
the current locale. The maximum column width is 12
characters INCLUDING the currency symbol (see
SHARE_PRICE_COLS in src/intf.h). */
pgettext("subtitle", "Price per\nshare (%s)"),
lconvinfo.currency_symbol);
pgettext("subtitle", "Price per\nshare (%ls)"),
currency_symbol);
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
if (company[i].on_map) {
left(curwin, line, 4, attr_normal, 0, 0, 1, "%s",
left(curwin, line, 4, attr_normal, 0, 0, 1, "%ls",
company[i].name);
right(curwin, line, w - 2, attr_normal, 0, 0, 1, "%.2f ",

View File

@ -128,10 +128,12 @@ player_info_t player[MAX_PLAYERS]; // Array of players
map_val_t galaxy_map[MAX_X][MAX_Y]; // Map of the galaxy
move_rec_t game_move[NUMBER_MOVES]; // Current moves
char *keycode_company; // Keycodes for each company
char *keycode_game_move; // Keycodes for each game move
char *printable_map_val; // Printable output for each map value
char *printable_game_move; // Printable output for each game move
wchar_t *keycode_company; // Keycodes for each company
wchar_t *keycode_game_move; // Keycodes for each game move
wchar_t *printable_map_val; // Printable output for each map value
wchar_t *printable_game_move; // Printable output for each game move
chtype *chtype_map_val[MAX_COMPANIES + 3]; // as chtype strings
chtype *chtype_game_move[NUMBER_MOVES]; // as chtype strings
int max_turn; // Max. number of turns in game
int turn_number; // Current turn (1 to max_turn)

View File

@ -32,7 +32,7 @@
#define included_GLOBALS_H 1
#include <stdbool.h>
#include <system.h>
/************************************************************************
@ -97,7 +97,7 @@
// Information about each company
typedef struct company_info {
const char *name; // Company name
wchar_t *name; // Company name
double share_price; // Share price
double share_return; // Return per share
long int stock_issued; // Total stock sold to players
@ -108,7 +108,8 @@ typedef struct company_info {
// Information about each player
typedef struct player_info {
char *name; // Player name
wchar_t *name; // Player name
char *name_utf8; // Player name (in UTF-8, for load/save)
double cash; // Cash available
double debt; // Amount of debt
long int stock_owned[MAX_COMPANIES]; // How much stock is owned
@ -130,11 +131,14 @@ typedef enum map_val {
#define MAP_TO_COMPANY(m) ((m) - MAP_A)
#define IS_MAP_COMPANY(m) ((m) >= MAP_A && (m) <= MAP_LAST)
#define PRINTABLE_MAP_VAL(m) \
(((m) == MAP_EMPTY) ? printable_map_val[0] : \
(((m) == MAP_OUTPOST) ? printable_map_val[1] : \
(((m) == MAP_STAR) ? printable_map_val[2] : \
printable_map_val[(m) - MAP_A + 3])))
#define MAP_TO_INDEX(m) \
(((m) == MAP_EMPTY) ? 0 : \
(((m) == MAP_OUTPOST) ? 1 : \
(((m) == MAP_STAR) ? 2 : \
((m) - MAP_A + 3))))
#define PRINTABLE_MAP_VAL(m) printable_map_val[MAP_TO_INDEX(m)]
#define CHTYPE_MAP_VAL(m) chtype_map_val[MAP_TO_INDEX(m)]
// Information about a move
@ -144,6 +148,7 @@ typedef struct move_rec {
} move_rec_t;
#define PRINTABLE_GAME_MOVE(m) (printable_game_move[m])
#define CHTYPE_GAME_MOVE(m) (chtype_game_move[m])
// Player moves / selection values
@ -193,10 +198,12 @@ extern player_info_t player[MAX_PLAYERS]; // Array of players
extern map_val_t galaxy_map[MAX_X][MAX_Y]; // Map of the galaxy
extern move_rec_t game_move[NUMBER_MOVES]; // Current moves
extern char *keycode_company; // Keycodes for each company
extern char *keycode_game_move; // Keycodes for each game move
extern char *printable_map_val; // Printable output for each map value
extern char *printable_game_move; // Printable output for each game move
extern wchar_t *keycode_company; // Keycodes for each company
extern wchar_t *keycode_game_move; // Keycodes for each game move
extern wchar_t *printable_map_val; // Printable output for each map value
extern wchar_t *printable_game_move; // Printable output for each game move
extern chtype *chtype_map_val[MAX_COMPANIES + 3]; // as chtype strings
extern chtype *chtype_game_move[NUMBER_MOVES]; // as chtype strings
extern int max_turn; // Max. number of turns in game
extern int turn_number; // Current turn (1 to max_turn)

View File

@ -279,7 +279,6 @@ void show_help (void)
char *cp;
mbstate_t mbstate;
chtype *outp;
wchar_t c;
size_t i, n;
int count = BIGBUFSIZE;
@ -387,36 +386,31 @@ void show_help (void)
case '8':
case '9':
// N-th choice of move, as a key press
c = btowc(PRINTABLE_GAME_MOVE(*htxt - L'1'));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
wcbuf[0] = PRINTABLE_GAME_MOVE(*htxt - L'1');
wcbuf[1] = '\0';
goto addwcbuf;
case 'M':
// Last choice of move, as a key press
c = btowc(PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
wcbuf[0] = PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1);
wcbuf[1] = '\0';
goto addwcbuf;
case '.':
// Map representation of empty space
c = btowc(PRINTABLE_MAP_VAL(MAP_EMPTY));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_EMPTY);
wcbuf[1] = '\0';
goto addwcbuf;
case '+':
// Map representation of an outpost
c = btowc(PRINTABLE_MAP_VAL(MAP_OUTPOST));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_OUTPOST);
wcbuf[1] = '\0';
goto addwcbuf;
case '*':
// Map representation of a star
c = btowc(PRINTABLE_MAP_VAL(MAP_STAR));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
wcbuf[0] = PRINTABLE_MAP_VAL(MAP_STAR);
wcbuf[1] = '\0';
goto addwcbuf;
@ -429,8 +423,8 @@ void show_help (void)
case 'G':
case 'H':
// Map representation of company
c = btowc(PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*htxt - L'A')));
wcbuf[0] = (c == WEOF) ? EILSEQ_REPL : c;
assert((*htxt - L'A') < MAX_COMPANIES);
wcbuf[0] = PRINTABLE_MAP_VAL(COMPANY_TO_MAP(*htxt - L'A'));
wcbuf[1] = '\0';
goto addwcbuf;
@ -486,35 +480,41 @@ void show_help (void)
"for the previous page ] "));
wrefresh(curwin);
int key = gettxchar(curwin);
switch (key) {
case KEY_BS:
case KEY_BACKSPACE:
case KEY_DEL:
case KEY_PPAGE:
case KEY_UP:
case KEY_LEFT:
case KEY_BTAB:
if (curpage == 0) {
beep();
} else {
curpage--;
}
break;
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
default:
wint_t key;
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
curpage++;
done = (curpage == numpages);
} else {
// Function or control character
switch (key) {
case KEY_BS:
case KEY_BACKSPACE:
case KEY_DEL:
case KEY_PPAGE:
case KEY_UP:
case KEY_LEFT:
case KEY_BTAB:
if (curpage == 0) {
beep();
} else {
curpage--;
}
break;
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
done = true;
break;
default:
curpage++;
done = (curpage == numpages);
}
}
}

1212
src/intf.c

File diff suppressed because it is too large Load Diff

View File

@ -105,8 +105,8 @@ typedef enum curs_type {
#define KEY_CTRL(x) ((x) - 0100) // ASCII control character
// Keycodes for inserting the default value in input routines
#define KEY_DEFAULTVAL1 '='
#define KEY_DEFAULTVAL2 ';'
#define CHAR_DEFVAL1 '='
#define CHAR_DEFVAL2 ';'
// Control-arrow key combinations, as returned by Ncurses
#ifndef KEY_CDOWN
@ -116,6 +116,11 @@ typedef enum curs_type {
# define KEY_CRIGHT 01052 // CTRL + Right Arrow
#endif
// Function-key result, for Curses that do not define it
#ifndef KEY_CODE_YES
# define KEY_CODE_YES 0400
#endif
// Timeout value (in ms) for Meta-X-style keyboard input
#ifdef NCURSES_VERSION
# define META_TIMEOUT ESCDELAY
@ -321,7 +326,7 @@ extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
Returns: int - Number of lines actually used
This function converts the format string and following arguments into
chbuf, a chtype buffer that can be used for calls to leftch(), centerch()
chbuf, a chtype string that can be used for calls to leftch(), centerch()
and rightch(). At most maxlines lines are used, each with a maximum
width of maxwidth. The actual widths of each resulting line are stored
in widthbuf (which must not be NULL). If maxlines is greater than 1,
@ -534,26 +539,26 @@ extern int right (WINDOW *win, int y, int x, chtype attr_norm, chtype attr_alt1,
/*
Function: gettxchar - Read a character from the keyboard
Function: gettxchar - Read a wide character from the keyboard
Parameters: win - Window to use (should be curwin)
Returns: int - The keyboard character
wch - Pointer to keyboard wide character
Returns: int - OK or KEY_CODE_YES
This function reads a single character from the keyboard. The key is
NOT echoed to the terminal display, nor is the cursor visibility
affected.
This implementation does not handle multibyte characters correctly:
each part of the multibyte character most likely appears as a separate
keyboard press.
This function waits until the user presses a key on the keyboard, then
reads that key as a single wide character. If it is a function key or
a control key, it is stored in wch and KEY_CODE_YES is returned.
Otherwise, it is an ordinary key: it is also stored in wch and OK is
returned. ERR is never returned. The key is NOT echoed to the
terminal display, nor is the cursor visibility affected.
*/
extern int gettxchar (WINDOW *win);
extern int gettxchar (WINDOW *win, wint_t *wch);
/*
Function: gettxline - Read a line from the keyboard (low-level)
Function: gettxline - Read a line of input from the keyboard (low-level)
Parameters: win - Window to use (should be curwin)
buf - Pointer to preallocated buffer
bufsize - Size of buffer in bytes
bufsize - Size of buffer (number of wchar_t elements)
modified - Pointer to modified status (result)
multifield - Allow <TAB>, etc, to exit this function
emptyval - String used if input line is empty
@ -561,14 +566,14 @@ extern int gettxchar (WINDOW *win);
allowed - Characters allowed in the input line
stripspc - True to strip leading/trailing spaces
y, x - Start of the input field (line, column)
width - Width of the input field
width - Width of the input field (column spaces)
attr - Character rendition to use for input field
Returns: int - Status code: OK, ERR or KEY_ keycode
This low-level function draws an input field width characters long
This low-level function shows an input field width column spaces long
using attr as the character rendition, then reads a line of input from
the keyboard and places it into the preallocated buffer buf[] of size
bufsize. On entry, buf[] must contain a valid C string; this string is
bufsize. On entry, buf[] must contain a valid string; this string is
used as the initial contents of the input field. On exit, buf[]
contains the final string as edited or input by the user. This string
is printed in place of the input field using the original character
@ -580,13 +585,13 @@ extern int gettxchar (WINDOW *win);
empty string is entered, the string pointed to by emptyval (if not
NULL) is stored in buf[].
If CANCEL, EXIT, ESC, ^C, ^\ or ^G is pressed, ERR is returned. In
If ESC, CANCEL, EXIT, ^C, ^G or ^\ is pressed, ERR is returned. In
this case, buf[] contains the string as left by the user: emptyval is
NOT used, nor are leading and trailing spaces stripped.
If multifield is true, the UP and DOWN arrow keys, as well as TAB,
Shift-TAB, ^P (Previous) and ^N (Next) return KEY_UP or KEY_DOWN as
appropriate. As with CANCEL etc., emptyval is NOT used, nor are
Shift-TAB, ^P (Previous) and ^N (Next) return either KEY_UP or KEY_DOWN
as appropriate. As with ESC etc., emptyval is NOT used, nor are
leading and trailing spaces stripped.
In all of these cases, the boolean variable *modified (if modified is
@ -594,7 +599,7 @@ extern int gettxchar (WINDOW *win);
way (including if the user made any changed, spaces were stripped or if
emptyval was copied into buf[]).
If KEY_DEFAULTVAL1 or KEY_DEFAULTVAL2 is pressed when the input line is
If either KEY_DEFVAL1 or KEY_DEFVAL2 is pressed when the input line is
empty, the string pointed to by defaultval (if not NULL) is placed in
the buffer as if typed by the user. Editing is NOT terminated in this
case.
@ -607,17 +612,12 @@ extern int gettxchar (WINDOW *win);
Note that the character rendition (attributes) in attr may contain a
printing character. For example, A_BOLD | '_' is a valid rendition
that causes the input field to be a series of "_" characters in bold.
This implementation does not handle multibyte characters correctly:
each part of the multibyte character most likely appears as a separate
keyboard press and is handled as a separate character, causing the
cursor position to be incorrect. In addition, allowed is compared on a
byte-by-byte basis, not character-by-character.
Note also that the cursor becomes invisible after calling this function.
*/
extern int gettxline (WINDOW *win, char *buf, int bufsize,
extern int gettxline (WINDOW *win, wchar_t *restrict buf, int bufsize,
bool *restrict modified, bool multifield,
const char *emptyval, const char *defaultval,
const char *allowed, bool stripspc, int y, int x,
const wchar_t *emptyval, const wchar_t *defaultval,
const wchar_t *allowed, bool stripspc, int y, int x,
int width, chtype attr);
@ -633,18 +633,19 @@ extern int gettxline (WINDOW *win, char *buf, int bufsize,
Returns: int - Status code: OK, ERR or KEY_ keycode
This function calls gettxline() to allow the user to enter a string via
the keyboard. On entry, bufptr must be the address of a char * pointer
variable; that pointer (*bufptr) must either be NULL or contain the
address of a buffer previously allocated with gettxstr(). If *bufptr
is NULL, a buffer of BUFSIZE is automatically allocated using malloc();
this buffer is used to store and return the input line.
the keyboard. On entry, bufptr must be the address of a wchar_t *
pointer variable; that pointer (*bufptr) must either be NULL or contain
the address of a buffer previously allocated with gettxstr(). If
*bufptr is NULL, a buffer of BUFSIZE is automatically allocated using
malloc(); this buffer is used to store and return the input line.
Apart from bufptr, all parameters are as used for gettxline(). The
gettxline() parameters emptyval and defaultval are passed as "",
allowed is NULL and stripspc is true.
*/
extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
bool multifield, int y, int x, int width, chtype attr);
extern int gettxstr (WINDOW *win, wchar_t *restrict *restrict bufptr,
bool *restrict modified, bool multifield,
int y, int x, int width, chtype attr);
/*
@ -656,7 +657,7 @@ extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
emptyval - Value to use for empty input
defaultval - Value to use for default input
y, x - Start of the input field (line, column)
width - Width of the input field
width - Width of the input field (column spaces)
attr - Character rendition to use for input field
Returns: int - Status code: OK, ERR or KEY_ keycode
@ -668,12 +669,11 @@ extern int gettxstr (WINDOW *win, char **bufptr, bool *restrict modified,
result from gettxline() is passed back to the caller. Note that the
low-level function gettxline() is called with multifield set to false.
This function is locale-aware, although multibyte strings are not
handled correctly. In particular, the default value is formatted using
strfmon() and uses the locale monetary default decimal places
(frac_digits). In addition, the user is allowed to use the locale's
radix character (decimal point) and the thousands separator, as well as
the monetary versions of these.
This function is locale-aware. In particular, the default value is
formatted using strfmon() and uses the locale monetary default decimal
places (frac_digits). In addition, the user is allowed to use the
locale's radix character (decimal point) and the thousands separator,
as well as the monetary versions of these.
*/
extern int gettxdouble (WINDOW *win, double *restrict result, double min,
double max, double emptyval, double defaultval,
@ -696,9 +696,9 @@ extern int gettxdouble (WINDOW *win, double *restrict result, double min,
This function behaves almost exactly like gettxdouble(), except that
only integer numbers are allowed to be entered.
This function is locale-aware, although multibyte strings are not
handled correctly. In particular, the user is allowed to use the
locale's thousands separator and the monetary thousands separator.
This function is locale-aware. In particular, the user is allowed to
use the locale's thousands separator and the monetary thousands
separator.
*/
extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
long int max, long int emptyval, long int defaultval,
@ -710,10 +710,11 @@ extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
Parameters: win - Window to use (should be curwin)
Returns: bool - True if Yes was selected, false if No
This function waits for the user to press either "Y" (for Yes) or "N"
(for No) on the keyboard, then prints the answer using A_BOLD. True is
returned if "Y" was selected, false if "N". Note that the cursor
becomes invisible after calling this function.
This function waits for the user to press either the locale-specific
equivalent of "Y" (for Yes) or "N" (for No) on the keyboard, then
prints the answer using A_BOLD. True is returned if "Y" was selected,
false if "N". Note that the cursor becomes invisible after calling
this function.
*/
extern bool answer_yesno (WINDOW *win);
@ -730,10 +731,6 @@ extern bool answer_yesno (WINDOW *win);
The reason the user is not asked "Press any key to continue" is
historical: many, many people used to ask "where is the <ANY> key?" :-)
The current implementation does not handle multibyte characters
correctly: only the first byte of the character is consumed, with
further bytes left in the keyboard queue.
*/
extern void wait_for_key (WINDOW *win, int y, chtype attr);

View File

@ -219,8 +219,8 @@ selection_t get_move (void)
// Display current move choices on the galaxy map
for (int i = 0; i < NUMBER_MOVES; i++) {
mvwaddch(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
PRINTABLE_GAME_MOVE(i) | attr_map_choice);
mvwaddchstr(curwin, game_move[i].y + 3, game_move[i].x * 2 + 2,
CHTYPE_GAME_MOVE(i));
}
wrefresh(curwin);
@ -242,7 +242,7 @@ selection_t get_move (void)
right(curwin, 1, getmaxx(curwin) / 2, attr_normal, attr_keycode,
attr_choice, 1,
_("Select move [^[%c^]-^[%c^]/^{1^}-^{3^}/^{<CTRL><C>^}]: "),
_("Select move [^[%lc^]-^[%lc^]/^{1^}-^{3^}/^{<CTRL><C>^}]: "),
PRINTABLE_GAME_MOVE(0), PRINTABLE_GAME_MOVE(NUMBER_MOVES - 1));
curs_set(CURS_ON);
@ -250,60 +250,69 @@ selection_t get_move (void)
// Get the actual selection made by the player
while (selection == SEL_NONE) {
int i;
bool found;
wint_t key;
int key = gettxchar(curwin);
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
int i;
bool found;
if (isupper(*keycode_game_move)) {
key = toupper(key);
} else if (islower(*keycode_game_move)) {
key = tolower(key);
}
for (i = 0, found = false; keycode_game_move[i] != '\0'; i++) {
if (keycode_game_move[i] == key) {
found = true;
selection = i;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_choice, 0, 1,
/* TRANSLATORS: "Move" refers to the choice of
moves made by the current player (out of a
selection of 20 moves). */
_("Move ^{%c^}"), PRINTABLE_GAME_MOVE(i));
break;
if (iswupper(*keycode_game_move)) {
key = towupper(key);
} else if (iswlower(*keycode_game_move)) {
key = towlower(key);
}
}
if (! found) {
for (i = 0, found = false; keycode_game_move[i] != '\0'; i++) {
if (keycode_game_move[i] == key) {
found = true;
selection = i;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_choice, 0, 1,
/* TRANSLATORS: "Move" refers to the choice of
moves made by the current player (out of a
selection of 20 moves). */
_("Move ^{%lc^}"), PRINTABLE_GAME_MOVE(i));
break;
}
}
if (! found) {
switch (key) {
case '1':
curs_set(CURS_OFF);
show_status(current_player);
curs_set(CURS_ON);
break;
case '2':
selection = SEL_BANKRUPT;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_normal | A_BOLD, 0, 1,
_("^{<2>^} (Declare bankruptcy)"));
break;
case '3':
selection = SEL_SAVE;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_normal | A_BOLD, 0, 1,
_("^{<3>^} (Save and end the game)"));
break;
default:
beep();
}
}
} else {
// Function or control key
switch (key) {
case '1':
curs_set(CURS_OFF);
show_status(current_player);
curs_set(CURS_ON);
break;
case '2':
selection = SEL_BANKRUPT;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_normal | A_BOLD, 0, 1,
_("^{<2>^} (Declare bankruptcy)"));
break;
case '3':
selection = SEL_SAVE;
curs_set(CURS_OFF);
left(curwin, 1, getmaxx(curwin) / 2, attr_normal,
attr_normal | A_BOLD, 0, 1,
_("^{<3>^} (Save and end the game)"));
break;
case KEY_ESC:
case KEY_CANCEL:
case KEY_EXIT:
@ -361,10 +370,10 @@ selection_t get_move (void)
if (! saved) {
// Ask which game to save
int key;
bool done;
int widthbuf[2];
int lines, maxwidth;
int choice;
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_keycode, 0,
2, WIN_COLS - 7, widthbuf, 2,
@ -383,12 +392,22 @@ selection_t get_move (void)
done = false;
while (! done) {
key = gettxchar(curwin);
wint_t key;
if (key >= '1' && key <= '9') {
wechochar(curwin, key | A_BOLD);
done = true;
if (gettxchar(curwin, &key) == OK) {
// Ordinary wide character
if (key >= '1' && key <= '9') {
left(curwin, getcury(curwin), getcurx(curwin),
A_BOLD, 0, 0, 1, "%lc", key);
wrefresh(curwin);
choice = key - '0';
done = true;
} else {
beep();
}
} else {
// Function or control key
switch (key) {
case KEY_ESC:
case KEY_CANCEL:
@ -396,7 +415,7 @@ selection_t get_move (void)
case KEY_CTRL('C'):
case KEY_CTRL('G'):
case KEY_CTRL('\\'):
key = KEY_CANCEL;
choice = ERR;
done = true;
break;
@ -408,9 +427,10 @@ selection_t get_move (void)
curs_set(CURS_OFF);
if (key != KEY_CANCEL) {
if (choice != ERR) {
// Try to save the game, if possible
game_num = key - '0';
game_num = choice;
mkchstr(chbuf, BUFSIZE, attr_status_window, 0, 0, 1,
WIN_COLS - 7, &width, 1,
@ -645,14 +665,14 @@ void bankrupt_player (bool forced)
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
attr_error_title, attr_error_highlight, 0, 0,
attr_error_waitforkey, _(" Bankruptcy Court "),
_("%s has been declared bankrupt "
_("%ls has been declared bankrupt "
"by the Interstellar Trading Bank."),
player[current_player].name);
} else {
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_error_window,
attr_error_title, attr_error_highlight, 0, 0,
attr_error_waitforkey, _(" Bankruptcy Court "),
_("%s has declared bankruptcy."),
_("%ls has declared bankruptcy."),
player[current_player].name);
}
txrefresh();
@ -721,7 +741,7 @@ void try_start_new_company (int x, int y)
txdlgbox(MAX_DLG_LINES, 50, 7, WCENTER, attr_normal_window,
attr_title, attr_normal, attr_highlight, 0, attr_waitforkey,
_(" New Company "),
_("A new company has been formed!\nIts name is ^{%s^}."),
_("A new company has been formed!\nIts name is ^{%ls^}."),
company[i].name);
txrefresh();
@ -777,7 +797,7 @@ void merge_companies (map_val_t a, map_val_t b)
lines = mkchstr(chbuf, BUFSIZE, attr_normal, attr_highlight, 0, 4,
WIN_COLS - 8, widthbuf, 4,
_("^{%s^} has just merged into ^{%s^}.\n"
_("^{%ls^} has just merged into ^{%ls^}.\n"
"Please note the following transactions:\n"),
company[bb].name, company[aa].name);
@ -787,11 +807,11 @@ void merge_companies (map_val_t a, map_val_t b)
centerch(curwin, 3, 0, chbuf, lines, widthbuf);
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
&width_aa, 1, "%s", company[aa].name);
&width_aa, 1, "%ls", company[aa].name);
chbuf_aa = xchstrdup(chbuf);
mkchstr(chbuf, BUFSIZE, attr_highlight, 0, 0, 1, getmaxx(curwin) / 2,
&width_bb, 1, "%s", company[bb].name);
&width_bb, 1, "%ls", company[bb].name);
chbuf_bb = xchstrdup(chbuf);
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, getmaxx(curwin) / 2,
@ -824,12 +844,11 @@ void merge_companies (map_val_t a, map_val_t b)
pgettext("subtitle", "Player"));
right(curwin, lines + 6, w - 4, attr_subtitle, 0, 0, 1,
/* TRANSLATORS: "Bonus" refers to the bonus cash amount paid to
each player after two companies merge. %s is the currency
each player after two companies merge. %ls is the currency
symbol in the current locale. The maximum column width is
12 characters INCLUDING the currency symbol (see
MERGE_BONUS_COLS in src/intf.h). */
pgettext("subtitle", "Bonus (%s)"),
lconvinfo.currency_symbol);
pgettext("subtitle", "Bonus (%ls)"), currency_symbol);
right(curwin, lines + 6, w - 6 - MERGE_BONUS_COLS, attr_subtitle, 0, 0, 1,
/* TRANSLATORS: "Total" refers to the total number of shares in
the new company after a merger. The maximum column width is
@ -868,7 +887,7 @@ void merge_companies (map_val_t a, map_val_t b)
mkchstr(chbuf, BUFSIZE, attr_normal, 0, 0, 1, w - 12
- MERGE_BONUS_COLS - MERGE_TOTAL_STOCK_COLS
- MERGE_NEW_STOCK_COLS - MERGE_OLD_STOCK_COLS,
&width, 1, "%s", player[i].name);
&width, 1, "%ls", player[i].name);
leftch(curwin, ln, 4, chbuf, 1, &width);
right(curwin, ln, w - 4, attr_normal, 0, 0, 1, "%!N", bonus);
@ -994,7 +1013,7 @@ void adjust_values (void)
attr_error_title, attr_error_highlight,
attr_error_normal, 0, attr_error_waitforkey,
_(" Bankruptcy Court "),
_("%s has been declared bankrupt "
_("%ls has been declared bankrupt "
"by the Interstellar Trading Bank.\n\n"
"^{All assets have been taken "
"to repay outstanding loans.^}"),
@ -1016,7 +1035,7 @@ void adjust_values (void)
lines = mkchstr(chbuf, BUFSIZE, attr_error_highlight,
attr_error_normal, 0, 6, 60 - 4, widthbuf, 6,
_("%s has been declared bankrupt by the "
_("%ls has been declared bankrupt by the "
"Interstellar Trading Bank.\n\n"
"^{The Bank has agreed to pay stock holders ^}"
"%.2f%%^{ of the share value on each share "