From 75c147e7534a8511e65547ef6f206d0f5211d5e4 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 18 Nov 2000 03:55:51 +0000 Subject: [PATCH] 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... --- src/backend/utils/adt/cash.c | 50 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index d924bf3fe0..696559a59e 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -9,7 +9,7 @@ * workings can be found in the book "Software Solutions in C" by * 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 @@ -91,9 +91,19 @@ cash_in(PG_FUNCTION_ARGS) if (lconvert == NULL) lconvert = localeconv(); - /* frac_digits in the C locale seems to return CHAR_MAX */ - /* best guess is 2 in this case I think */ - fpoint = ((lconvert->frac_digits != (char)CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */ + /* + * frac_digits will be CHAR_MAX in some locales, notably C. However, + * 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 : '.'); ssymbol = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ','); @@ -225,9 +235,9 @@ cash_out(PG_FUNCTION_ARGS) int count = LAST_DIGIT; int point_pos; int comma_position = 0; - char mon_group, - comma, - points; + int points, + mon_group; + char comma; char *csymbol, dsymbol, *nsymbol; @@ -237,32 +247,36 @@ cash_out(PG_FUNCTION_ARGS) if (lconvert == NULL) 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; + if (mon_group <= 0 || mon_group > 6) + mon_group = 3; + 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; dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.'); csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$"); nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-"); #else + points = 2; mon_group = 3; comma = ','; - csymbol = "$"; + convention = 0; dsymbol = '.'; + csymbol = "$"; nsymbol = "-"; - points = 2; - convention = 0; #endif 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 */ if (comma) { -- 2.40.0