@@ -150,6 +150,8 @@ cash_in(PG_FUNCTION_ARGS)
150
150
s ++ ;
151
151
if (strncmp (s ,csymbol ,strlen (csymbol ))== 0 )
152
152
s += strlen (csymbol );
153
+ while (isspace ((unsignedchar )* s ))
154
+ s ++ ;
153
155
154
156
#ifdef CASHDEBUG
155
157
printf ("cashin- string is '%s'\n" ,s );
@@ -180,6 +182,8 @@ cash_in(PG_FUNCTION_ARGS)
180
182
s ++ ;
181
183
if (strncmp (s ,csymbol ,strlen (csymbol ))== 0 )
182
184
s += strlen (csymbol );
185
+ while (isspace ((unsignedchar )* s ))
186
+ s ++ ;
183
187
184
188
#ifdef CASHDEBUG
185
189
printf ("cashin- string is '%s'\n" ,s );
@@ -218,10 +222,11 @@ cash_in(PG_FUNCTION_ARGS)
218
222
219
223
/*
220
224
* should only be trailing digits followed by whitespace, right paren,
221
- *or possibly a trailingminus sign
225
+ *trailing sign, and/or trailingcurrency symbol
222
226
*/
223
227
while (isdigit ((unsignedchar )* s ))
224
228
s ++ ;
229
+
225
230
while (* s )
226
231
{
227
232
if (isspace ((unsignedchar )* s )|| * s == ')' )
@@ -231,6 +236,10 @@ cash_in(PG_FUNCTION_ARGS)
231
236
sgn = -1 ;
232
237
s += strlen (nsymbol );
233
238
}
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 );
234
243
else
235
244
ereport (ERROR ,
236
245
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
@@ -259,15 +268,16 @@ cash_out(PG_FUNCTION_ARGS)
259
268
char * result ;
260
269
char buf [128 ];
261
270
char * bufptr ;
262
- bool minus = false;
263
271
int digit_pos ;
264
272
int points ,
265
273
mon_group ;
266
274
char dsymbol ;
267
275
const char * ssymbol ,
268
276
* csymbol ,
269
- * nsymbol ;
270
- char convention ;
277
+ * signsymbol ;
278
+ char sign_posn ,
279
+ cs_precedes ,
280
+ sep_by_space ;
271
281
struct lconv * lconvert = PGLC_localeconv ();
272
282
273
283
/* see comments about frac_digits in cash_in() */
@@ -283,8 +293,6 @@ cash_out(PG_FUNCTION_ARGS)
283
293
if (mon_group <=0 || mon_group > 6 )
284
294
mon_group = 3 ;
285
295
286
- convention = lconvert -> n_sign_posn ;
287
-
288
296
/* we restrict dsymbol to be a single byte, but not the other symbols */
289
297
if (* lconvert -> mon_decimal_point != '\0' &&
290
298
lconvert -> mon_decimal_point [1 ]== '\0' )
@@ -296,16 +304,26 @@ cash_out(PG_FUNCTION_ARGS)
296
304
else /* ssymbol should not equal dsymbol */
297
305
ssymbol = (dsymbol != ',' ) ?"," :"." ;
298
306
csymbol = (* lconvert -> currency_symbol != '\0' ) ?lconvert -> currency_symbol :"$" ;
299
- nsymbol = (* lconvert -> negative_sign != '\0' ) ?lconvert -> negative_sign :"-" ;
300
307
301
- /* we work with positive amounts and add the minus sign at the end */
302
308
if (value < 0 )
303
309
{
304
- minus = true;
310
+ /* make the amount positive for digit-reconstruction loop */
305
311
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 ;
306
324
}
307
325
308
- /* we build theresult string right-to-left in buf[] */
326
+ /* we build thedigits+decimal-point+sep string right-to-left in buf[] */
309
327
bufptr = buf + sizeof (buf )- 1 ;
310
328
* bufptr = '\0' ;
311
329
@@ -320,12 +338,12 @@ cash_out(PG_FUNCTION_ARGS)
320
338
{
321
339
if (points && digit_pos == 0 )
322
340
{
323
- /* insert decimal point */
341
+ /* insert decimal point, but not if value cannot be fractional */
324
342
* (-- bufptr )= dsymbol ;
325
343
}
326
- else if (digit_pos < points && (digit_pos %mon_group )== 0 )
344
+ else if (digit_pos < 0 && (digit_pos %mon_group )== 0 )
327
345
{
328
- /* insert thousands sep */
346
+ /* insert thousands sep, but only to left of radix point */
329
347
bufptr -= strlen (ssymbol );
330
348
memcpy (bufptr ,ssymbol ,strlen (ssymbol ));
331
349
}
@@ -335,27 +353,111 @@ cash_out(PG_FUNCTION_ARGS)
335
353
digit_pos -- ;
336
354
}while (value || digit_pos >=0 );
337
355
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
+ *0Parentheses enclose the quantity and the currency_symbol.
363
+ *1The sign string precedes the quantity and the currency_symbol.
364
+ *2The sign string succeeds the quantity and the currency_symbol.
365
+ *3The sign string precedes the currency_symbol.
366
+ *4The 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
+ *0No <space> separates the currency symbol and value.
372
+ *1If 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
+ *2If 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 );
346
381
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 )
356
383
{
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 ;
359
461
}
360
462
361
463
PG_RETURN_CSTRING (result );