Fix padding+minus flag on numbers for printf-family functions (#787)

The C standard states, for conversions using the d, i, b, B, o, u, x or X conversion specifiers:
> The precision specifies the minimum number of digits to appear; if
> the value being converted can be represented in fewer digits, it is
> expanded with leading zeros.
- C standard, 7.23.6.1. The fprintf function

However, cosmopolitan currently suppresses the addition of leading
zeros when the minus flag is set. This is not reflected by anything
within the C standard, meaning that behavior is incorrect.

This patch fixes this.
This commit is contained in:
Gabriel Ravier 2023-03-25 19:39:25 +01:00 committed by GitHub
parent 2d6ea2fbc9
commit 792b1c84c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 13 deletions

View file

@ -34,17 +34,15 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
unsigned char flags) { unsigned char flags) {
unsigned i; unsigned i;
/* pad leading zeros */ /* pad leading zeros */
if (!(flags & FLAGS_LEFT)) { if (width && (flags & FLAGS_ZEROPAD) &&
if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { width--;
width--; }
} while ((len < prec) && (len < BUFFER_SIZE)) {
while ((len < prec) && (len < BUFFER_SIZE)) { buf[len++] = '0';
buf[len++] = '0'; }
} while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < BUFFER_SIZE)) {
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < BUFFER_SIZE)) { buf[len++] = '0';
buf[len++] = '0';
}
} }
/* handle hash */ /* handle hash */
if (flags & FLAGS_HASH) { if (flags & FLAGS_HASH) {
@ -134,8 +132,8 @@ int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
bool neg; bool neg;
uint128_t value, sign; uint128_t value, sign;
/* ignore '0' flag when prec is given */ /* ignore '0' flag when prec or minus flag is given */
if (flags & FLAGS_PRECISION) { if (flags & (FLAGS_PRECISION | FLAGS_LEFT)) {
flags &= ~FLAGS_ZEROPAD; flags &= ~FLAGS_ZEROPAD;
} }

View file

@ -62,6 +62,25 @@ TEST(fmt, d) {
EXPECT_STREQ(" 16", _gc(xasprintf("% d", 16))); EXPECT_STREQ(" 16", _gc(xasprintf("% d", 16)));
EXPECT_STREQ(" 2147483647", _gc(xasprintf("% d", INT_MAX))); EXPECT_STREQ(" 2147483647", _gc(xasprintf("% d", INT_MAX)));
EXPECT_STREQ("-2147483648", _gc(xasprintf("% d", INT_MIN))); EXPECT_STREQ("-2147483648", _gc(xasprintf("% d", INT_MIN)));
EXPECT_STREQ("042 ", _gc(xasprintf("%-4.3d", 42)));
EXPECT_STREQ("-00054", _gc(xasprintf("%-1.5lld", -54ll)));
EXPECT_STREQ("00109", _gc(xasprintf("%-.5lld", 109ll)));
EXPECT_STREQ("-00116", _gc(xasprintf("%-.5lld", -116ll)));
EXPECT_STREQ("00108 ", _gc(xasprintf("%-8.5lld", 108ll)));
EXPECT_STREQ("-00054 ", _gc(xasprintf("%-8.5lld", -54ll)));
}
TEST(fmt, u) {
EXPECT_STREQ("042 ", _gc(xasprintf("%-4.3u", 42)));
}
TEST(fmt, x) {
EXPECT_STREQ("0x01 ", _gc(xasprintf("%#-07.2x", 1)));
EXPECT_STREQ("0x00136d ", _gc(xasprintf("%#-010.6x", 4973)));
}
TEST(fmt, b) {
EXPECT_STREQ("000010100 ", _gc(xasprintf("%-14.9b", 20)));
} }
TEST(fmt, s) { TEST(fmt, s) {