Skip to content
This repository was archived by the owner on Jun 16, 2025. It is now read-only.

fmtscale() handling of values in the range [1, 9] is weird and arguably broken #1366

Open
@krader1961

Description

@krader1961

I was perplexed why the test coverage of fmtscale() was so low since it is a small function and has an explicit unit test. So I added more test cases to src/lib/libast/tests/string/fmtscale.c. I was surprised to find that zero becomes 0 but one becomes 1.0. Similarly 9 becomes 9.0. But ten becomes 10. Why do values between zero and ten have a decimal place? It is due to this block of code:

if (n > 0 && n < 10) {
char *decimal = nl_langinfo(RADIXCHAR);
sfsprintf(buf, z, "%I*u%s%d%s", sizeof(n), n, decimal, r, suf);
} else {

Notice that values like 11 and 999 are also converted to strings without a decimal point. Why are values in the range [1, 9] treated differently than zero or [10, 999]? This makes no sense. Values like seven are no more ambiguous than 666. Either both should have a decimal place or neither should.

In fact, the basic behavior of fmtscale() is suspect. Why is 999 rendered as 999 when scaled by 1000 rather than 1.0k? Or 500 as 500 rather than 0.5k?

The only use of the fmtscale() function is in sfvprintf(). There doesn't appear to be an analog in the stdio code for this behavior. The only tests that invoke fmtscale() are in src/cmd/ksh93/tests/b_printf.sh. Specifically, by tests like this one:

[[ $(printf "%#d" 1000) = "1.0k" ]] || log_error "printf %#d does not set k suffix"

Note that printf on other platforms behaves very differently for these cases. Either reporting an error or producing more sensible output (i.e., without the unexpected decimal value).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions