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.22 1998/02/26 04:36:53 momjian Exp $
12+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.23 1998/03/02 00:13:36 thomas Exp $
1313 */
1414
1515#include <stdio.h>
@@ -34,7 +34,6 @@ static const char *num_word(Cash value);
3434
3535#ifdef USE_LOCALE
3636static struct lconv * lconvert = NULL ;
37-
3837#endif
3938
4039/* cash_in()
@@ -46,6 +45,8 @@ static struct lconv *lconvert = NULL;
4645 * XXX HACK It looks as though some of the symbols for
4746 *monetary values returned by localeconv() can be multiple
4847 *bytes/characters. This code assumes one byte only. - tgl 97/04/14
48+ * XXX UNHACK Allow the currency symbol to be multi-byte.
49+ * - thomas 1998-03-01
4950 */
5051Cash *
5152cash_in (const char * str )
@@ -58,11 +59,11 @@ cash_in(const char *str)
5859int seen_dot = 0 ;
5960const char * s = str ;
6061int fpoint ;
62+ char * csymbol ;
6163char dsymbol ,
6264ssymbol ,
6365psymbol ,
64- nsymbol ,
65- csymbol ;
66+ * nsymbol ;
6667
6768#ifdef USE_LOCALE
6869#ifdef CASHDEBUG
@@ -76,33 +77,45 @@ cash_in(const char *str)
7677/* best guess is 2 in this case I think */
7778fpoint = ((lconvert -> frac_digits != CHAR_MAX ) ?lconvert -> frac_digits :2 );/* int_frac_digits? */
7879
79- dsymbol = * lconvert -> mon_decimal_point ;
80- ssymbol = * lconvert -> mon_thousands_sep ;
81- csymbol = * lconvert -> currency_symbol ;
82- psymbol = * lconvert -> positive_sign ;
83- nsymbol = * lconvert -> negative_sign ;
80+ dsymbol = (( * lconvert -> mon_decimal_point != '\0' )? * lconvert -> mon_decimal_point : '.' ) ;
81+ ssymbol = (( * lconvert -> mon_thousands_sep != '\0' )? * lconvert -> mon_thousands_sep : ',' ) ;
82+ csymbol = (( * lconvert -> currency_symbol != '\0' )? lconvert -> currency_symbol : "$" ) ;
83+ psymbol = (( * lconvert -> positive_sign != '\0' )? * lconvert -> positive_sign : '+' ) ;
84+ nsymbol = (( * lconvert -> negative_sign != '\0' )? lconvert -> negative_sign : "-" ) ;
8485#else
8586fpoint = 2 ;
8687dsymbol = '.' ;
8788ssymbol = ',' ;
88- csymbol = '$' ;
89+ csymbol = "$" ;
8990psymbol = '+' ;
90- nsymbol = '-' ;
91+ nsymbol = "-" ;
9192#endif
9293
9394#ifdef CASHDEBUG
94- printf ("cashin- precision%d ; decimal%c ; thousands%c ; currency%c ; positive%c ; negative%c \n" ,
95- fpoint ,dsymbol ,ssymbol ,csymbol ,psymbol ,nsymbol );
95+ printf ("cashin- precision'%d' ; decimal'%c' ; thousands'%c' ; currency'%s' ; positive'%c' ; negative'%s' \n" ,
96+ fpoint ,dsymbol ,ssymbol ,csymbol ,psymbol ,nsymbol );
9697#endif
9798
9899/* we need to add all sorts of checking here. For now just */
99- /* strip all leading whitespace and any leading dollar sign */
100- while (isspace (* s )|| * s == csymbol )
101- s ++ ;
100+ /* strip all leading whitespace and any leading currency symbol */
101+ while (isspace (* s ))s ++ ;
102+ if (strncmp (s ,csymbol ,strlen (csymbol ))== 0 )s += strlen (csymbol );
103+
104+ #ifdef CASHDEBUG
105+ printf ("cashin- string is '%s'\n" ,s );
106+ #endif
102107
103108/* a leading minus or paren signifies a negative number */
104109/* again, better heuristics needed */
105- if (* s == nsymbol || * s == '(' )
110+ if (strncmp (s ,nsymbol ,strlen (nsymbol ))== 0 )
111+ {
112+ sgn = -1 ;
113+ s += strlen (nsymbol );
114+ #ifdef CASHDEBUG
115+ printf ("cashin- negative symbol; string is '%s'\n" ,s );
116+ #endif
117+ }
118+ else if (* s == '(' )
106119{
107120sgn = -1 ;
108121s ++ ;
@@ -113,8 +126,16 @@ cash_in(const char *str)
113126s ++ ;
114127}
115128
116- while (isspace (* s )|| * s == csymbol )
117- s ++ ;
129+ #ifdef CASHDEBUG
130+ printf ("cashin- string is '%s'\n" ,s );
131+ #endif
132+
133+ while (isspace (* s ))s ++ ;
134+ if (strncmp (s ,csymbol ,strlen (csymbol ))== 0 )s += strlen (csymbol );
135+
136+ #ifdef CASHDEBUG
137+ printf ("cashin- string is '%s'\n" ,s );
138+ #endif
118139
119140for (;;s ++ )
120141{
@@ -164,6 +185,10 @@ cash_in(const char *str)
164185
165186* result = (value * sgn );
166187
188+ #ifdef CASHDEBUG
189+ printf ("cashin- result is %d\n" ,* result );
190+ #endif
191+
167192return (result );
168193}/* cash_in() */
169194
@@ -186,7 +211,7 @@ cash_out(Cash *in_value)
186211char mon_group ,
187212comma ,
188213points ;
189- char csymbol ,
214+ char * csymbol ,
190215dsymbol ,
191216* nsymbol ;
192217char convention ;
@@ -196,18 +221,18 @@ cash_out(Cash *in_value)
196221lconvert = localeconv ();
197222
198223mon_group = * lconvert -> mon_grouping ;
199- comma = * lconvert -> mon_thousands_sep ;
200- csymbol = * lconvert -> currency_symbol ;
201- dsymbol = * lconvert -> mon_decimal_point ;
202- nsymbol = lconvert -> negative_sign ;
224+ comma = ((* lconvert -> mon_thousands_sep != '\0' )?* lconvert -> mon_thousands_sep :',' );
203225/* frac_digits in the C locale seems to return CHAR_MAX */
204226/* best guess is 2 in this case I think */
205227points = ((lconvert -> frac_digits != CHAR_MAX ) ?lconvert -> frac_digits :2 );/* int_frac_digits? */
206228convention = lconvert -> n_sign_posn ;
229+ dsymbol = ((* lconvert -> mon_decimal_point != '\0' )?* lconvert -> mon_decimal_point :'.' );
230+ csymbol = ((* lconvert -> currency_symbol != '\0' )?lconvert -> currency_symbol :"$" );
231+ nsymbol = ((* lconvert -> negative_sign != '\0' )?lconvert -> negative_sign :"-" );
207232#else
208233mon_group = 3 ;
209234comma = ',' ;
210- csymbol = '$' ;
235+ csymbol = "$" ;
211236dsymbol = '.' ;
212237nsymbol = "-" ;
213238points = 2 ;
@@ -217,6 +242,7 @@ cash_out(Cash *in_value)
217242point_pos = LAST_DIGIT - points ;
218243
219244/* We're playing a little fast and loose with this. Shoot me. */
245+ /* Not me, that was the other guy. Haven't fixed it yet - thomas */
220246if (!mon_group || mon_group == CHAR_MAX )
221247mon_group = 3 ;
222248
@@ -249,7 +275,8 @@ cash_out(Cash *in_value)
249275value /=10 ;
250276}
251277
252- buf [count ]= csymbol ;
278+ strncpy ((buf + count - strlen (csymbol )+ 1 ),csymbol ,strlen (csymbol ));
279+ count -= strlen (csymbol )- 1 ;
253280
254281if (buf [LAST_DIGIT ]== ',' )
255282buf [LAST_DIGIT ]= buf [LAST_PAREN ];