mirror of
https://git.zap.org.au/git/trader.git
synced 2024-11-03 17:27:29 -05:00
Compensate for the POSIX locale not having a currency symbol
The function l_strfmon() will insert MOD_POSIX_CURRENCY_SYMBOL in the appropriate place when used with the POSIX ("C") locale.
This commit is contained in:
parent
e56247b1b4
commit
da7477dc28
46
src/exch.c
46
src/exch.c
@ -96,9 +96,8 @@ void exchange_stock (void)
|
||||
}
|
||||
|
||||
// Handle the locale's currency symbol
|
||||
struct lconv *lc = localeconv();
|
||||
assert(lc != NULL);
|
||||
snprintf(buf, BUFSIZE, "share (%s)", lc->currency_symbol);
|
||||
snprintf(buf, BUFSIZE, "share (%s)",
|
||||
localeconv_info.currency_symbol);
|
||||
|
||||
wattrset(curwin, ATTR_WINDOW_SUBTITLE);
|
||||
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ",
|
||||
@ -111,7 +110,7 @@ void exchange_stock (void)
|
||||
if (company[i].on_map) {
|
||||
mvwaddch(curwin, line, 2, PRINTABLE_MAP_VAL(COMPANY_TO_MAP(i)) |
|
||||
ATTR_MAP_CHOICE);
|
||||
strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
mvwprintw(curwin, line, 4, "%-22s %12s %10.2f %'10ld %'10ld ",
|
||||
company[i].name, buf, company[i].share_return
|
||||
* 100.0, company[i].stock_issued,
|
||||
@ -241,9 +240,6 @@ void visit_bank (void)
|
||||
double val, max;
|
||||
char *buf;
|
||||
|
||||
struct lconv *lc = localeconv();
|
||||
assert(lc != NULL);
|
||||
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
@ -263,18 +259,18 @@ void visit_bank (void)
|
||||
|
||||
center(curwin, 1, ATTR_WINDOW_TITLE, " Interstellar Trading Bank ");
|
||||
|
||||
strfmon(buf, BUFSIZE, "%18n", player[current_player].cash);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[current_player].cash);
|
||||
center2(curwin, 3, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Current cash: ", " %s ", buf);
|
||||
|
||||
strfmon(buf, BUFSIZE, "%18n", player[current_player].debt);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[current_player].debt);
|
||||
center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Current debt: ", " %s ", buf);
|
||||
|
||||
center2(curwin, 5, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Interest rate: ", " %17.2f%% ", interest_rate * 100.0);
|
||||
|
||||
strfmon(buf, BUFSIZE, "%18n", credit_limit);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", credit_limit);
|
||||
center2(curwin, 7, ATTR_HIGHLIGHT_STR, ATTR_WINDOW_TITLE,
|
||||
"Credit limit: ", " %s ", buf);
|
||||
|
||||
@ -354,16 +350,17 @@ void visit_bank (void)
|
||||
mvwprintw(curwin, 3, 10, "How much do you wish to borrow? ");
|
||||
|
||||
wattron(curwin, A_BOLD);
|
||||
if (lc->p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", lc->currency_symbol,
|
||||
(lc->p_sep_by_space == 1) ? " " : "");
|
||||
if (localeconv_info.p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", localeconv_info.currency_symbol,
|
||||
(localeconv_info.p_sep_by_space == 1) ? " " : "");
|
||||
n = 10;
|
||||
} else {
|
||||
getyx(curwin, y, x);
|
||||
n = strlen(lc->currency_symbol) + 10 + (lc->p_sep_by_space == 1);
|
||||
n = strlen(localeconv_info.currency_symbol) + 10
|
||||
+ (localeconv_info.p_sep_by_space == 1);
|
||||
mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
|
||||
(lc->p_sep_by_space == 1) ? " " : "",
|
||||
lc->currency_symbol);
|
||||
(localeconv_info.p_sep_by_space == 1) ? " " : "",
|
||||
localeconv_info.currency_symbol);
|
||||
wmove(curwin, y, x);
|
||||
}
|
||||
wattroff(curwin, A_BOLD);
|
||||
@ -414,16 +411,17 @@ void visit_bank (void)
|
||||
mvwprintw(curwin, 3, 10, "How much do you wish to repay? ");
|
||||
|
||||
wattron(curwin, A_BOLD);
|
||||
if (lc->p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", lc->currency_symbol,
|
||||
(lc->p_sep_by_space == 1) ? " " : "");
|
||||
if (localeconv_info.p_cs_precedes == 1) {
|
||||
wprintw(curwin, "%s%s", localeconv_info.currency_symbol,
|
||||
(localeconv_info.p_sep_by_space == 1) ? " " : "");
|
||||
n = 10;
|
||||
} else {
|
||||
getyx(curwin, y, x);
|
||||
n = strlen(lc->currency_symbol) + 10 + (lc->p_sep_by_space == 1);
|
||||
n = strlen(localeconv_info.currency_symbol) + 10
|
||||
+ (localeconv_info.p_sep_by_space == 1);
|
||||
mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
|
||||
(lc->p_sep_by_space == 1) ? " " : "",
|
||||
lc->currency_symbol);
|
||||
(localeconv_info.p_sep_by_space == 1) ? " " : "",
|
||||
localeconv_info.currency_symbol);
|
||||
wmove(curwin, y, x);
|
||||
}
|
||||
wattroff(curwin, A_BOLD);
|
||||
@ -508,7 +506,7 @@ void trade_shares (int num, bool *bid_used)
|
||||
company[num].max_stock - company[num].stock_issued);
|
||||
|
||||
mvwaddstr(curwin, 5, 2, "Price per share: ");
|
||||
strfmon(buf, BUFSIZE, "%12n", company[num].share_price);
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[num].share_price);
|
||||
attrpr(curwin, ATTR_HIGHLIGHT_STR, "%12s", buf);
|
||||
|
||||
mvwaddstr(curwin, 6, 2, "Return: ");
|
||||
@ -524,7 +522,7 @@ void trade_shares (int num, bool *bid_used)
|
||||
|
||||
wmove(curwin, 6, 38);
|
||||
attrpr(curwin, ATTR_HIGHLIGHT_STR, "Current cash: ");
|
||||
strfmon(buf, BUFSIZE, "%16n", player[current_player].cash);
|
||||
l_strfmon(buf, BUFSIZE, "%16n", player[current_player].cash);
|
||||
attrpr(curwin, ATTR_WINDOW_TITLE, " %16s ", buf);
|
||||
|
||||
wrefresh(curwin);
|
||||
|
26
src/game.c
26
src/game.c
@ -455,7 +455,7 @@ void end_game (void)
|
||||
}
|
||||
|
||||
if (number_players == 1) {
|
||||
strfmon(buf, BUFSIZE, "%1n", total_value(0));
|
||||
l_strfmon(buf, BUFSIZE, "%1n", total_value(0));
|
||||
|
||||
newtxwin(9, 60, LINE_OFFSET + 8, COL_CENTER(60));
|
||||
wbkgd(curwin, ATTR_NORMAL_WINDOW);
|
||||
@ -468,10 +468,6 @@ void end_game (void)
|
||||
wait_for_key(curwin, 7, ATTR_WAITNORMAL_STR);
|
||||
deltxwin();
|
||||
} else {
|
||||
// Handle the locale's currency symbol
|
||||
struct lconv *lc = localeconv();
|
||||
assert(lc != NULL);
|
||||
|
||||
// Sort players on the basis of total value
|
||||
for (i = 0; i < number_players; i++) {
|
||||
player[i].sort_value = total_value(i);
|
||||
@ -489,12 +485,13 @@ void end_game (void)
|
||||
center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_STANDOUT_STR,
|
||||
"who is ", "%s", "*** BANKRUPT ***");
|
||||
} else {
|
||||
strfmon(buf, BUFSIZE, "%1n", player[0].sort_value);
|
||||
l_strfmon(buf, BUFSIZE, "%1n", player[0].sort_value);
|
||||
center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"with a value of ", "%s", buf);
|
||||
}
|
||||
|
||||
snprintf(buf, BUFSIZE, "Total Value (%s)", lc->currency_symbol);
|
||||
snprintf(buf, BUFSIZE, "Total Value (%s)",
|
||||
localeconv_info.currency_symbol);
|
||||
|
||||
int w = getmaxx(curwin) - 33;
|
||||
wattrset(curwin, ATTR_WINDOW_SUBTITLE);
|
||||
@ -502,7 +499,7 @@ void end_game (void)
|
||||
wattrset(curwin, ATTR_NORMAL_WINDOW);
|
||||
|
||||
for (i = 0; i < number_players; i++) {
|
||||
strfmon(buf, BUFSIZE, "%!18n", player[i].sort_value);
|
||||
l_strfmon(buf, BUFSIZE, "%!18n", player[i].sort_value);
|
||||
mvwprintw(curwin, i + 7, 2, "%5s %-*.*s %18s ",
|
||||
ordinal[i + 1], w, w, player[i].name, buf);
|
||||
}
|
||||
@ -677,9 +674,8 @@ void show_status (int num)
|
||||
center(curwin, 8, ATTR_NORMAL_WINDOW, "No companies on the map");
|
||||
} else {
|
||||
// Handle the locale's currency symbol
|
||||
struct lconv *lc = localeconv();
|
||||
assert(lc != NULL);
|
||||
snprintf(buf, BUFSIZE, "share (%s)", lc->currency_symbol);
|
||||
snprintf(buf, BUFSIZE, "share (%s)",
|
||||
localeconv_info.currency_symbol);
|
||||
|
||||
wattrset(curwin, ATTR_WINDOW_SUBTITLE);
|
||||
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ",
|
||||
@ -690,7 +686,7 @@ void show_status (int num)
|
||||
|
||||
for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
|
||||
if (company[i].on_map) {
|
||||
strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", company[i].share_price);
|
||||
mvwprintw(curwin, line, 2,
|
||||
" %-22s %10s %10.2f %'10ld %10.2f ",
|
||||
company[i].name, buf,
|
||||
@ -705,18 +701,18 @@ void show_status (int num)
|
||||
}
|
||||
|
||||
line = 15;
|
||||
strfmon(buf, BUFSIZE, "%18n", player[num].cash);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[num].cash);
|
||||
center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Current cash: ", " %s ", buf);
|
||||
if (player[num].debt != 0.0) {
|
||||
strfmon(buf, BUFSIZE, "%18n", player[num].debt);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", player[num].debt);
|
||||
center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Current debt: ", " %s ", buf);
|
||||
center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
|
||||
"Interest rate: ", " %17.2f%% ", interest_rate * 100.0);
|
||||
}
|
||||
|
||||
strfmon(buf, BUFSIZE, "%18n", val);
|
||||
l_strfmon(buf, BUFSIZE, "%18n", val);
|
||||
center2(curwin, line + 1, ATTR_HIGHLIGHT_STR, ATTR_WINDOW_TITLE,
|
||||
"Total value: ", " %s ", buf);
|
||||
|
||||
|
69
src/intf.c
69
src/intf.c
@ -1287,14 +1287,12 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
|
||||
{
|
||||
char *buf, *buf_copy;
|
||||
char *allowed, *emptystr, *defaultstr;
|
||||
struct lconv *lc = localeconv();
|
||||
double val;
|
||||
bool done;
|
||||
int ret;
|
||||
|
||||
|
||||
assert(result != NULL);
|
||||
assert(lc != NULL);
|
||||
|
||||
if (max < min) {
|
||||
double n = max;
|
||||
@ -1330,13 +1328,19 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
|
||||
*buf = '\0';
|
||||
|
||||
strcpy(allowed, "0123456789+-Ee");
|
||||
strncat(allowed, lc->decimal_point, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, lc->thousands_sep, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, lc->mon_decimal_point, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, lc->mon_thousands_sep, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.decimal_point,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.thousands_sep,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.mon_decimal_point,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.mon_thousands_sep,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
|
||||
snprintf(emptystr, BUFSIZE, "%'1.*f", lc->frac_digits, emptyval);
|
||||
snprintf(defaultstr, BUFSIZE, "%'1.*f", lc->frac_digits, defaultval);
|
||||
snprintf(emptystr, BUFSIZE, "%'1.*f", localeconv_info.frac_digits,
|
||||
emptyval);
|
||||
snprintf(defaultstr, BUFSIZE, "%'1.*f", localeconv_info.frac_digits,
|
||||
defaultval);
|
||||
|
||||
done = false;
|
||||
while (! done) {
|
||||
@ -1350,32 +1354,35 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
|
||||
buf_copy[BUFSIZE - 1] = '\0';
|
||||
|
||||
// Replace mon_decimal_point with decimal_point
|
||||
if (strcmp(lc->mon_decimal_point, lc->decimal_point) != 0) {
|
||||
while ((p = strstr(buf_copy, lc->mon_decimal_point)) != NULL) {
|
||||
if (strcmp(localeconv_info.mon_decimal_point, "") != 0
|
||||
&& strcmp(localeconv_info.decimal_point, "") != 0
|
||||
&& strcmp(localeconv_info.mon_decimal_point,
|
||||
localeconv_info.decimal_point) != 0) {
|
||||
while ((p = strstr(buf_copy, localeconv_info.mon_decimal_point)) != NULL) {
|
||||
char *pn;
|
||||
int len1 = strlen(lc->mon_decimal_point);
|
||||
int len2 = strlen(lc->decimal_point);
|
||||
int len1 = strlen(localeconv_info.mon_decimal_point);
|
||||
int len2 = strlen(localeconv_info.decimal_point);
|
||||
|
||||
// Make space for lc->decimal_point, if needed
|
||||
// Make space for localeconv_info.decimal_point, if needed
|
||||
memmove(p + len2, p + len1, strlen(p) - (len2 - len1) + 1);
|
||||
|
||||
// Copy lc->decimal_point over p WITHOUT copying ending NUL
|
||||
for (pn = lc->decimal_point; *pn != '\0'; pn++, p++) {
|
||||
// Copy localeconv_info.decimal_point over p WITHOUT copying ending NUL
|
||||
for (pn = localeconv_info.decimal_point; *pn != '\0'; pn++, p++) {
|
||||
*p = *pn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove thousands separators if required
|
||||
if (strcmp(lc->thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, lc->thousands_sep)) != NULL) {
|
||||
int len = strlen(lc->thousands_sep);
|
||||
if (strcmp(localeconv_info.thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, localeconv_info.thousands_sep)) != NULL) {
|
||||
int len = strlen(localeconv_info.thousands_sep);
|
||||
memmove(p, p + len, strlen(p) - len + 1);
|
||||
}
|
||||
}
|
||||
if (strcmp(lc->mon_thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, lc->mon_thousands_sep)) != NULL) {
|
||||
int len = strlen(lc->thousands_sep);
|
||||
if (strcmp(localeconv_info.mon_thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, localeconv_info.mon_thousands_sep)) != NULL) {
|
||||
int len = strlen(localeconv_info.thousands_sep);
|
||||
memmove(p, p + len, strlen(p) - len + 1);
|
||||
}
|
||||
}
|
||||
@ -1427,14 +1434,12 @@ int gettxlong (WINDOW *win, long *result, long min, long max, long emptyval,
|
||||
{
|
||||
char *buf, *buf_copy;
|
||||
char *allowed, *emptystr, *defaultstr;
|
||||
struct lconv *lc = localeconv();
|
||||
long val;
|
||||
bool done;
|
||||
int ret;
|
||||
|
||||
|
||||
assert(result != NULL);
|
||||
assert(lc != NULL);
|
||||
|
||||
if (max < min) {
|
||||
long n = max;
|
||||
@ -1470,8 +1475,10 @@ int gettxlong (WINDOW *win, long *result, long min, long max, long emptyval,
|
||||
*buf = '\0';
|
||||
|
||||
strcpy(allowed, "0123456789+-");
|
||||
strncat(allowed, lc->thousands_sep, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, lc->mon_thousands_sep, BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.thousands_sep,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
strncat(allowed, localeconv_info.mon_thousands_sep,
|
||||
BUFSIZE - strlen(allowed) - 1);
|
||||
|
||||
snprintf(emptystr, BUFSIZE, "%'1ld", emptyval);
|
||||
snprintf(defaultstr, BUFSIZE, "%'1ld", defaultval);
|
||||
@ -1488,15 +1495,15 @@ int gettxlong (WINDOW *win, long *result, long min, long max, long emptyval,
|
||||
buf_copy[BUFSIZE - 1] = '\0';
|
||||
|
||||
// Remove thousands separators if required
|
||||
if (strcmp(lc->thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, lc->thousands_sep)) != NULL) {
|
||||
int len = strlen(lc->thousands_sep);
|
||||
if (strcmp(localeconv_info.thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, localeconv_info.thousands_sep)) != NULL) {
|
||||
int len = strlen(localeconv_info.thousands_sep);
|
||||
memmove(p, p + len, strlen(p) - len + 1);
|
||||
}
|
||||
}
|
||||
if (strcmp(lc->mon_thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, lc->mon_thousands_sep)) != NULL) {
|
||||
int len = strlen(lc->thousands_sep);
|
||||
if (strcmp(localeconv_info.mon_thousands_sep, "") != 0) {
|
||||
while ((p = strstr(buf_copy, localeconv_info.mon_thousands_sep)) != NULL) {
|
||||
int len = strlen(localeconv_info.thousands_sep);
|
||||
memmove(p, p + len, strlen(p) - len + 1);
|
||||
}
|
||||
}
|
||||
|
15
src/move.c
15
src/move.c
@ -789,10 +789,7 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
"%-20s", company[aa].name);
|
||||
|
||||
// Handle the locale's currency symbol
|
||||
struct lconv *lc = localeconv();
|
||||
assert(lc != NULL);
|
||||
|
||||
snprintf(buf, BUFSIZE, "Bonus (%s)", lc->currency_symbol);
|
||||
snprintf(buf, BUFSIZE, "Bonus (%s)", localeconv_info.currency_symbol);
|
||||
|
||||
int w = getmaxx(curwin) - 52;
|
||||
wattrset(curwin, ATTR_WINDOW_SUBTITLE);
|
||||
@ -816,7 +813,7 @@ void merge_companies (map_val_t a, map_val_t b)
|
||||
player[i].stock_owned[bb] = 0;
|
||||
player[i].cash += bonus;
|
||||
|
||||
strfmon(buf, BUFSIZE, "%!12n", bonus);
|
||||
l_strfmon(buf, BUFSIZE, "%!12n", bonus);
|
||||
mvwprintw(curwin, line, 2, " %-*.*s %'8ld %'8ld %'8ld %12s ",
|
||||
w, w, player[i].name, old_stock, new_stock,
|
||||
player[i].stock_owned[aa], buf);
|
||||
@ -992,11 +989,11 @@ void adjust_values (void)
|
||||
center(curwin, 7, ATTR_ERROR_WINDOW,
|
||||
"of the share value on each share owned.");
|
||||
|
||||
strfmon(buf, BUFSIZE, "%12n", company[which].share_price);
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[which].share_price);
|
||||
center2(curwin, 9, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
|
||||
"Old share value: ", "%s", buf);
|
||||
|
||||
strfmon(buf, BUFSIZE, "%12n", company[which].share_price * rate);
|
||||
l_strfmon(buf, BUFSIZE, "%12n", company[which].share_price * rate);
|
||||
center2(curwin, 10, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
|
||||
"Amount paid per share: ", "%s", buf);
|
||||
|
||||
@ -1095,10 +1092,10 @@ void adjust_values (void)
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Interstellar Trading Bank ");
|
||||
|
||||
strfmon(buf, BUFSIZE, "%1n", player[current_player].debt);
|
||||
l_strfmon(buf, BUFSIZE, "%1n", player[current_player].debt);
|
||||
center(curwin, 3, ATTR_ERROR_STR, "Your debt has amounted to %s", buf);
|
||||
|
||||
strfmon(buf, BUFSIZE, "%1n", impounded);
|
||||
l_strfmon(buf, BUFSIZE, "%1n", impounded);
|
||||
center3(curwin, 4, ATTR_ERROR_WINDOW, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
|
||||
"The Bank has impounded ", " from your cash", "%s", buf);
|
||||
|
||||
|
@ -343,6 +343,9 @@ void init_program (void)
|
||||
// Initialise the random number generator
|
||||
init_rand();
|
||||
|
||||
// Initialise locale-specific variables
|
||||
init_locale();
|
||||
|
||||
// Initialise signal-handling functions
|
||||
// @@@ To be completed
|
||||
|
||||
|
145
src/utils.c
145
src/utils.c
@ -31,6 +31,14 @@
|
||||
#include "trader.h"
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Global variable definitions *
|
||||
************************************************************************/
|
||||
|
||||
// Global copy, suitably modified, of localeconv() information
|
||||
struct lconv localeconv_info;
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific constants and variable definitions *
|
||||
************************************************************************/
|
||||
@ -38,6 +46,12 @@
|
||||
#define GAME_FILENAME_PROTO "game%d"
|
||||
#define GAME_FILENAME_BUFSIZE 16
|
||||
|
||||
// Default values used to override POSIX locale
|
||||
#define MOD_POSIX_CURRENCY_SYMBOL "$"
|
||||
#define MOD_POSIX_FRAC_DIGITS 2
|
||||
#define MOD_POSIX_P_CS_PRECEDES 1
|
||||
#define MOD_POSIX_P_SEP_BY_SPACE 0
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module-specific variables *
|
||||
@ -47,6 +61,9 @@ static char *program_name_str = NULL; // Canonical program name
|
||||
static char *home_directory_str = NULL; // Full pathname to home
|
||||
static char *data_directory_str = NULL; // Writable data dir pathname
|
||||
|
||||
static char *current_mon_locale; // As returned by setlocale()
|
||||
static bool add_currency_symbol = false; // Do we need to add "$"?
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Initialisation and environment function definitions *
|
||||
@ -56,6 +73,8 @@ static char *data_directory_str = NULL; // Writable data dir pathname
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// init_program_name: Make the program name "canonical"
|
||||
|
||||
void init_program_name (char *argv[])
|
||||
{
|
||||
if (argv == NULL || argv[0] == NULL || *argv[0] == '\0') {
|
||||
@ -73,6 +92,8 @@ void init_program_name (char *argv[])
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// program_name: Return the canonical program name
|
||||
|
||||
const char *program_name (void)
|
||||
{
|
||||
if (program_name_str == NULL) {
|
||||
@ -84,6 +105,8 @@ const char *program_name (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// home_directory: Return home directory pathname
|
||||
|
||||
const char *home_directory (void)
|
||||
{
|
||||
if (home_directory_str == NULL) {
|
||||
@ -100,6 +123,8 @@ const char *home_directory (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// data_directory: Return writable data directory pathname
|
||||
|
||||
const char *data_directory (void)
|
||||
{
|
||||
/* This implementation assumes a POSIX environment by using "/" as
|
||||
@ -126,6 +151,8 @@ const char *data_directory (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// game_filename: Convert an integer to a game filename
|
||||
|
||||
char *game_filename (int gamenum)
|
||||
{
|
||||
/* This implementation assumes a POSIX environment by using "/" as
|
||||
@ -170,6 +197,8 @@ char *game_filename (int gamenum)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// err_exit: Print an error and exit
|
||||
|
||||
void err_exit (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -188,6 +217,8 @@ void err_exit (const char *format, ...)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// errno_exit: Print an error message (using errno) and exit
|
||||
|
||||
void errno_exit (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -210,6 +241,8 @@ void errno_exit (const char *format, ...)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// err_exit_nomem: Print an "out of memory" error and exit
|
||||
|
||||
void err_exit_nomem (void)
|
||||
{
|
||||
err_exit("out of memory");
|
||||
@ -224,6 +257,8 @@ void err_exit_nomem (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// init_rand: Initialise the random number generator
|
||||
|
||||
void init_rand (void)
|
||||
{
|
||||
/* Ideally, initialisation of the random number generator should be
|
||||
@ -238,6 +273,8 @@ void init_rand (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// randf: Return a random number between 0.0 and 1.0
|
||||
|
||||
extern double randf (void)
|
||||
{
|
||||
return drand48();
|
||||
@ -245,13 +282,119 @@ extern double randf (void)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// randi: Return a random number between 0 and limit
|
||||
|
||||
extern int randi (int limit)
|
||||
{
|
||||
return drand48() * (double) limit;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Locale-aware function definitions *
|
||||
************************************************************************/
|
||||
|
||||
// These functions are documented in the file "utils.h"
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// init_locale: Initialise locale-specific variables
|
||||
|
||||
void init_locale (void)
|
||||
{
|
||||
struct lconv *lc;
|
||||
|
||||
|
||||
current_mon_locale = setlocale(LC_MONETARY, NULL);
|
||||
lc = localeconv();
|
||||
|
||||
assert(current_mon_locale != NULL);
|
||||
assert(lc != NULL);
|
||||
|
||||
localeconv_info = *lc;
|
||||
|
||||
/* Are we in the POSIX locale? This test may not be portable as the
|
||||
string returned by setlocale() is supposed to be opaque. */
|
||||
add_currency_symbol = false;
|
||||
if (strcmp(current_mon_locale, "POSIX") == 0
|
||||
|| strcmp(current_mon_locale, "C") == 0) {
|
||||
|
||||
add_currency_symbol = true;
|
||||
localeconv_info.currency_symbol = MOD_POSIX_CURRENCY_SYMBOL;
|
||||
localeconv_info.frac_digits = MOD_POSIX_FRAC_DIGITS;
|
||||
localeconv_info.p_cs_precedes = MOD_POSIX_P_CS_PRECEDES;
|
||||
localeconv_info.p_sep_by_space = MOD_POSIX_P_SEP_BY_SPACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// l_strfmon: Convert monetary value to a string
|
||||
|
||||
ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
const char *restrict format, double val)
|
||||
{
|
||||
/* The current implementation assumes MOD_POSIX_P_CS_PRECEDES is 1
|
||||
(currency symbol precedes value) and that MOD_POSIX_P_SEP_BY_SPACE
|
||||
is 0 (no space separates currency symbol and value). It does,
|
||||
however, handle currency symbols of length > 1 */
|
||||
assert(MOD_POSIX_P_CS_PRECEDES == 1);
|
||||
assert(MOD_POSIX_P_SEP_BY_SPACE == 0);
|
||||
|
||||
ssize_t ret = strfmon(s, maxsize, format, val);
|
||||
|
||||
if (ret > 0 && add_currency_symbol) {
|
||||
if (strstr(format, "!") == NULL) {
|
||||
/* Insert localeconv_info.currency_symbol to s.
|
||||
|
||||
NB: add_currecy_symbol == true assumes POSIX locale:
|
||||
single-byte strings are in effect, so strlen(), etc, work
|
||||
correctly. */
|
||||
const char *sym = localeconv_info.currency_symbol;
|
||||
int symlen = strlen(sym);
|
||||
char *p;
|
||||
int spc;
|
||||
|
||||
// Count number of leading spaces
|
||||
for (p = s, spc = 0; *p == ' '; p++, spc++)
|
||||
;
|
||||
|
||||
if (symlen <= spc) {
|
||||
/* Enough space for currency symbol: copy it WITHOUT
|
||||
copying terminating NUL character */
|
||||
for (p -= symlen; *sym != '\0'; p++, sym++) {
|
||||
*p = *sym;
|
||||
}
|
||||
} else {
|
||||
// Make space for currency symbol, then copy it
|
||||
|
||||
memmove(s + symlen - spc, s, maxsize - (symlen - spc) + 1);
|
||||
s[maxsize - 1] = '\0';
|
||||
|
||||
for ( ; *sym != '\0'; sym++, s++) {
|
||||
// Make sure terminating NUL character is NOT copied!
|
||||
*s = *sym;
|
||||
}
|
||||
|
||||
ret = MIN(ret + symlen - spc, maxsize - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Encryption function definitions *
|
||||
************************************************************************/
|
||||
|
||||
// These functions are documented in the file "utils.h"
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// scramble: Scramble (encrypt) the buffer
|
||||
|
||||
char *scramble (int key, char *buf, int bufsize)
|
||||
{
|
||||
/* The algorithm used here is reversable: scramble(scramble(...))
|
||||
@ -281,6 +424,8 @@ char *scramble (int key, char *buf, int bufsize)
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// unscramble: Unscramble (decrypt) the buffer
|
||||
|
||||
char *unscramble (int key, char *buf, int bufsize)
|
||||
{
|
||||
return scramble(key, buf, bufsize);
|
||||
|
44
src/utils.h
44
src/utils.h
@ -42,6 +42,14 @@
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Global variable declarations *
|
||||
************************************************************************/
|
||||
|
||||
// Global copy, suitably modified, of localeconv() information
|
||||
extern struct lconv localeconv_info;
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Initialisation and environment function prototypes *
|
||||
************************************************************************/
|
||||
@ -209,6 +217,42 @@ extern double randf (void);
|
||||
extern int randi (int limit);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Locale-aware function prototypes *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Function: init_locale - Initialise locale-specific variables
|
||||
Parameters: (none)
|
||||
Returns: (nothing)
|
||||
|
||||
This function initialises the global variable localeconv_info with
|
||||
values suitable for this program. In particular, if the POSIX or C
|
||||
locale is in effect, the currency_symbol and frac_digits members are
|
||||
updated to be something reasonable. This function must be called
|
||||
before using localeconf_info.
|
||||
*/
|
||||
extern void init_locale (void);
|
||||
|
||||
|
||||
/*
|
||||
Function: l_strfmon - Convert monetary value to a string
|
||||
Parameters: s - Buffer to receive result
|
||||
maxsize - Maximum size of buffer
|
||||
format - strfmon() format to use
|
||||
val - Monetary value to convert
|
||||
Returns: ssize_t - Size of returned string
|
||||
|
||||
This function calls strfmon() to convert val to a suitable monetary
|
||||
value string. If the POSIX or C locale is in effect, and "!" does NOT
|
||||
appear in the format, "$" is inserted into the resulting string. This
|
||||
function overcomes the limitation that the POSIX locale does not define
|
||||
anything for localeconv()->currency_symbol.
|
||||
*/
|
||||
extern ssize_t l_strfmon (char *restrict s, size_t maxsize,
|
||||
const char *restrict format, double val);
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Encryption function prototypes *
|
||||
************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user