@@ -150,6 +150,8 @@ cash_in(PG_FUNCTION_ARGS)
150150 s ++ ;
151151 if (strncmp (s , csymbol , strlen (csymbol )) == 0 )
152152 s += strlen (csymbol );
153+ while (isspace ((unsigned char ) * s ))
154+ s ++ ;
153155
154156#ifdef CASHDEBUG
155157 printf ("cashin- string is '%s'\n" , s );
@@ -180,6 +182,8 @@ cash_in(PG_FUNCTION_ARGS)
180182 s ++ ;
181183 if (strncmp (s , csymbol , strlen (csymbol )) == 0 )
182184 s += strlen (csymbol );
185+ while (isspace ((unsigned char ) * s ))
186+ s ++ ;
183187
184188#ifdef CASHDEBUG
185189 printf ("cashin- string is '%s'\n" , s );
@@ -218,10 +222,11 @@ cash_in(PG_FUNCTION_ARGS)
218222
219223 /*
220224 * should only be trailing digits followed by whitespace, right paren,
221- * or possibly a trailing minus sign
225+ * trailing sign, and/or trailing currency symbol
222226 */
223227 while (isdigit ((unsigned char ) * s ))
224228 s ++ ;
229+
225230 while (* s )
226231 {
227232 if (isspace ((unsigned char ) * s ) || * s == ')' )
@@ -231,6 +236,10 @@ cash_in(PG_FUNCTION_ARGS)
231236 sgn = -1 ;
232237 s += strlen (nsymbol );
233238 }
239+ else if (strncmp (s , psymbol , strlen (psymbol )) == 0 )
240+ s += strlen (psymbol );
241+ else if (strncmp (s , csymbol , strlen (csymbol )) == 0 )
242+ s += strlen (csymbol );
234243 else
235244 ereport (ERROR ,
236245 (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
@@ -259,15 +268,16 @@ cash_out(PG_FUNCTION_ARGS)
259268 char * result ;
260269 char buf [128 ];
261270 char * bufptr ;
262- bool minus = false;
263271 int digit_pos ;
264272 int points ,
265273 mon_group ;
266274 char dsymbol ;
267275 const char * ssymbol ,
268276 * csymbol ,
269- * nsymbol ;
270- char convention ;
277+ * signsymbol ;
278+ char sign_posn ,
279+ cs_precedes ,
280+ sep_by_space ;
271281 struct lconv * lconvert = PGLC_localeconv ();
272282
273283 /* see comments about frac_digits in cash_in() */
@@ -283,8 +293,6 @@ cash_out(PG_FUNCTION_ARGS)
283293 if (mon_group <= 0 || mon_group > 6 )
284294 mon_group = 3 ;
285295
286- convention = lconvert -> n_sign_posn ;
287-
288296 /* we restrict dsymbol to be a single byte, but not the other symbols */
289297 if (* lconvert -> mon_decimal_point != '\0' &&
290298 lconvert -> mon_decimal_point [1 ] == '\0' )
@@ -296,16 +304,26 @@ cash_out(PG_FUNCTION_ARGS)
296304 else /* ssymbol should not equal dsymbol */
297305 ssymbol = (dsymbol != ',' ) ? "," : "." ;
298306 csymbol = (* lconvert -> currency_symbol != '\0' ) ? lconvert -> currency_symbol : "$" ;
299- nsymbol = (* lconvert -> negative_sign != '\0' ) ? lconvert -> negative_sign : "-" ;
300307
301- /* we work with positive amounts and add the minus sign at the end */
302308 if (value < 0 )
303309 {
304- minus = true;
310+ /* make the amount positive for digit-reconstruction loop */
305311 value = - value ;
312+ /* set up formatting data */
313+ signsymbol = (* lconvert -> negative_sign != '\0' ) ? lconvert -> negative_sign : "-" ;
314+ sign_posn = lconvert -> n_sign_posn ;
315+ cs_precedes = lconvert -> n_cs_precedes ;
316+ sep_by_space = lconvert -> n_sep_by_space ;
317+ }
318+ else
319+ {
320+ signsymbol = lconvert -> positive_sign ;
321+ sign_posn = lconvert -> p_sign_posn ;
322+ cs_precedes = lconvert -> p_cs_precedes ;
323+ sep_by_space = lconvert -> p_sep_by_space ;
306324 }
307325
308- /* we build the result string right-to-left in buf[] */
326+ /* we build the digits+decimal-point+sep string right-to-left in buf[] */
309327 bufptr = buf + sizeof (buf ) - 1 ;
310328 * bufptr = '\0' ;
311329
@@ -320,12 +338,12 @@ cash_out(PG_FUNCTION_ARGS)
320338 {
321339 if (points && digit_pos == 0 )
322340 {
323- /* insert decimal point */
341+ /* insert decimal point, but not if value cannot be fractional */
324342 * (-- bufptr ) = dsymbol ;
325343 }
326- else if (digit_pos < points && (digit_pos % mon_group ) == 0 )
344+ else if (digit_pos < 0 && (digit_pos % mon_group ) == 0 )
327345 {
328- /* insert thousands sep */
346+ /* insert thousands sep, but only to left of radix point */
329347 bufptr -= strlen (ssymbol );
330348 memcpy (bufptr , ssymbol , strlen (ssymbol ));
331349 }
@@ -335,27 +353,111 @@ cash_out(PG_FUNCTION_ARGS)
335353 digit_pos -- ;
336354 } while (value || digit_pos >= 0 );
337355
338- /* prepend csymbol */
339- bufptr -= strlen (csymbol );
340- memcpy (bufptr , csymbol , strlen (csymbol ));
341-
342- /* see if we need to signify negative amount */
343- if (minus )
344- {
345- result = palloc (strlen (bufptr ) + strlen (nsymbol ) + 3 );
356+ /*----------
357+ * Now, attach currency symbol and sign symbol in the correct order.
358+ *
359+ * The POSIX spec defines these values controlling this code:
360+ *
361+ * p/n_sign_posn:
362+ * 0 Parentheses enclose the quantity and the currency_symbol.
363+ * 1 The sign string precedes the quantity and the currency_symbol.
364+ * 2 The sign string succeeds the quantity and the currency_symbol.
365+ * 3 The sign string precedes the currency_symbol.
366+ * 4 The sign string succeeds the currency_symbol.
367+ *
368+ * p/n_cs_precedes: 0 means currency symbol after value, else before it.
369+ *
370+ * p/n_sep_by_space:
371+ * 0 No <space> separates the currency symbol and value.
372+ * 1 If the currency symbol and sign string are adjacent, a <space>
373+ * separates them from the value; otherwise, a <space> separates
374+ * the currency symbol from the value.
375+ * 2 If the currency symbol and sign string are adjacent, a <space>
376+ * separates them; otherwise, a <space> separates the sign string
377+ * from the value.
378+ *----------
379+ */
380+ result = palloc (strlen (bufptr ) + strlen (csymbol ) + strlen (signsymbol ) + 4 );
346381
347- /* Position code of 0 means use parens */
348- if (convention == 0 )
349- sprintf (result , "(%s)" , bufptr );
350- else if (convention == 2 )
351- sprintf (result , "%s%s" , bufptr , nsymbol );
352- else
353- sprintf (result , "%s%s" , nsymbol , bufptr );
354- }
355- else
382+ switch (sign_posn )
356383 {
357- /* just emit what we have */
358- result = pstrdup (bufptr );
384+ case 0 :
385+ if (cs_precedes )
386+ sprintf (result , "(%s%s%s)" ,
387+ csymbol ,
388+ (sep_by_space == 1 ) ? " " : "" ,
389+ bufptr );
390+ else
391+ sprintf (result , "(%s%s%s)" ,
392+ bufptr ,
393+ (sep_by_space == 1 ) ? " " : "" ,
394+ csymbol );
395+ break ;
396+ case 1 :
397+ default :
398+ if (cs_precedes )
399+ sprintf (result , "%s%s%s%s%s" ,
400+ signsymbol ,
401+ (sep_by_space == 2 ) ? " " : "" ,
402+ csymbol ,
403+ (sep_by_space == 1 ) ? " " : "" ,
404+ bufptr );
405+ else
406+ sprintf (result , "%s%s%s%s%s" ,
407+ signsymbol ,
408+ (sep_by_space == 2 ) ? " " : "" ,
409+ bufptr ,
410+ (sep_by_space == 1 ) ? " " : "" ,
411+ csymbol );
412+ break ;
413+ case 2 :
414+ if (cs_precedes )
415+ sprintf (result , "%s%s%s%s%s" ,
416+ csymbol ,
417+ (sep_by_space == 1 ) ? " " : "" ,
418+ bufptr ,
419+ (sep_by_space == 2 ) ? " " : "" ,
420+ signsymbol );
421+ else
422+ sprintf (result , "%s%s%s%s%s" ,
423+ bufptr ,
424+ (sep_by_space == 1 ) ? " " : "" ,
425+ csymbol ,
426+ (sep_by_space == 2 ) ? " " : "" ,
427+ signsymbol );
428+ break ;
429+ case 3 :
430+ if (cs_precedes )
431+ sprintf (result , "%s%s%s%s%s" ,
432+ signsymbol ,
433+ (sep_by_space == 2 ) ? " " : "" ,
434+ csymbol ,
435+ (sep_by_space == 1 ) ? " " : "" ,
436+ bufptr );
437+ else
438+ sprintf (result , "%s%s%s%s%s" ,
439+ bufptr ,
440+ (sep_by_space == 1 ) ? " " : "" ,
441+ signsymbol ,
442+ (sep_by_space == 2 ) ? " " : "" ,
443+ csymbol );
444+ break ;
445+ case 4 :
446+ if (cs_precedes )
447+ sprintf (result , "%s%s%s%s%s" ,
448+ csymbol ,
449+ (sep_by_space == 2 ) ? " " : "" ,
450+ signsymbol ,
451+ (sep_by_space == 1 ) ? " " : "" ,
452+ bufptr );
453+ else
454+ sprintf (result , "%s%s%s%s%s" ,
455+ bufptr ,
456+ (sep_by_space == 1 ) ? " " : "" ,
457+ csymbol ,
458+ (sep_by_space == 2 ) ? " " : "" ,
459+ signsymbol );
460+ break ;
359461 }
360462
361463 PG_RETURN_CSTRING (result );
0 commit comments