Fix the X conversion specifier's alternative form (#788)

The standard states that, when the # flag is used:
> The result is converted to an "alternative form". [...] For x (or X)
conversion, a nonzero result has 0x (or 0X) prefixed to it.
- C standard, 7.23.6.1. The fprintf function

cosmopolitan fails to use the correct alternative form (0X) when the X
conversion specifier is used, instead using 0x, which is not
capitalized.

This patch fixes this, along with the several tests that test for the
wrong behavior.
This commit is contained in:
Gabriel Ravier 2023-03-29 09:10:53 +02:00 committed by GitHub
parent a412ca7a77
commit 0adefbf152
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 10 deletions

View file

@ -317,6 +317,7 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
goto FormatNumber;
case 'b':
log2base = 1;
alphabet = "0123456789abcdefpb";
goto FormatNumber;
case 'o':
log2base = 3;

View file

@ -31,7 +31,7 @@ uint128_t __udivmodti4(uint128_t, uint128_t, uint128_t *);
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
char *buf, unsigned len, bool negative,
unsigned log2base, unsigned prec, unsigned width,
unsigned char flags) {
unsigned char flags, const char *alphabet) {
unsigned i;
/* pad leading zeros */
if (width && (flags & FLAGS_ZEROPAD) &&
@ -53,10 +53,9 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
len--;
}
}
if (log2base == 4 && len < BUFFER_SIZE) {
buf[len++] = 'x';
} else if (log2base == 1 && len < BUFFER_SIZE) {
buf[len++] = 'b';
if ((log2base == 4 || log2base == 1) && len < BUFFER_SIZE) {
buf[len++] = alphabet[17]; // x, X or b (for the corresponding conversion
// specifiers)
}
if (len < BUFFER_SIZE) {
buf[len++] = '0';
@ -122,7 +121,7 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
_npassert(count <= BUFFER_SIZE);
}
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
flags);
flags, alphabet);
}
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/math.h"
@ -77,6 +78,26 @@ TEST(fmt, u) {
TEST(fmt, x) {
EXPECT_STREQ("0x01 ", _gc(xasprintf("%#-07.2x", 1)));
EXPECT_STREQ("0x00136d ", _gc(xasprintf("%#-010.6x", 4973)));
EXPECT_STREQ("0X1", _gc(xasprintf("%#X", 1)));
EXPECT_STREQ("0XA", _gc(xasprintf("%#X", 10)));
EXPECT_STREQ("0XFFFF", _gc(xasprintf("%#X", 65535)));
EXPECT_STREQ("0XABCDEF", _gc(xasprintf("%#X", 0xABCDEF)));
EXPECT_STREQ("0X1", _gc(xasprintf("%#hX", (short)1)));
EXPECT_STREQ("0XA", _gc(xasprintf("%#hX", (short)10)));
EXPECT_STREQ("0XFFFF", _gc(xasprintf("%#hX", (short)65535)));
EXPECT_STREQ("0XABCD", _gc(xasprintf("%#hX", (short)0xABCD)));
EXPECT_STREQ(" 0X308C6705", _gc(xasprintf("%#20X", 814507781)));
EXPECT_STREQ("0X0000000000308C6705", _gc(xasprintf("%#020X", 814507781)));
EXPECT_STREQ(" 0X6705",
_gc(xasprintf("%#20hX", (short)814507781)));
EXPECT_STREQ("0X000000000000006705",
_gc(xasprintf("%#020hX", (short)814507781)));
EXPECT_STREQ(" 0XABCDEF", _gc(xasprintf("%#20X", 0xABCDEF)));
EXPECT_STREQ("0X000000000000ABCDEF", _gc(xasprintf("%#020X", 0xABCDEF)));
EXPECT_STREQ(" 0XCDEF",
_gc(xasprintf("%#20hX", (short)0xABCDEF)));
EXPECT_STREQ("0X00000000000000CDEF",
_gc(xasprintf("%#020hX", (short)0xABCDEF)));
}
TEST(fmt, b) {

View file

@ -310,8 +310,8 @@ TEST(sprintf, test_padding_pound_020) {
EXPECT_STREQ("00000000037777777001", Format("%#020o", 4294966785U));
EXPECT_STREQ("0x00000000001234abcd", Format("%#020x", 305441741));
EXPECT_STREQ("0x0000000000edcb5433", Format("%#020x", 3989525555U));
EXPECT_STREQ("0x00000000001234ABCD", Format("%#020X", 305441741));
EXPECT_STREQ("0x0000000000EDCB5433", Format("%#020X", 3989525555U));
EXPECT_STREQ("0X00000000001234ABCD", Format("%#020X", 305441741));
EXPECT_STREQ("0X0000000000EDCB5433", Format("%#020X", 3989525555U));
}
TEST(sprintf, test_padding_pound_20) {
@ -325,8 +325,8 @@ TEST(sprintf, test_padding_pound_20) {
EXPECT_STREQ(" 037777777001", Format("%#20o", 4294966785U));
EXPECT_STREQ(" 0x1234abcd", Format("%#20x", 305441741));
EXPECT_STREQ(" 0xedcb5433", Format("%#20x", 3989525555U));
EXPECT_STREQ(" 0x1234ABCD", Format("%#20X", 305441741));
EXPECT_STREQ(" 0xEDCB5433", Format("%#20X", 3989525555U));
EXPECT_STREQ(" 0X1234ABCD", Format("%#20X", 305441741));
EXPECT_STREQ(" 0XEDCB5433", Format("%#20X", 3989525555U));
}
TEST(sprintf, test_padding_20_point_5) {