View Issue Details

IDProjectCategoryView StatusLast Update
00020001003.1(2024)/Issue8System Interfacespublic2026-09-17 19:28
Reporterkre Assigned To 
PrioritynormalSeverityObjectionTypeError
Status NewResolutionOpen 
NameRobert Elz
Organization
User Reference
SectionXSH 3.strfmon
Page Number2129-2133
Line Number69523 69524-69526 69529 69537-65538 69540-69542 69545-69546 69557-69558 69560-69561 69567-69571 69577 69581-69590 69591-69594 69598 69613-69616 69628-69630 69632-69670 69640-69651 69672-69676 69678-69680 69684-69686
Interp Status
Final Accepted Text
Summary0002000: XSH 3/strfmon misses info and needs attention
Description


In the sequel, I shall refer solely to strfmon(), but everything applies equally to strfmon_l().
The mechanism by which the locale data is made available is not material to anything in this defect report.


The following defects are ordered in decreasing order of importance, as I see them, except with some related issues grouped adjacent to one another.
All defects (except probably the last) should be corrected however.



  1. When issue 0001199 was fixed (the changes made as the result of that I generally agree with) one part of the original issue report seems to have been forgotten.
    It (0001199) said:

    However, without a distinction between positive and negative values, and without a visible decimal separator, this behaviour is useless, or even dangerous


    The issue with positive/negative was (mostly) handled, the issue when there is no visible decimal separator was not, and needs to be.
    See issue 0001199 for an example illustrating the problem.




  2. Following on from the previous, it is also unclear, even with the text as amended by issue 0001199, what should be done when a locale defines non-empty strings to be used as the signs, but specifies the same string for both cases.
    This is effectively the same problem as issue 0001199 dealt with, being unable to determine whether a value is positive, or negative, just in a different way.


    Relevant to this, and what makes it different from the empty string case, is that the result might differ when the position of the sign string is different for positive and negative values.
    That is, it is not necessarily simply invalid to use the same non-empty string for both the positive and negative signs.




  3. It is not always clear in the specification when character means character and when it means byte or perhaps "character from a restricted character set", or something different entirely.


    That the specification generally means character is clear from line 69523:


    The format is a character string, beginning and ending in its initial state, if any, ...

    which would make no sense if character was being used as a synonym for the C programming language char data type, or simply a byte, or even a character from the Portable Character Set from the standard (XBD 6.1).
    Those kinds of characters have no state, hence no initial state to require.


    This issue crops up in many places, the most obvious is in (line 69540):


    An '=' followed by a single character f which is used as the numeric fill character.

    The text (lines 69541-69542) attempts to add some meaning to this:

    In order to work with precision or width counts, the fill character shall be a single byte character; if not, the behavior is undefined.

    But that makes no sense at all.
    To work with the precision and width counts, the fill character needs to occupy one column position in the output.
    That distinction has nothing at all to do with how many bytes are in the representation of the character.
    A single byte character, in some locales, might be zero-width or occupy multiple columns in the output, even in a constant width font.
    Obvious examples are the <tab> character, and ASCII control characters.
    A <newline> or <carriage-return> would have different, but related, issues.
    It is also unclear why the behaviour should be undefined should the application not give a suitable character as the fill character value.
    That is a truly machiovellian punishment.
    Would it not be better to simply make it clear than in such cases the intended alignment might not be able to be achieved?
    That is, the implementation should just use whatever character is specified as f when needed as the fill character, and if that character is not suitable for the purpose, the output will look odd, instead of nice.
    No calling abort(), or removing all of the user's files, which "undefined behaviour" would permit.


    A similar problem can be found at line 69577:


    A decimal digit string w specifying a minimum field width in bytes

    which also makes little sense, if one assumes as the specification seems to imply, at a minimum, that the objective is to be able to align output from multiple calls to strfmon().
    What matters is the appearance of the final output, not how many bytes of encoded characters are needed to achieve that result.
    The number of bytes is, or should, only be relevant when determining whether the result fits within the maxsize number of bytes available in the output buffer.
    Everything else should be using characters, possibly constrained in some cases to be printing or graphic characters, and perhaps sometimes constrained by the widths of the characters concerned.
    This needs to be clear in the specification, with no mention of bytes in any of the relevant places.


    The same problem arises with everything else inserted into the resulting output string, including the mon_decimal_point and the <mon_thousands_sep> strings.
    Lines 69592-69594 do explain the idea:


    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.

    though that text does give rise to the immediately following defect.


    It should also be made clear what other constraints, if any, must be met for the output to be able to be nicely aligned.
    The use of a monospace (constant width) font to display the result is an obvious one, without that achieving alignment requires much more complex mechanisms that simply counting characters, which is all that is available here.
    But is it expected that all the values intended to be able to be aligned have neen formatted using the same locale, or is it intended that output from different locales be able to be intermixed, and remain aligned?
    The answer to that question constrains what constraints should be placed upon what is permitted in locales for the mon_decimal_point (I have a fake locale, for testing purposes, which uses $'\u3002' as that character, and the font I use for my terminal sessions renders that character in 2 columns).
    Is strfmon() expected to work with such a value?
    It does, even to aligning (approximately) as intended, as the alighnment is primarily for the value to the left of the radix, which is unaffected by this.
    But something similar might be used as the mon_thousands_sep.
    Further, different locales might have different mon_grouping settings.
    My fake locale uses "2;3;2;3;2" which is going to result in a different number of separators being inserted in some values than the more common "3".
    As one call to strfmon has no way to communicate decisions to another, nor to predict what locale might be in use when the next call is made, it might seem necessary to constrain the alignment goal to apply only as long as the same locale is used for all relevant strfmon calls.
    But that might also be too strict, perhaps as long as the locales used all use the same mon_grouping, and use as their mon_decimal_point and mon_thousands_sep strings which occupy the same number of columns as the equivalent setting in all other locales used in a sequence intended to align correctlty, that would be enough?


    Did no-one ever consider any of these questions?




  4. The text at lines 69592-69594:


    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.

    concentrate entirely upon making the positive and negative output forms of equal length, but the text at lines 69582-69584:

    This option can be used to keep the formatted output from multiple calls to the strfmon( ) function aligned in the same columns.

    makes it clear that the aim that is implied by lines 69592-69594 is not sufficient to meet the expectations of the strfmon specification, and that more precision is required to meet the overall objective.


    That is, if for positive numbers, the sign follows the value, and for negative nnumbers the sign precedes the value, then, to keep the numeric parts of a positive and a negative value aligned, both of them must allocate space in the resulting
    string for the possible negative sign before the value, and the possible positive sign following the value (when positive signs are being included), so that either of them might be used to occupy the sign value.
    What's more, that is what implementations I have seen actually do.
    Simply having the positive and negative formats being of equal length is not suffficient.


    It is also not stated anywhere, but clearly is intended (I hope), that the expected alignment is only achieved if the same format string is used for all the applicable calls to strfmon().




  5. A corollary to the previous two points, is that it should be made explicit that aligned values can only be expected to remain aligned when displayed or printed, if they are rendered in a constant width font, or at least one in which all characters are represented in a non-negative integer multiple of a fixed column width.




  6. The description of "grouping characters" (a term for which incidentally I can find no definition in the standard, though it is obvious that in this context it means the mon_thousands_sep characters inserted to perform the grouping function of monetary output values, which is a defined operation) and how they apply to the Left Precision given in lines 69589-69590 is one of the least useful specifications I think I have ever seen.
    It states (lines 69589-69590):


    If grouping has not been suppressed with the '^' flag, and it is defined for the current locale, grouping separators are inserted before the fill characters (if any) are added.

    The pre-conditions are simple enough, but I would interpret the action as meaning that each "grouping separator" (another undefined term) inserted replaces one (or perhaps more) of the fill characters, which then fill in any remaining unused positions as specified in the previous paragraph (lines 69581-69588).
    The subsequent sentence (line 69591), which ends the paragraph, about the inapplicability of grouping to fill characters, even if they are digits, is clear enough as it stands.


    But as illustrated by the examples (see lines 69640-69642 (or 69643-69645 or 69646-69648) in comparison with lines 69649-69651 which, apart from the use of a non-space fill character in the alternatives of the former, which is immaterial, show the same example, except the former has grouping enabled, and the latter with it suppressed), and from observing what is done by actual implementations, that is not what is intended at all.
    Rather, the value given by the Left Precision "n" value, is to be increased by the maximum number of "grouping separators" which would be needed if a value to be formatted generates n (as specified) digits before the radix character (decimal-point) if any.
    Then the value is formatted, and the number of "grouping separators" required for the actual value are inserted, and finally the increased value of n is used to fill any remaining unused positions with fill characters.
    That is, the use of grouping can increase the number of fill characters to be used for a particular value, and the actual left precision width from what is in the conversion specification, but never decrease it, compared to when grouping is not used.


    How, an implementer, or an application writer, is intended to determine the intended behaviour from the written specification bamboozles me.
    It needs rewriting.


    Note also, that though the linux manual page for this function attempts to make this clear, it is not a lot better:


    Next, there may be a left precision of the form "#" followed by a decimal digit string.
    If the number of digits left of the radix character is smaller than this, the representation is padded on the left with the numeric fill character.
    Grouping characters are not counted in this field width.

    That would make it seem as if the number of grouping characters inserted, or which might be inserted, has no effect on the padding inserted by the left precision, which is not correct either.




  7. The ERRORS section at lines 69628-69630 states the functions shall fail if:


    • [EINVAL]

      The '+' flag was included in a conversion specification and the locale's positive_sign and negative_sign values would both be returned by localeconv( ) as empty strings.



    The APPLICATION USAGE section, at lines 69672-69676:


    The '+' flag should be used with care, because if the locale's positive_sign and negative_sign values are both empty strings, there is no way to distinguish negative from positive values with signs and therefore strfmon( ) fails. If the application has a preference for signs but parentheses are acceptable, it should try strfmon( ) with the '+' flag first, and if it fails with [EINVAL] then repeat the call without the '+' flag.

    and the RATIONALE at lines 69678-69680:

    The [EINVAL] error condition applies only when the '+' flag is used because this flag indicates that the application requires the use of signs, and if there are no signs in the locale data then this requirement cannot be satisfied.

    together expand upon this intended unique use.


    While implementations are generally permitted to add error numbers, and to add meanings to errors the standard specifies, as specified by XSH 2.3 at lines 17831-17833:


    Implementations may support additional errors not included in this list, may generate errors included in this list under circumstances other than those described here, or may contain extensions or limitations that prevent some errors from occurring.

    that same section goes on to place a restriction upon this implementation freedom, at lines 17839-17841 (and following for more restrictions not relevant here):

    Implementations may generate error numbers listed here under circumstances other than those described, if and only if all those error conditions can always be treated identically to the error conditions as described in this volume of POSIX.1-2024.


    Taken together all of this implies, to me anyway, that the implementation may not generate EINVAL for any error other than the one listed, as an application would then be unable to ascertain that the problem was the '+' in the format string, and offer a different format for the locale in question in that case.


    The problem all this causes for the implementation, is just how it should deal with applications which fail to meet their shall obligations, for example the one at line 69529:


    The application shall ensure that a conversion specification consists of the following sequence:

    I appreciate that when an application fails to comply with its obligations, implementation behaviour is unspecified, or perhaps even undefined, and is certainly beyond the scope of the standard.
    This however does not help the implementer, who must do something in such cases.
    Further as it seems above, the implementer is prohibited from using the obvious EINVAL error code in such a situation.
    Further, it does not help the application writer either, if some implementations simply ignore such issues and continue formatting as best they can, others return -1 and a seemingly random error code, and yet others simply call XSH 3 section 3/abort (pages 577-558).


    At the very least, the specification should offer some guidance in this situation, and probably rewrite the application usage and rationale, so as to no longer constrain EINVAL such that it cannot be used by the implementation for other issues.




  8. The standard offers no guidance on what should be done, should some of the data expected to be provided by the locale, is not defined there.
    The POSIX locale is one which does not supply any.
    Particularly after the resolution of issue 0001199, some of this has
    been dealt with, but not all.
    This includes the lack of a (non-empty) mon_decimal_point.
    There is also no discussion on what should be done if any of the specified strings are non-empty, but do not contain anything which produces a visible representation in the output.


    There should be.




  9. Returning to APPLICATION USAGE section, at lines 69672-69676:


    The '+' flag should be used with care, because if the locale's positive_sign and negative_sign values are both empty strings, there is no way to distinguish negative from positive values with signs and therefore strfmon( ) fails. If the application has a preference for signs but parentheses are acceptable, it should try strfmon( ) with the '+' flag first, and if it fails with [EINVAL] then repeat the call without the '+' flag.

    That suggests that simply omitting the '+' flag, will cause stfrmon() to use parentheses as the indicator for negative values.
    That is not what the post-issue 0001199 standard causes to happen.
    Instead, as stated on lines 69567-69571 when considering the case that
    neither of the '+' nor '(' flags are included in the format:

    If the style cannot be determined from these locale values because a value that needs to be used would be returned by localeconv() as {CHAR_MAX}, the style used shall be that specified for the '+' flag; if this would cause strfmon( ) to fail because the locale's positive_sign and negative_sign values would both be returned by localeconv( ) as empty strings, strfmon( ) shall behave as if the negative_sign value was the string "-".

    In other words, unless the format specifies the '(' flag (in which case this section is never reached, and its positive_sign and negative_sign and sign placement values are all ignored), if the '+' flag is not given, and the locale's default is not to use parentheses to indicate negative values, then the resulting output would use the empty positive_sign if the value is non-negative, and use "-" instead of an empty negative_sign if the value is negative.


    This APPLICATION USAGE text needs to be rewritten to take that into account.




  10. At times the standard is too specific in what it specifies.
    For example, at lines 69557-69558:


    If a sign's placement cannot be determined from these locale values because a value that needs to be used would be returned by localeconv() as 0 or {CHAR_MAX}, ...

    Why is it important what the issue is with the value?


    The range of values for the sign position are 0 to 4, with 0 not being useful for the situation being discussed in those lines, or {CHAR_MAX} to mean no value is supplied.
    But what if the locale data specifies a value of 7?
    That has no (currently) defined meaning, and hence is not useful for determining the placement of the sign, but it is not "returned by localeconv() as 0 or {CHAR_MAX}", so what is the implementation to do?


    This kind of over specification should be removed, it is not important why the sign placement cannot be determined from the locale values, just that it cannot.
    Note that this is not just a fanciful, perhaps even imagined, impossible case.
    A later version of the standard may add extra possible values to any of the fields for which a set of numeric designated choices are provided, and an older implenentation (an instance of stfrmon compiled into an existing applicaion for example) may encounter a previously invalid value, and needs to know how to handle that case.
    This is not an instance where "behaviour is unspecified" (or even "undefined") is an acceptable outcome.
    The standard must be permitted to evolve without invalidating existing applications.




  11. The EXAMPLES section, page 2132 (lines 69632-69670) assumes the existence of "a locale for the US" and, to make sense of the example output, what that locale must contain.
    I can find no justification in the standard to assume that such a locale exists anywhere.
    I certainly believe that most readers would understand USD as the international currency symbol for the United States of America, and $ as its national currency symbol, and probably that its frac_digits and int_frac_digits would usually both be two.
    I am not sure however that using a "-" to indicate negative values, and nothing for positive ones, rather than enclosing negative values in parentheses, or use of CR for positive and DB for negative, is how such a locale would be defined.
    Nor would I necessarily expect the sign, if used, to precede the currency symbol, rather than follow it.


    If some fictional locale is to be used for examples, regardless of whether that locale might be an actual locale on some system used by one or more of the actual writers of the text, then at least as much of it as is needed to understand the examples should be presented in the specification.


    Further, there should certainly be examples given where the POSIX (aka C) locale, the only one the standard actually specifies, is used.
    Had there been, some of the problems this specification had before issue 0001199 rectified them, and some of the problems it still has, might have been recognised and corrected much sooner than this.




  12. The DESCRIPTION at lines 69524-69526 contains:


    ..., and conversion specifications, each of which shall result in the fetching of zero or more arguments which are converted and formatted.

    "Zero or more" ?




    The zero case is obviously for the %% format conversion specification (which I personally would not treat as a conversion specification at all, but as an escaping mechanism, but that isn't the point here).




    But "or more" ??




    One is certainly more than zero, and one (exactly) is what every other format conversion requires.
    Why not just say "zero or one", and not leave the reader wondering when more than one might be required?
    Of course, if there is some hidden intent to allow indirect specification of the field width, the left precision, or the right precision, or some or all of those, in the way that the printf family of functions permit, which would perhaps be a useful addition, though not supported by any implementation of which I am aware, then the "or more" would be justified.




  13. In the same paragraph as the previous defect (lines 69524-69526) the text elided at the beginning of the text quoted previously is:


    The format is a character string, beginning and ending in its initial state, if any, that contains two types of objects: plain characters, which are simply copied to the output stream, ...

    but there is no definition anywhere of what is a plain character.
    The intent is obvious, but standards should not rely upon readers being able to deduce from what appears to be obvious, they should be explicit.




  14. The locale specification (XBD 7) and the specification of strfmon seem to lack the ability to format currency amounts in the (old style to be sure) formats previously used in the UK, and other countries including AU and NZ.
    That is, the Lsd format, as in £10/- or £9-19-11 and similar constructions.
    There may be other formats in use, or previously in use, which are similarly neglected.


    There is also no way to specify that other characters, rather than '(' and ')' be used to surround values, further it should be possible to have different characters surrounding positive and negative values - the positive_sign and negative_sign settings cannot be used for this, as only one of them is ever used for any particular value, and whichever that is is only ever used once.


    These issues should be fixed, but this is not the place to do it.
    Thus I will not offer potential solutions - the issue is here just so it is clear that the problems are known, and cannot at some future time be dismissed with "We didn't ever consider those possibilities."



Desired Action


The following contains instructions for the editor, as required.
Those are ordered by the affected line numbers, not grouped based upon the issues above.


Some of the suggested changes contain multiple reasonable resolutions, or depend upon other resolutions.
The committee will need to decide which to apply, while retaining overall consistency.
My preferred choice will always be the first listed.
The final choice given is generally to be considered only as a last resort choice, and should be avoided if at all possible.


I intend to follow submission of this defect report, with an added note which relates the various changes to the issues raised in the Description above,
and, when it seems needed, explains (my view at least of) how the suggested changes solve the issues reported.
It may also include some arguments for preferring my choice of resolution for some of the changes where more than one outcome would deal with the problem reported, in one way or another.








Make the following changes, all in the XSH section 3 group of pages for strfmon (pages 2129-2133).


Page and line numbers will be given for each change, but as they are all within the strfmon() section of XSH 3, that will not be restated.



  1. On page 2129, at lines 69524-29526 change the text:

    plain characters, which are simply copied to the output stream, and conversion specifications, each of which shall result in the fetching of zero or more arguments which are converted and formatted.

    to:

    conversion specifications, each of which might result in the fetching of an argument, which is to be converted, formatted, and the results copied to the output array; and other characters, which are simply copied to the output array.
    The format string is processed from beginning to end, one object at a time, with output from each appended to the output array s in the order in which it is generated.
    Processing may cease as soon as it is determined that the size of the string in the output array s will necessarily exceed maxsize bytes.


  2. On page 2129, between lines 69537 and 69538, insert a new paragraph:


    This specification is partly concerned with the widths of various characters and character strings.
    Implementations are not expected to attempt to determine actual character widths, but rather to assume the results will be displayed in a fixed width (mono spaced) font, where each character or character string is an integer multiple (0 or more) of one character position.
    Desired widths are all specified as a number of character positions using the same scale.
    To achieve what may be the desired formatting results, though not to simply obtain accurate values, the application should ensure that the results are displayed in a suitable fixed width font.


  3. On page 2129, at lines 69540-69542 change:


    In order to work with precision or width counts, the fill character shall be a single byte character; if not, the behavior is undefined.

    to:

    In order to work as intended with the left precision, and width values, the fill character needs to be one which will occupy a single column of a fixed with font's output; if not, the results generated are unlikely to be pleasing.


  4. On page 2129, lines 69545-69546, change:


    Do not format the currency amount with grouping characters.
    The default is to insert the grouping characters if defined for the current locale.

    to:

    Do not apply the monetary grouping algorithm to the currency amount.
    No mon_thousands_sep strings are inserted.
    The default is to insert the mon_thousands_sep as specified by the mon_grouping of the current locale, unless the locale has an empty mon_thousands_sep string, or has specified the mon_grouping as an empty string, or one beginning with {CHAR_MAX}.
    In such cases no monetary grouping is performed.


  5. On page 2130, at lines 69557-69558, delete:


    because a value that needs to be used would be returned by localeconv( ) as 0 or {CHAR_MAX}

    but not the immediately following ','.


  6. On page 2130, at lines 69560-69561, change the paragraph:


    If '(' is specified, negative amounts shall be enclosed within parentheses and the locale's positive_sign and negative_sign values shall not be used.

    to:

    If '(' is specified, negative amounts, and the currency symbol if defined for the locale, and not suppressed by the '!' flag, shall be enclosed within parentheses, and none of the locale's positive_sign, negative_sign, n_sign_posn, int_n_sign_posn, p_sign_posn and int_p_sign_posn values shall be used.


  7. On page 2130, at lines 69567-69568, delete:


    because a value that needs to be used would be returned by localeconv( ) as {CHAR_MAX}

    but not the immediately following ','.


  8. On page 2130, after line 69571, before line 69572, insert:


    If the locale's positive_sign and negative_sign are not empty, but produce identical output, then unless the locale's p_sign_posn or int_p_sign_posn, as appropriate, differs from the corresponding n_sign_posn or int_n_sign_posn, or are both 0, then strfmon() shall behave as if the relevant p_sign_posn was 2, and the relevant n_sign_position was 1.


  9. On page 2130, at line 69577, change the words:


    in bytes

    to:

    as a multiple applied to the width of a single digit character, that is, a number of columns if using a fixed width font,


  10. On page 2130, at line 69584, change the words:


    special character as in

    to:

    numeric fill character, which if, for example was '*', might produce


  11. On page 2130, at line 69590, change:


    grouping separators are inserted before the fill characters (if any) are added

    to:

    grouping separators (each an instance of the mon_thousands_sep of the locale) are inserted to the converted value string, as specified in the following paragraph.


  12. On page 2130, between lines 69591 and 69592, insert a new paragraph:


    When grouping is to be performed, and a Left Precision value n has been specified, then the first step is to determine how many instances of the grouping separator would be inserted into a value which used all n digits, regardless of the actual value to be formatted.
    That number is multiplied by the width (in columns) of the mon_thousands_sep string for the locale.
    That product is then added to n to form an increased Left Precision m.
    The actual converted value then has as many grouping separators inserted as are needed for that particular value, and the width of the result determined (in column positions) as v.
    Then m - v, if that value is greater than zero, fill characters f (or the default <space> if no = flag was given), are inserted before the converted value and its inserted grouping separators, giving the formatted converted value.
    When grouping is not to be performed, the width of the converted value is determined, as v and then n - v (if greater than zero) fill characters f (or the default <space>) are inserted before the converted value, to produce the formatted converted value.
    If no Left Precision is specified, and grouping is to be performed, grouping separators are simply inserted into the converted value and the result is then used as the formatted converted value.
    In this case if no grouping is to be performed, then the converted value is used as the formatted converted value.


  13. On page 2130, after line 69594, but continuing in the same paragraph, insert:


    The formatted converted value then has the appropriate strings prepended, and appended, such that a fixed output width is produced, which shall not vary depending upon whether the value was negative or otherwise.
    For positions which would be used, had the value had the opposite sign, <space> characters shall be inserted to retain length equality with other values with differing signs.
    Only if the Left Precision was not specified, or was specified and was not large enough for the value may the resulting length differ from the length produced by any other value for which the Left Precision is sufficient.
    The final result is then padded (to the right or left, as specified by the presence, or absence, respectively, of the - flag), if a Field Width specified as w was given, to ensure it is at least w characters wide.


  14. On page 2131, at line 69598, after the end of the sentence ending:


    by the current locale is used.

    insert a new sentence:

    If the locale specifies no default, the precision shall be taken as 0.
    If a non-zero precision results, and the locale specifies an empty mon_decimal_point string, or fails to specify that value, then

    and follow that with one of the following sentence endings:


    1. the precision p shall be treated as if specified as 0, regardless of the actual p value given.


    2. the decimal_point value from the LC_NUMERIC category of the same locale may be used, if that is defined and not empty. Otherwise

    3. and in this case then follow that by one of the other choices here.

    4. the mon_decimal_point shall be treated as if it were ".".


    5. the mon_decimal_point shall be treated as if it were ",".


    6. the implementation shall act as if the abort() function were called.


    7. the result is implementation defined.


    8. the result is unspecified.



  15. On page 2131, line 69613, after the words


    which may be different from the numeric

    insert the following, including the leading and trailing commas:

    , and is unrelated to,


  16. On page 2131, between lines 69615 and 69616, insert a new paragraph:


    If any of the LC_MONETARY values for the current locale specify invalid or inappropriate values, those values shall be treated as if they were not set in the locale, for the purposes of strfmon() (without affecting the locale for other uses in any way).


  17. On page 2131, after line 69630, add a new error code (substituting a suitable value from <errno.h> for EUNKNOWN, preferably EINVAL, but something else if that is not considered suitable):


    [EUNKNOWN]

    The format string was determined to be invalid, containing some inappropriate character after the leading '%' before a valid conversion specifier character is reached.



  18. On page 2131, after line 69630, after the preceding addition at the same location, add:


    [EILSEQ]

    One or more characters in the format string was not validly encoded according to the character set specified by the LC_CTYPE category of the application's current locale.
    Encoding errors in the strings provided for the LC_MONETARY locale values (in the locale used by strfmon_l, those would be formatted according to the LC_CTYPE of that locale), do not generate this error, but are treated as if the affected parameter was unset.



  19. On page 2132, line 69633, change the words:


    this example

    to:

    these examples


  20. On page 2132, after line 69633, before line 69634, insert a new paragraph,
    intelligently formatted (not ugly like here) (after verifying the values):


    In this locale the relevant values for the examples are set as follows:

    • currency_symbol "$"

    • mon_decimal_point "."

    • mon_thousands_sep ","

    • mon_grouping 3

    • positive_sign ""

    • negative_sign "-"

    • frac_digits 2

    • p_cs_precedes 1

    • p_sep_by_space 0

    • n_cs_precedes 1

    • n_sep_by_space 0

    • p_sign_posn 1

    • n_sign_posn 1




  21. On page 2132, between lines 69669 and 69670, insert the following,
    again, nicely formatted:


    The following show some examples when the locale used is the POSIX locale,
    as specified in XBD 7.3.3.1 (on page 150), using the values 123.45, -123.45, and 3456.781 (as above):

    %n [123]     No currency symbol, no fraction digits


            [-123]    Negative sign set to "-" when it & positive sign are empty


            [3457]    No grouping defined, round up fractional part




    %(n     [123]     Alternative pos/neg style, explicitly requested


            [(123)]


            [3457]




    %.2n [123]     No decimal_point defined, hence precision always 0


            [-123]


            [3457]




    %=x#5n  [ xx123]    Three digits, 2 fill chars, one empty sign position


            [-xx123]


            [ x3457]    No grouping so left precision not made wider




    %+n     EINVAL     Sign demanded, none defined by the locale


            EINVAL


            EINVAL



  22. On page 2132 at lines 69674-69675 change:


    but parentheses are acceptable

    to:

    but not a requirement,


  23. On page 2133 on line 69676, after the end of the existing sentence, but within the same paragraph, add the first, or both, of the following two new sentences:


    If parentheses would be acceptable to indicate negative values, the '+' flag could be changed to the '(' flag, which should always work, instead of simply removing it.
    Applications should note that the [EINVAL] may have a cause other than the presence of the '+' flag in a locale where there are no distinct sign strings.


  24. On page 2133, line 69678, delete the word


    only


  25. On page 2133, lines 69684-69686 delete the whole FUTURE DIRECTIONS section.
    That is, all 3 lines, header, and the (short) paragraph.



TagsNo tags attached.

Activities

kre

2026-09-17 19:28

reporter   bugnote:0007502

All suggested wordings can obviously be improved for spelling, grammar,
better standards-speak, etc. Please don't reduce precision when so doing.

The suggested changes:

#1) is from issues 12 and 13. I'd hope there's nothing controversial
about that. Part of the change might give rise to "Of course, that's
obvious" -- I don't believe in such things, nothing is too obvious to
be explicit about. There is also no "output stream" involved, the
output is to an array of bytes.

#2 is from issues 3, 4, 5, 6 probably, maybe more. The wording suggested
can probably be improved. This one is assuming that the objective is to
produce nicely aligned printed (or displayed) output, not anything where
particular byte offsets in the result have any particular meaning.

#3 is issue 3, or a part of it. Issue 5 as well. In particular, regardless
what criteria are to apply to the fill character, making the behaviour
undefined if those are not met is absurd. All the implementation should
ever do is insert N copies of the fill character (calculated as described
in change #12). That might have the effect of not producing nicely aligned
results as expected, but that's hardly undefined behaviour as the standard
defines that phrase. Nor is it even unspecified, or implementation defined.
It's just not what the application was hoping for.

#4 is part of issue 6, and just a general tidying of the language, for
added precision.

#5 is issue 10.

#6 is more general cleanup for better precision.

#7 is issue 10 (again).

#8 is more that perhaps should have been added by 0001199, and issue 2.

#9 is more of issue 3.

#10 is just a wording cleanup, related to a part of issue 3 (the numeric
fill character has a name, and "special character" is not it!)

#11 and #12 (which go together) are from issue 6. By all means improve
the wording of #12.

#13 is issue 4. Also more of issue 3.

#14 is issue 1. Choice 1 for this one seems obvious to me, if there
is no monetary decimal point character in the locale, then clearly the locale
does not want fractional currency values. If it simply prefers to have
no fractions, in the normal case, it can set frac_digits to 0, then the
application can override that with an explicit precision. setting the
decimal point to "" should thus mean "never have fractional values for
this locale".

However it seems relatively common in implementations to simply use
the numeric decimal point if the monetary one is not defined.
Personally I see no justification for that at all (even though it is what
NetBSD's implementation does (or did)). Note that if you choose choice 2,
then you MUST pick one of the others (1 (though that would be unlikely if
the aim is to allow some decimal point string), or one of 3..7). Despite
how it may appear, the standard does not require a locale to have a
non-empty numeric decimal point character - it requires localedef to
reject a specification where a non-empty numeric decimal point character
is not defined, but nowhere does it require an implementation to use
localedef when generating locale data, just that it be available to be
used if desired. What's more, if it did, the POSIX (aka C) locale
would be unable to be created, as that one violates all kinds of
constraints imposed upon locales that localedef deals with.
Choices 3 and 4 would be perhaps plausible (after all, strfmon defines
"-" as a plausible negative sign should none be provided) - perhaps
as follow-ons to choice 2. The rest of the choices, while possible,
are absurd.

#15 is just a minor cleanup, adding some precision - making it clear
that the numeric decimal point is not a fallback for the monetary
decimal point (perhaps the wording for that could be better). Of course
should you choose choice 2 for action #14, then this one should probably
be ignored.

#16 is issue 8.

#17 is issue 7 (or part thereof).

#18 is more from issue 7.

#19 is simply a grammar fix (should perhaps have been submitted as a
separate "Editorial" defect report, but it seemed saner to deal with
it at the same time as everything else).

#20 is issue 11.

#21 is more from issue 11. The actual examples will depend upon the
resolution of issue 1 (action #14).

#22 is kind of a follow-on to issues 9 and 8, and a correction to what is
currently implied by the text. Trying with the '+' flag if a sign is
wanted, is clear enough, but omitting the '+' flag and "parentheses are
acceptable" are unrelated concepts, parentheses will only be used when
there is no + or ( flag given, if the locale has one (and only one) of
its [int_]p_sign_posn and [int_]n_sign_posn, set to 0. Both 0 and the
the parentheses would be useless (this is another case just like having
the positive_sign and negative_sign both empty, or identical, and makes
using parentheses useless as well. But if neither of the [int_]p|n_sign_posn
values is 0, parentheses won't be used, so the text "but parentheses are
acceptable" is misleading. Instead, omitting the + just allows strfmon()
to format the value in locales like the POSIX locale, when none of the
LC_MONETARY values provides much, or any, assistance at all, while generating
something reasonable.

#23 is a follow-on to #22, and also relates to issue 7, and specifies
how an application, for which "parentheses are acceptable" might achieve
that if using the + flag fails (by using the '(' flag instead). The '('
flag also ends up (as a result of action #6) being defined in such a way
that it always works (always uses (n) for negative values and just p for
positive ones, regardless of what the locale specifies (or doesn't).

#24 is a (potential) consequence of action #17 (issue 7), and depends upon
what the resolution of the [EINVAL] issue turns out to be.

#25 is a bonus extra - no issue for this one. However, dividing number/
name spaces into pieces for use by different kinds of users, when done by
a standards organisation, is doomed to always either fail, or cause problems.

The whole basis for the standard is to specify what the applications can
expect to have happen for specific actions they take, and to tell the
implementers what they need to do to produce those results. If an implementer
sees the existing FUTURE DIRECTIONS and has a need for a new conversion
character (perhaps to generate values in units of millions, or something,
with an 'M' suffix/prefix somewhere) and does as advised by picking an
upper case character for that conversion (here, probably 'M'). That's fine,
they do that, and this group won't accidentally allocate M to some other
use.

But this implementation's new feature becomes popular, and ends up copied
by all of the other implementations, because applications want to use it
(assuming one can find an application that uses strfmon()!). What happens next?

Clearly the new conversion character needs to be standardised. And to be
compatible with what every implementation has implemented, it would need to
use the 'M' as the conversion character.

But the existing FUTURE DIRECTIONS says "no" to that, the standard must
use a lower case character. So, we either do what it says, in which
case the standard is promising an action that no implementation supports
(not good, and leads to implementers needing to provide both - the conversion
character the applications all use, along with the one the standard defines
for the purpose - that's simply wasteful and stupid), or the standard just
ignores the FUTURE DIRECTIONS and does the sane thing in a case like this.
If that is to be what is likely to happen, there is no point having the
FUTURE DIRECTIONS so let's just delete it now, and be done with it.

Beyond that, the more likely things for an implementation to want to
add, are more flag characters. After all, the difference between the
conversion characters are whether they are national or international
conversions ... what else could there be? Extra-terrestial currency
conversions? Household currency conversions? None of that is likely,
and the 'M' mooted above is more likely to be implemented as a flag,
than as a conversion specification (I see no reason why an alphabetic
flag can't be used - just as long as it can't be confused with a conversion
character). For that usage, there's no guidance as to what new flag
characters implementations might add, whilst avoiding conflicts with any
new flag characters added in the standard. Since (I submit) new flags
are far more likely than new conversion characters, the current FUTURE
DIRECTIONS is simply useless, even if you don't agree with the argument
in the previous paragraphs.

There is no resolution provided for issue 14. Good luck with that one.

Issue History

Date Modified Username Field Change
2026-09-17 19:23 kre New Issue
2026-09-17 19:28 kre Note Added: 0007502