Skip to content

Commit 75c147e

Browse files
committed
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...
1 parent aa21da2 commit 75c147e

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

src/backend/utils/adt/cash.c

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* workings can be found in the book "Software Solutions in C" by
1010
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
1111
*
12-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.45 2000/08/03 16:34:22 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.46 2000/11/18 03:55:51 tgl Exp $
1313
*/
1414

1515
#include <limits.h>
@@ -91,9 +91,19 @@ cash_in(PG_FUNCTION_ARGS)
9191
if (lconvert == NULL)
9292
lconvert = localeconv();
9393

94-
/* frac_digits in the C locale seems to return CHAR_MAX */
95-
/* best guess is 2 in this case I think */
96-
fpoint = ((lconvert->frac_digits != (char)CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */
94+
/*
95+
* frac_digits will be CHAR_MAX in some locales, notably C. However,
96+
* just testing for == CHAR_MAX is risky, because of compilers like
97+
* gcc that "helpfully" let you alter the platform-standard definition
98+
* of whether char is signed or not. If we are so unfortunate as to
99+
* get compiled with a nonstandard -fsigned-char or -funsigned-char
100+
* switch, then our idea of CHAR_MAX will not agree with libc's.
101+
* The safest course is not to test for CHAR_MAX at all, but to impose
102+
* a range check for plausible frac_digits values.
103+
*/
104+
fpoint = lconvert->frac_digits;
105+
if (fpoint < 0 || fpoint > 10)
106+
fpoint = 2; /* best guess in this case, I think */
97107

98108
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
99109
ssymbol = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
@@ -225,9 +235,9 @@ cash_out(PG_FUNCTION_ARGS)
225235
int count = LAST_DIGIT;
226236
int point_pos;
227237
int comma_position = 0;
228-
char mon_group,
229-
comma,
230-
points;
238+
int points,
239+
mon_group;
240+
char comma;
231241
char *csymbol,
232242
dsymbol,
233243
*nsymbol;
@@ -237,32 +247,36 @@ cash_out(PG_FUNCTION_ARGS)
237247
if (lconvert == NULL)
238248
lconvert = localeconv();
239249

250+
/* see comments about frac_digits in cash_in() */
251+
points = lconvert->frac_digits;
252+
if (points < 0 || points > 10)
253+
points = 2; /* best guess in this case, I think */
254+
255+
/*
256+
* As with frac_digits, must apply a range check to mon_grouping
257+
* to avoid being fooled by variant CHAR_MAX values.
258+
*/
240259
mon_group = *lconvert->mon_grouping;
260+
if (mon_group <= 0 || mon_group > 6)
261+
mon_group = 3;
262+
241263
comma = ((*lconvert->mon_thousands_sep != '\0') ? *lconvert->mon_thousands_sep : ',');
242-
/* frac_digits in the C locale seems to return CHAR_MAX */
243-
/* best guess is 2 in this case I think */
244-
points = ((lconvert->frac_digits != (char)CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */
245264
convention = lconvert->n_sign_posn;
246265
dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.');
247266
csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
248267
nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
249268
#else
269+
points = 2;
250270
mon_group = 3;
251271
comma = ',';
252-
csymbol = "$";
272+
convention = 0;
253273
dsymbol = '.';
274+
csymbol = "$";
254275
nsymbol = "-";
255-
points = 2;
256-
convention = 0;
257276
#endif
258277

259278
point_pos = LAST_DIGIT - points;
260279

261-
/* We're playing a little fast and loose with this. Shoot me. */
262-
/* Not me, that was the other guy. Haven't fixed it yet - thomas */
263-
if (!mon_group || mon_group == (char)CHAR_MAX)
264-
mon_group = 3;
265-
266280
/* allow more than three decimal points and separate them */
267281
if (comma)
268282
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy