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)
9191if (lconvert == NULL )
9292lconvert = 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
98108dsymbol = ((* lconvert -> mon_decimal_point != '\0' ) ?* lconvert -> mon_decimal_point :'.' );
99109ssymbol = ((* lconvert -> mon_thousands_sep != '\0' ) ?* lconvert -> mon_thousands_sep :',' );
@@ -225,9 +235,9 @@ cash_out(PG_FUNCTION_ARGS)
225235int count = LAST_DIGIT ;
226236int point_pos ;
227237int comma_position = 0 ;
228- char mon_group ,
229- comma ,
230- points ;
238+ int points ,
239+ mon_group ;
240+ char comma ;
231241char * csymbol ,
232242dsymbol ,
233243* nsymbol ;
@@ -237,32 +247,36 @@ cash_out(PG_FUNCTION_ARGS)
237247if (lconvert == NULL )
238248lconvert = 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+ */
240259mon_group = * lconvert -> mon_grouping ;
260+ if (mon_group <=0 || mon_group > 6 )
261+ mon_group = 3 ;
262+
241263comma = ((* 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? */
245264convention = lconvert -> n_sign_posn ;
246265dsymbol = ((* lconvert -> mon_decimal_point != '\0' ) ?* lconvert -> mon_decimal_point :'.' );
247266csymbol = ((* lconvert -> currency_symbol != '\0' ) ?lconvert -> currency_symbol :"$" );
248267nsymbol = ((* lconvert -> negative_sign != '\0' ) ?lconvert -> negative_sign :"-" );
249268#else
269+ points = 2 ;
250270mon_group = 3 ;
251271comma = ',' ;
252- csymbol = "$" ;
272+ convention = 0 ;
253273dsymbol = '.' ;
274+ csymbol = "$" ;
254275nsymbol = "-" ;
255- points = 2 ;
256- convention = 0 ;
257276#endif
258277
259278point_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 */
267281if (comma )
268282{