From 77ac40d73e7728bb2e2c5c108037d2573472ed3e Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Mon, 2 Mar 1998 00:13:36 +0000 Subject: [PATCH] Fix money type USE_LOCALE support at least for default "C" locale. Still has questionable code for some locale-specific strings. --- src/backend/utils/adt/cash.c | 79 ++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index e9e3a971b4..90f92bd24f 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.22 1998/02/26 04:36:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.23 1998/03/02 00:13:36 thomas Exp $ */ #include @@ -34,7 +34,6 @@ static const char *num_word(Cash value); #ifdef USE_LOCALE static struct lconv *lconvert = NULL; - #endif /* cash_in() @@ -46,6 +45,8 @@ static struct lconv *lconvert = NULL; * XXX HACK It looks as though some of the symbols for * monetary values returned by localeconv() can be multiple * bytes/characters. This code assumes one byte only. - tgl 97/04/14 + * XXX UNHACK Allow the currency symbol to be multi-byte. + * - thomas 1998-03-01 */ Cash * cash_in(const char *str) @@ -58,11 +59,11 @@ cash_in(const char *str) int seen_dot = 0; const char *s = str; int fpoint; + char *csymbol; char dsymbol, ssymbol, psymbol, - nsymbol, - csymbol; + *nsymbol; #ifdef USE_LOCALE #ifdef CASHDEBUG @@ -76,33 +77,45 @@ cash_in(const char *str) /* best guess is 2 in this case I think */ fpoint = ((lconvert->frac_digits != CHAR_MAX) ? lconvert->frac_digits : 2); /* int_frac_digits? */ - dsymbol = *lconvert->mon_decimal_point; - ssymbol = *lconvert->mon_thousands_sep; - csymbol = *lconvert->currency_symbol; - psymbol = *lconvert->positive_sign; - nsymbol = *lconvert->negative_sign; + dsymbol = ((*lconvert->mon_decimal_point != '\0')? *lconvert->mon_decimal_point: '.'); + ssymbol = ((*lconvert->mon_thousands_sep != '\0')? *lconvert->mon_thousands_sep: ','); + csymbol = ((*lconvert->currency_symbol != '\0')? lconvert->currency_symbol: "$"); + psymbol = ((*lconvert->positive_sign != '\0')? *lconvert->positive_sign: '+'); + nsymbol = ((*lconvert->negative_sign != '\0')? lconvert->negative_sign: "-"); #else fpoint = 2; dsymbol = '.'; ssymbol = ','; - csymbol = '$'; + csymbol = "$"; psymbol = '+'; - nsymbol = '-'; + nsymbol = "-"; #endif #ifdef CASHDEBUG - printf("cashin- precision %d; decimal %c; thousands %c; currency %c; positive %c; negative %c\n", - fpoint, dsymbol, ssymbol, csymbol, psymbol, nsymbol); +printf( "cashin- precision '%d'; decimal '%c'; thousands '%c'; currency '%s'; positive '%c'; negative '%s'\n", + fpoint, dsymbol, ssymbol, csymbol, psymbol, nsymbol); #endif /* we need to add all sorts of checking here. For now just */ - /* strip all leading whitespace and any leading dollar sign */ - while (isspace(*s) || *s == csymbol) - s++; + /* strip all leading whitespace and any leading currency symbol */ + while (isspace(*s)) s++; + if (strncmp(s,csymbol,strlen(csymbol)) == 0) s += strlen(csymbol); + +#ifdef CASHDEBUG +printf( "cashin- string is '%s'\n", s); +#endif /* a leading minus or paren signifies a negative number */ /* again, better heuristics needed */ - if (*s == nsymbol || *s == '(') + if (strncmp(s,nsymbol,strlen(nsymbol)) == 0) + { + sgn = -1; + s += strlen(nsymbol); +#ifdef CASHDEBUG +printf( "cashin- negative symbol; string is '%s'\n", s); +#endif + } + else if (*s == '(') { sgn = -1; s++; @@ -113,8 +126,16 @@ cash_in(const char *str) s++; } - while (isspace(*s) || *s == csymbol) - s++; +#ifdef CASHDEBUG +printf( "cashin- string is '%s'\n", s); +#endif + + while (isspace(*s)) s++; + if (strncmp(s,csymbol,strlen(csymbol)) == 0) s += strlen(csymbol); + +#ifdef CASHDEBUG +printf( "cashin- string is '%s'\n", s); +#endif for (;; s++) { @@ -164,6 +185,10 @@ cash_in(const char *str) *result = (value * sgn); +#ifdef CASHDEBUG +printf( "cashin- result is %d\n", *result); +#endif + return (result); } /* cash_in() */ @@ -186,7 +211,7 @@ cash_out(Cash *in_value) char mon_group, comma, points; - char csymbol, + char *csymbol, dsymbol, *nsymbol; char convention; @@ -196,18 +221,18 @@ cash_out(Cash *in_value) lconvert = localeconv(); mon_group = *lconvert->mon_grouping; - comma = *lconvert->mon_thousands_sep; - csymbol = *lconvert->currency_symbol; - dsymbol = *lconvert->mon_decimal_point; - nsymbol = lconvert->negative_sign; + 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_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 mon_group = 3; comma = ','; - csymbol = '$'; + csymbol = "$"; dsymbol = '.'; nsymbol = "-"; points = 2; @@ -217,6 +242,7 @@ cash_out(Cash *in_value) 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_MAX) mon_group = 3; @@ -249,7 +275,8 @@ cash_out(Cash *in_value) value /= 10; } - buf[count] = csymbol; + strncpy((buf+count-strlen(csymbol)+1),csymbol,strlen(csymbol)); + count -= strlen(csymbol)-1; if (buf[LAST_DIGIT] == ',') buf[LAST_DIGIT] = buf[LAST_PAREN];