@@ -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 ((unsigned char ) * 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 ((unsigned char ) * 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 trailing minus sign
225
+ * trailing sign, and/or trailing currency symbol
222
226
*/
223
227
while (isdigit ((unsigned char ) * s ))
224
228
s ++ ;
229
+
225
230
while (* s )
226
231
{
227
232
if (isspace ((unsigned char ) * 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 the result string right-to-left in buf[] */
326
+ /* we build the digits+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
+ * 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 );
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 );
0 commit comments