Austin Group Defect Tracker

Aardvark Mark III


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001199 [1003.1(2016)/Issue7+TC2] System Interfaces Editorial Error 2018-08-12 19:23 2018-08-21 11:08
Reporter bhaible View Status public  
Assigned To
Priority normal Resolution Open  
Status New  
Name Bruno Haible
Organization GNU
User Reference
Section strfmon
Page Number 2039 to 2043
Line Number 65327 to 65492
Interp Status ---
Final Accepted Text
Summary 0001199: strfmon, if standards compliant, produces highly misleading results
Description The following program shows strfmon results in the C locale:
=======================================================================
#include <locale.h>
#include <monetary.h>
#include <stdio.h>
int main ()
{
  char buf[80];
  printf ("currency = |%s|\n", localeconv()->currency_symbol);
  printf ("positive sign = |%s|\n", localeconv()->positive_sign);
  printf ("negative sign = |%s|\n", localeconv()->negative_sign);

  strfmon (buf, sizeof (buf), "%^#5.0n", 123.4);
  printf ("strfmon result for positive value = |%s|\n", buf);

  strfmon (buf, sizeof (buf), "%^#5.0n", -123.4);
  printf ("strfmon result for negative value = |%s|\n", buf);

  strfmon (buf, sizeof (buf), "%.2n", 123.5);
  printf ("strfmon result with 2 fractional digits: = |%s|\n", buf);
}
=======================================================================

The result on AIX 7.1 is:
currency = ||
positive sign = ||
negative sign = ||
strfmon result for positive value = | 123|
strfmon result for negative value = | 123|
strfmon result with 2 fractional digits: = |12350|

This is POSIX compliant, as far as I can see. However, without a distinction between positive and negative values, and without a visible decimal separator, this behaviour is useless, or even dangerous (if a programmer was not aware of this behaviour and has not worked around it).

The result on glibc 2.23 is:
currency = ||
positive sign = ||
negative sign = ||
strfmon result for positive value = | 123|
strfmon result for negative value = |- 123|
strfmon result with 2 fractional digits: = |123.50|

This is not POSIX compliant, because in the negative value case, it shows a '-' sign, although localeconv()->negative_sign is the empty string (which is mandated by POSIX http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_03_01 [^] ).

The result on Solaris 10 is:
currency = ||
positive sign = ||
negative sign = ||
strfmon result for positive value = | 123|
strfmon result for negative value = |- 123|
strfmon result with 2 fractional digits: = |123.50|

This is not POSIX compliant, 1. because of the '-' sign, 2. because it produces
a different number of characters in the negative and in the positive case, which is against what POSIX says for the '#' flag (lines 65387 to 65389):

  To ensure alignment, any characters appearing before or after the
  number in the formatted output such as currency or sign symbols are
  padded as necessary with <space> characters to make their positive
  and negative formats an equal length.

The result on macOS 10.13 is:
currency = ||
positive sign = ||
negative sign = ||
strfmon result for positive value = | 123 |
strfmon result for negative value = |( 123)|
strfmon result with 2 fractional digits: = |123.50|

This is not POSIX compliant, because the test program does not specify the '+' nor '(' flag, and POSIX says (lines 65363 to 65366):

  If '+' is specified, the locale's equivalent of '+' and '-' are
  used (for example, in many locales, the empty string if positive and '-'
  if negative). If '(' is specified, negative amounts are enclosed within
  parentheses. If neither flag is specified, the '+' style is used.

In summary, out of four implementations, only one is POSIX compliant, and it produces highly misleading / dangerous results.
Desired Action Remove strfmon and strfmon_l from the standard. Also remove <monetary.h> from the standard, since its only purpose is the declare these functions.

Or otherwise, change the standard so that the glibc results become the only compliant results.
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0004086)
geoffclare (manager)
2018-08-21 11:08

There seems to be a conflict between the strfmon() '+' flag and the values of p_sign_posn and n_sign_posn. If a locale has n_sign_posn = 0 and both positive_sign and negative_sign are empty, then this would mean that the only way to indicate sign is to enclose negative values in parentheses, in which case it should be an error to specify the '+' flag. It also seems odd that if neither '+' nor '(' is specified, the default is '+'; it would make more sense, if locales with both positive_sign and negative_sign empty can exist, for the default to be whatever style is specified by p_sign_posn and n_sign_posn (and if p_sign_posn is -1 and the value is positive, or n_sign_posn is -1 and the value is negative, strfmon() should return an error).

Note that where the bug description says:

> although localeconv()->negative_sign is the empty string (which is mandated by POSIX ...)

this is not true. POSIX says, at the end of XBD 7.3.3.1 LC_MONETARY Category in the POSIX Locale, "All values are unspecified in the POSIX locale." (Not hugely relevant to this issue, since the test program prints the values of positive_sign and negative_sign, but I thought it worth pointing out.)

- Issue History
Date Modified Username Field Change
2018-08-12 19:23 bhaible New Issue
2018-08-12 19:23 bhaible Name => Bruno Haible
2018-08-12 19:23 bhaible Organization => GNU
2018-08-12 19:23 bhaible Section => strfmon
2018-08-12 19:23 bhaible Page Number => 2039 to 2043
2018-08-12 19:23 bhaible Line Number => 65327 to 65492
2018-08-12 19:24 bhaible Issue Monitored: bhaible
2018-08-21 11:08 geoffclare Note Added: 0004086


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker