mirror of
https://github.com/postgres/postgres.git
synced 2025-06-23 14:01:44 +03:00
Modify locale code to defend against possibility that it was compiled
with an -fsigned-char/-funsigned-char setting opposite to that of libc, thus breaking the convention that 'undefined' values returned by localeconv() are represented by CHAR_MAX. It is sheer stupidity that gcc even has such a switch --- it's just as bad as the structure-packing control switches offered by the more brain-dead PC compilers --- and as for the behavior of Linux distribution vendors who set RPM_OPT_FLAGS differently from the way they built libc, well, words fail me...
This commit is contained in:
@ -9,7 +9,7 @@
|
|||||||
* workings can be found in the book "Software Solutions in C" by
|
* workings can be found in the book "Software Solutions in C" by
|
||||||
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
|
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.45 2000/08/03 16:34:22 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.46 2000/11/18 03:55:51 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -91,9 +91,19 @@ cash_in(PG_FUNCTION_ARGS)
|
|||||||
if (lconvert == NULL)
|
if (lconvert == NULL)
|
||||||
lconvert = localeconv();
|
lconvert = localeconv();
|
||||||
|
|
||||||
/* frac_digits in the C locale seems to return CHAR_MAX */
|
/*
|
||||||
/* best guess is 2 in this case I think */
|
* frac_digits will be CHAR_MAX in some locales, notably C. However,
|
||||||
fpoint = ((lconvert->frac_digits != (char)CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */
|
* just testing for == CHAR_MAX is risky, because of compilers like
|
||||||
|
* gcc that "helpfully" let you alter the platform-standard definition
|
||||||
|
* of whether char is signed or not. If we are so unfortunate as to
|
||||||
|
* get compiled with a nonstandard -fsigned-char or -funsigned-char
|
||||||
|
* switch, then our idea of CHAR_MAX will not agree with libc's.
|
||||||
|
* The safest course is not to test for CHAR_MAX at all, but to impose
|
||||||
|
* a range check for plausible frac_digits values.
|
||||||
|
*/
|
||||||
|
fpoint = lconvert->frac_digits;
|
||||||
|
if (fpoint < 0 || fpoint > 10)
|
||||||
|
fpoint = 2; /* best guess in this case, I think */
|
||||||
|
|
||||||
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
||||||
ssymbol = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
ssymbol = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
||||||
@ -225,9 +235,9 @@ cash_out(PG_FUNCTION_ARGS)
|
|||||||
int count = LAST_DIGIT;
|
int count = LAST_DIGIT;
|
||||||
int point_pos;
|
int point_pos;
|
||||||
int comma_position = 0;
|
int comma_position = 0;
|
||||||
char mon_group,
|
int points,
|
||||||
comma,
|
mon_group;
|
||||||
points;
|
char comma;
|
||||||
char *csymbol,
|
char *csymbol,
|
||||||
dsymbol,
|
dsymbol,
|
||||||
*nsymbol;
|
*nsymbol;
|
||||||
@ -237,32 +247,36 @@ cash_out(PG_FUNCTION_ARGS)
|
|||||||
if (lconvert == NULL)
|
if (lconvert == NULL)
|
||||||
lconvert = localeconv();
|
lconvert = localeconv();
|
||||||
|
|
||||||
|
/* see comments about frac_digits in cash_in() */
|
||||||
|
points = lconvert->frac_digits;
|
||||||
|
if (points < 0 || points > 10)
|
||||||
|
points = 2; /* best guess in this case, I think */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As with frac_digits, must apply a range check to mon_grouping
|
||||||
|
* to avoid being fooled by variant CHAR_MAX values.
|
||||||
|
*/
|
||||||
mon_group = *lconvert->mon_grouping;
|
mon_group = *lconvert->mon_grouping;
|
||||||
|
if (mon_group <= 0 || mon_group > 6)
|
||||||
|
mon_group = 3;
|
||||||
|
|
||||||
comma = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
comma = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
|
||||||
/* frac_digits in the C locale seems to return CHAR_MAX */
|
|
||||||
/* best guess is 2 in this case I think */
|
|
||||||
points = ((lconvert->frac_digits != (char)CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */
|
|
||||||
convention = lconvert->n_sign_posn;
|
convention = lconvert->n_sign_posn;
|
||||||
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
|
||||||
csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
|
csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
|
||||||
nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
|
nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
|
||||||
#else
|
#else
|
||||||
|
points = 2;
|
||||||
mon_group = 3;
|
mon_group = 3;
|
||||||
comma = ',';
|
comma = ',';
|
||||||
csymbol = "$";
|
|
||||||
dsymbol = '.';
|
|
||||||
nsymbol = "-";
|
|
||||||
points = 2;
|
|
||||||
convention = 0;
|
convention = 0;
|
||||||
|
dsymbol = '.';
|
||||||
|
csymbol = "$";
|
||||||
|
nsymbol = "-";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
point_pos = LAST_DIGIT - points;
|
point_pos = LAST_DIGIT - points;
|
||||||
|
|
||||||
/* We're playing a little fast and loose with this. Shoot me. */
|
|
||||||
/* Not me, that was the other guy. Haven't fixed it yet - thomas */
|
|
||||||
if (!mon_group || mon_group == (char)CHAR_MAX)
|
|
||||||
mon_group = 3;
|
|
||||||
|
|
||||||
/* allow more than three decimal points and separate them */
|
/* allow more than three decimal points and separate them */
|
||||||
if (comma)
|
if (comma)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user