1
0
mirror of https://git.zap.org.au/git/trader.git synced 2024-10-27 18:20:13 -04: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:
John Zaitseff 2011-07-20 10:44:44 +10:00
parent e56247b1b4
commit da7477dc28
7 changed files with 269 additions and 79 deletions

View File

@ -96,9 +96,8 @@ void exchange_stock (void)
} }
// Handle the locale's currency symbol // Handle the locale's currency symbol
struct lconv *lc = localeconv(); snprintf(buf, BUFSIZE, "share (%s)",
assert(lc != NULL); localeconv_info.currency_symbol);
snprintf(buf, BUFSIZE, "share (%s)", lc->currency_symbol);
wattrset(curwin, ATTR_WINDOW_SUBTITLE); wattrset(curwin, ATTR_WINDOW_SUBTITLE);
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ", mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ",
@ -111,7 +110,7 @@ void exchange_stock (void)
if (company[i].on_map) { if (company[i].on_map) {
mvwaddch(curwin, line, 2, PRINTABLE_MAP_VAL(COMPANY_TO_MAP(i)) | mvwaddch(curwin, line, 2, PRINTABLE_MAP_VAL(COMPANY_TO_MAP(i)) |
ATTR_MAP_CHOICE); 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 ", mvwprintw(curwin, line, 4, "%-22s %12s %10.2f %'10ld %'10ld ",
company[i].name, buf, company[i].share_return company[i].name, buf, company[i].share_return
* 100.0, company[i].stock_issued, * 100.0, company[i].stock_issued,
@ -241,9 +240,6 @@ void visit_bank (void)
double val, max; double val, max;
char *buf; char *buf;
struct lconv *lc = localeconv();
assert(lc != NULL);
buf = malloc(BUFSIZE); buf = malloc(BUFSIZE);
if (buf == NULL) { if (buf == NULL) {
@ -263,18 +259,18 @@ void visit_bank (void)
center(curwin, 1, ATTR_WINDOW_TITLE, " Interstellar Trading Bank "); 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, center2(curwin, 3, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Current cash: ", " %s ", buf); "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, center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Current debt: ", " %s ", buf); "Current debt: ", " %s ", buf);
center2(curwin, 5, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR, center2(curwin, 5, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Interest rate: ", " %17.2f%% ", interest_rate * 100.0); "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, center2(curwin, 7, ATTR_HIGHLIGHT_STR, ATTR_WINDOW_TITLE,
"Credit limit: ", " %s ", buf); "Credit limit: ", " %s ", buf);
@ -354,16 +350,17 @@ void visit_bank (void)
mvwprintw(curwin, 3, 10, "How much do you wish to borrow? "); mvwprintw(curwin, 3, 10, "How much do you wish to borrow? ");
wattron(curwin, A_BOLD); wattron(curwin, A_BOLD);
if (lc->p_cs_precedes == 1) { if (localeconv_info.p_cs_precedes == 1) {
wprintw(curwin, "%s%s", lc->currency_symbol, wprintw(curwin, "%s%s", localeconv_info.currency_symbol,
(lc->p_sep_by_space == 1) ? " " : ""); (localeconv_info.p_sep_by_space == 1) ? " " : "");
n = 10; n = 10;
} else { } else {
getyx(curwin, y, x); 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", mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
(lc->p_sep_by_space == 1) ? " " : "", (localeconv_info.p_sep_by_space == 1) ? " " : "",
lc->currency_symbol); localeconv_info.currency_symbol);
wmove(curwin, y, x); wmove(curwin, y, x);
} }
wattroff(curwin, A_BOLD); wattroff(curwin, A_BOLD);
@ -414,16 +411,17 @@ void visit_bank (void)
mvwprintw(curwin, 3, 10, "How much do you wish to repay? "); mvwprintw(curwin, 3, 10, "How much do you wish to repay? ");
wattron(curwin, A_BOLD); wattron(curwin, A_BOLD);
if (lc->p_cs_precedes == 1) { if (localeconv_info.p_cs_precedes == 1) {
wprintw(curwin, "%s%s", lc->currency_symbol, wprintw(curwin, "%s%s", localeconv_info.currency_symbol,
(lc->p_sep_by_space == 1) ? " " : ""); (localeconv_info.p_sep_by_space == 1) ? " " : "");
n = 10; n = 10;
} else { } else {
getyx(curwin, y, x); 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", mvwprintw(curwin, y, getmaxx(curwin) - n, "%s%s",
(lc->p_sep_by_space == 1) ? " " : "", (localeconv_info.p_sep_by_space == 1) ? " " : "",
lc->currency_symbol); localeconv_info.currency_symbol);
wmove(curwin, y, x); wmove(curwin, y, x);
} }
wattroff(curwin, A_BOLD); wattroff(curwin, A_BOLD);
@ -508,7 +506,7 @@ void trade_shares (int num, bool *bid_used)
company[num].max_stock - company[num].stock_issued); company[num].max_stock - company[num].stock_issued);
mvwaddstr(curwin, 5, 2, "Price per share: "); 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); attrpr(curwin, ATTR_HIGHLIGHT_STR, "%12s", buf);
mvwaddstr(curwin, 6, 2, "Return: "); mvwaddstr(curwin, 6, 2, "Return: ");
@ -524,7 +522,7 @@ void trade_shares (int num, bool *bid_used)
wmove(curwin, 6, 38); wmove(curwin, 6, 38);
attrpr(curwin, ATTR_HIGHLIGHT_STR, "Current cash: "); 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); attrpr(curwin, ATTR_WINDOW_TITLE, " %16s ", buf);
wrefresh(curwin); wrefresh(curwin);

View File

@ -455,7 +455,7 @@ void end_game (void)
} }
if (number_players == 1) { 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)); newtxwin(9, 60, LINE_OFFSET + 8, COL_CENTER(60));
wbkgd(curwin, ATTR_NORMAL_WINDOW); wbkgd(curwin, ATTR_NORMAL_WINDOW);
@ -468,10 +468,6 @@ void end_game (void)
wait_for_key(curwin, 7, ATTR_WAITNORMAL_STR); wait_for_key(curwin, 7, ATTR_WAITNORMAL_STR);
deltxwin(); deltxwin();
} else { } else {
// Handle the locale's currency symbol
struct lconv *lc = localeconv();
assert(lc != NULL);
// Sort players on the basis of total value // Sort players on the basis of total value
for (i = 0; i < number_players; i++) { for (i = 0; i < number_players; i++) {
player[i].sort_value = total_value(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, center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_STANDOUT_STR,
"who is ", "%s", "*** BANKRUPT ***"); "who is ", "%s", "*** BANKRUPT ***");
} else { } 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, center2(curwin, 4, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"with a value of ", "%s", buf); "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; int w = getmaxx(curwin) - 33;
wattrset(curwin, ATTR_WINDOW_SUBTITLE); wattrset(curwin, ATTR_WINDOW_SUBTITLE);
@ -502,7 +499,7 @@ void end_game (void)
wattrset(curwin, ATTR_NORMAL_WINDOW); wattrset(curwin, ATTR_NORMAL_WINDOW);
for (i = 0; i < number_players; i++) { 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 ", mvwprintw(curwin, i + 7, 2, "%5s %-*.*s %18s ",
ordinal[i + 1], w, w, player[i].name, buf); 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"); center(curwin, 8, ATTR_NORMAL_WINDOW, "No companies on the map");
} else { } else {
// Handle the locale's currency symbol // Handle the locale's currency symbol
struct lconv *lc = localeconv(); snprintf(buf, BUFSIZE, "share (%s)",
assert(lc != NULL); localeconv_info.currency_symbol);
snprintf(buf, BUFSIZE, "share (%s)", lc->currency_symbol);
wattrset(curwin, ATTR_WINDOW_SUBTITLE); wattrset(curwin, ATTR_WINDOW_SUBTITLE);
mvwprintw(curwin, 4, 2, " %-22s %12s %10s %10s %10s ", 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++) { for (line = 6, i = 0; i < MAX_COMPANIES; i++) {
if (company[i].on_map) { 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, mvwprintw(curwin, line, 2,
" %-22s %10s %10.2f %'10ld %10.2f ", " %-22s %10s %10.2f %'10ld %10.2f ",
company[i].name, buf, company[i].name, buf,
@ -705,18 +701,18 @@ void show_status (int num)
} }
line = 15; 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, center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Current cash: ", " %s ", buf); "Current cash: ", " %s ", buf);
if (player[num].debt != 0.0) { 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, center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Current debt: ", " %s ", buf); "Current debt: ", " %s ", buf);
center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR, center2(curwin, line++, ATTR_NORMAL_WINDOW, ATTR_HIGHLIGHT_STR,
"Interest rate: ", " %17.2f%% ", interest_rate * 100.0); "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, center2(curwin, line + 1, ATTR_HIGHLIGHT_STR, ATTR_WINDOW_TITLE,
"Total value: ", " %s ", buf); "Total value: ", " %s ", buf);

View File

@ -1287,14 +1287,12 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
{ {
char *buf, *buf_copy; char *buf, *buf_copy;
char *allowed, *emptystr, *defaultstr; char *allowed, *emptystr, *defaultstr;
struct lconv *lc = localeconv();
double val; double val;
bool done; bool done;
int ret; int ret;
assert(result != NULL); assert(result != NULL);
assert(lc != NULL);
if (max < min) { if (max < min) {
double n = max; double n = max;
@ -1330,13 +1328,19 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
*buf = '\0'; *buf = '\0';
strcpy(allowed, "0123456789+-Ee"); strcpy(allowed, "0123456789+-Ee");
strncat(allowed, lc->decimal_point, BUFSIZE - strlen(allowed) - 1); strncat(allowed, localeconv_info.decimal_point,
strncat(allowed, lc->thousands_sep, BUFSIZE - strlen(allowed) - 1); BUFSIZE - strlen(allowed) - 1);
strncat(allowed, lc->mon_decimal_point, BUFSIZE - strlen(allowed) - 1); strncat(allowed, localeconv_info.thousands_sep,
strncat(allowed, lc->mon_thousands_sep, BUFSIZE - strlen(allowed) - 1); 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(emptystr, BUFSIZE, "%'1.*f", localeconv_info.frac_digits,
snprintf(defaultstr, BUFSIZE, "%'1.*f", lc->frac_digits, defaultval); emptyval);
snprintf(defaultstr, BUFSIZE, "%'1.*f", localeconv_info.frac_digits,
defaultval);
done = false; done = false;
while (! done) { while (! done) {
@ -1350,32 +1354,35 @@ int gettxdouble (WINDOW *win, double *result, double min, double max,
buf_copy[BUFSIZE - 1] = '\0'; buf_copy[BUFSIZE - 1] = '\0';
// Replace mon_decimal_point with decimal_point // Replace mon_decimal_point with decimal_point
if (strcmp(lc->mon_decimal_point, lc->decimal_point) != 0) { if (strcmp(localeconv_info.mon_decimal_point, "") != 0
while ((p = strstr(buf_copy, lc->mon_decimal_point)) != NULL) { && 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; char *pn;
int len1 = strlen(lc->mon_decimal_point); int len1 = strlen(localeconv_info.mon_decimal_point);
int len2 = strlen(lc->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); memmove(p + len2, p + len1, strlen(p) - (len2 - len1) + 1);
// Copy lc->decimal_point over p WITHOUT copying ending NUL // Copy localeconv_info.decimal_point over p WITHOUT copying ending NUL
for (pn = lc->decimal_point; *pn != '\0'; pn++, p++) { for (pn = localeconv_info.decimal_point; *pn != '\0'; pn++, p++) {
*p = *pn; *p = *pn;
} }
} }
} }
// Remove thousands separators if required // Remove thousands separators if required
if (strcmp(lc->thousands_sep, "") != 0) { if (strcmp(localeconv_info.thousands_sep, "") != 0) {
while ((p = strstr(buf_copy, lc->thousands_sep)) != NULL) { while ((p = strstr(buf_copy, localeconv_info.thousands_sep)) != NULL) {
int len = strlen(lc->thousands_sep); int len = strlen(localeconv_info.thousands_sep);
memmove(p, p + len, strlen(p) - len + 1); memmove(p, p + len, strlen(p) - len + 1);
} }
} }
if (strcmp(lc->mon_thousands_sep, "") != 0) { if (strcmp(localeconv_info.mon_thousands_sep, "") != 0) {
while ((p = strstr(buf_copy, lc->mon_thousands_sep)) != NULL) { while ((p = strstr(buf_copy, localeconv_info.mon_thousands_sep)) != NULL) {
int len = strlen(lc->thousands_sep); int len = strlen(localeconv_info.thousands_sep);
memmove(p, p + len, strlen(p) - len + 1); 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 *buf, *buf_copy;
char *allowed, *emptystr, *defaultstr; char *allowed, *emptystr, *defaultstr;
struct lconv *lc = localeconv();
long val; long val;
bool done; bool done;
int ret; int ret;
assert(result != NULL); assert(result != NULL);
assert(lc != NULL);
if (max < min) { if (max < min) {
long n = max; long n = max;
@ -1470,8 +1475,10 @@ int gettxlong (WINDOW *win, long *result, long min, long max, long emptyval,
*buf = '\0'; *buf = '\0';
strcpy(allowed, "0123456789+-"); strcpy(allowed, "0123456789+-");
strncat(allowed, lc->thousands_sep, BUFSIZE - strlen(allowed) - 1); strncat(allowed, localeconv_info.thousands_sep,
strncat(allowed, lc->mon_thousands_sep, BUFSIZE - strlen(allowed) - 1); BUFSIZE - strlen(allowed) - 1);
strncat(allowed, localeconv_info.mon_thousands_sep,
BUFSIZE - strlen(allowed) - 1);
snprintf(emptystr, BUFSIZE, "%'1ld", emptyval); snprintf(emptystr, BUFSIZE, "%'1ld", emptyval);
snprintf(defaultstr, BUFSIZE, "%'1ld", defaultval); 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'; buf_copy[BUFSIZE - 1] = '\0';
// Remove thousands separators if required // Remove thousands separators if required
if (strcmp(lc->thousands_sep, "") != 0) { if (strcmp(localeconv_info.thousands_sep, "") != 0) {
while ((p = strstr(buf_copy, lc->thousands_sep)) != NULL) { while ((p = strstr(buf_copy, localeconv_info.thousands_sep)) != NULL) {
int len = strlen(lc->thousands_sep); int len = strlen(localeconv_info.thousands_sep);
memmove(p, p + len, strlen(p) - len + 1); memmove(p, p + len, strlen(p) - len + 1);
} }
} }
if (strcmp(lc->mon_thousands_sep, "") != 0) { if (strcmp(localeconv_info.mon_thousands_sep, "") != 0) {
while ((p = strstr(buf_copy, lc->mon_thousands_sep)) != NULL) { while ((p = strstr(buf_copy, localeconv_info.mon_thousands_sep)) != NULL) {
int len = strlen(lc->thousands_sep); int len = strlen(localeconv_info.thousands_sep);
memmove(p, p + len, strlen(p) - len + 1); memmove(p, p + len, strlen(p) - len + 1);
} }
} }

View File

@ -789,10 +789,7 @@ void merge_companies (map_val_t a, map_val_t b)
"%-20s", company[aa].name); "%-20s", company[aa].name);
// Handle the locale's currency symbol // Handle the locale's currency symbol
struct lconv *lc = localeconv(); snprintf(buf, BUFSIZE, "Bonus (%s)", localeconv_info.currency_symbol);
assert(lc != NULL);
snprintf(buf, BUFSIZE, "Bonus (%s)", lc->currency_symbol);
int w = getmaxx(curwin) - 52; int w = getmaxx(curwin) - 52;
wattrset(curwin, ATTR_WINDOW_SUBTITLE); 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].stock_owned[bb] = 0;
player[i].cash += bonus; player[i].cash += bonus;
strfmon(buf, BUFSIZE, "%!12n", bonus); l_strfmon(buf, BUFSIZE, "%!12n", bonus);
mvwprintw(curwin, line, 2, " %-*.*s %'8ld %'8ld %'8ld %12s ", mvwprintw(curwin, line, 2, " %-*.*s %'8ld %'8ld %'8ld %12s ",
w, w, player[i].name, old_stock, new_stock, w, w, player[i].name, old_stock, new_stock,
player[i].stock_owned[aa], buf); player[i].stock_owned[aa], buf);
@ -992,11 +989,11 @@ void adjust_values (void)
center(curwin, 7, ATTR_ERROR_WINDOW, center(curwin, 7, ATTR_ERROR_WINDOW,
"of the share value on each share owned."); "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, center2(curwin, 9, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
"Old share value: ", "%s", buf); "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, center2(curwin, 10, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
"Amount paid per share: ", "%s", buf); "Amount paid per share: ", "%s", buf);
@ -1095,10 +1092,10 @@ void adjust_values (void)
center(curwin, 1, ATTR_ERROR_TITLE, " Interstellar Trading Bank "); 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); 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, center3(curwin, 4, ATTR_ERROR_WINDOW, ATTR_ERROR_WINDOW, ATTR_ERROR_STR,
"The Bank has impounded ", " from your cash", "%s", buf); "The Bank has impounded ", " from your cash", "%s", buf);

View File

@ -343,6 +343,9 @@ void init_program (void)
// Initialise the random number generator // Initialise the random number generator
init_rand(); init_rand();
// Initialise locale-specific variables
init_locale();
// Initialise signal-handling functions // Initialise signal-handling functions
// @@@ To be completed // @@@ To be completed

View File

@ -31,6 +31,14 @@
#include "trader.h" #include "trader.h"
/************************************************************************
* Global variable definitions *
************************************************************************/
// Global copy, suitably modified, of localeconv() information
struct lconv localeconv_info;
/************************************************************************ /************************************************************************
* Module-specific constants and variable definitions * * Module-specific constants and variable definitions *
************************************************************************/ ************************************************************************/
@ -38,6 +46,12 @@
#define GAME_FILENAME_PROTO "game%d" #define GAME_FILENAME_PROTO "game%d"
#define GAME_FILENAME_BUFSIZE 16 #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 * * 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 *home_directory_str = NULL; // Full pathname to home
static char *data_directory_str = NULL; // Writable data dir pathname 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 * * 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[]) void init_program_name (char *argv[])
{ {
if (argv == NULL || argv[0] == NULL || *argv[0] == '\0') { 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) const char *program_name (void)
{ {
if (program_name_str == NULL) { 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) const char *home_directory (void)
{ {
if (home_directory_str == NULL) { 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) const char *data_directory (void)
{ {
/* This implementation assumes a POSIX environment by using "/" as /* 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) char *game_filename (int gamenum)
{ {
/* This implementation assumes a POSIX environment by using "/" as /* 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, ...) void err_exit (const char *format, ...)
{ {
va_list args; 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, ...) void errno_exit (const char *format, ...)
{ {
va_list args; 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) void err_exit_nomem (void)
{ {
err_exit("out of memory"); 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) void init_rand (void)
{ {
/* Ideally, initialisation of the random number generator should be /* 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) extern double randf (void)
{ {
return drand48(); return drand48();
@ -245,13 +282,119 @@ extern double randf (void)
/***********************************************************************/ /***********************************************************************/
// randi: Return a random number between 0 and limit
extern int randi (int limit) extern int randi (int limit)
{ {
return drand48() * (double) 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) char *scramble (int key, char *buf, int bufsize)
{ {
/* The algorithm used here is reversable: scramble(scramble(...)) /* 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) char *unscramble (int key, char *buf, int bufsize)
{ {
return scramble(key, buf, bufsize); return scramble(key, buf, bufsize);

View File

@ -42,6 +42,14 @@
#define MAX(a, b) ((a) > (b) ? (a) : (b)) #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 * * Initialisation and environment function prototypes *
************************************************************************/ ************************************************************************/
@ -209,6 +217,42 @@ extern double randf (void);
extern int randi (int limit); 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 * * Encryption function prototypes *
************************************************************************/ ************************************************************************/