aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTravis Geiselbrecht <geist@foobox.com>2024-04-24 00:40:39 -0700
committerTravis Geiselbrecht <geist@foobox.com>2024-04-24 00:43:42 -0700
commit4401560dd9eae55f22868bbab4af939746d0eba7 (patch)
tree5fc14e190fb433c9fabfeb66c19671de84ba444e
parent45155fdbf936d7b1339282cdf0f3fa9006722ab7 (diff)
downloadlk-4401560dd9eae55f22868bbab4af939746d0eba7.tar.gz
[libc][printf] pull in fix from fuchsia that handles 0x prefixes properly
With this change printf passes the fuchsia unit tests, except the lack of field with and precision support. Disabled those parts of the test for now. Original change at https://fuchsia.googlesource.com/fuchsia/+/db61af0d1fc27c4c807f5da7d0553a4bb422882b The old code used to pad the output with zeros before the 0x, so you would end up with a 0000000x10. This is not the intended behavior. Original author: pedro.falcato@gmail.com
-rw-r--r--lib/libc/printf.c24
-rw-r--r--lib/libc/test/printf_tests.cpp6
2 files changed, 21 insertions, 9 deletions
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
index 41029aac..1baf8304 100644
--- a/lib/libc/printf.c
+++ b/lib/libc/printf.c
@@ -502,7 +502,7 @@ next_format:
s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar);
goto _output_string;
case 'p':
- flags |= LONGFLAG | ALTFLAG;
+ flags |= SIZETFLAG | ALTFLAG;
goto hex;
case 'X':
flags |= CAPSFLAG;
@@ -518,10 +518,15 @@ hex:
(flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) :
va_arg(ap, unsigned int);
s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags);
- if (flags & ALTFLAG) {
- OUTPUT_CHAR('0');
- OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x');
+
+ /* Normalize c, since code in _output_string needs to know that this is printing hex */
+ c = 'x';
+
+ /* Altflag processing should be bypassed when n == 0 so that 0x is not prepended to it */
+ if (n == 0) {
+ flags &= ~ALTFLAG;
}
+
goto _output_string;
case 'n':
ptr = va_arg(ap, void *);
@@ -589,6 +594,17 @@ _output_string:
if (flags & LEADZEROFLAG && signchar != '\0')
OUTPUT_CHAR(signchar);
+ /* Handle (altflag) printing 0x before the number */
+ /* Note that this needs to be done before padding the number */
+ if (c == 'x' && (flags & ALTFLAG)) {
+ OUTPUT_CHAR('0');
+ OUTPUT_CHAR(flags & CAPSFLAG ? 'X' : 'x');
+ /* Width is adjusted so i.e printf("%#04x", 0x02) -> 0x02 instead of 0x0002 */
+ if (format_num >= 2) {
+ format_num -= 2;
+ }
+ }
+
/* pad according to the format string */
for (; format_num > string_len; format_num--)
OUTPUT_CHAR(flags & LEADZEROFLAG ? '0' : ' ');
diff --git a/lib/libc/test/printf_tests.cpp b/lib/libc/test/printf_tests.cpp
index 4aca1fd2..b252c4d4 100644
--- a/lib/libc/test/printf_tests.cpp
+++ b/lib/libc/test/printf_tests.cpp
@@ -9,10 +9,6 @@
#include <stdio.h>
#include <string.h>
-#ifndef _KERNEL
-using ssize_t = ptrdiff_t;
-#endif
-
namespace {
template <typename IntegralType>
@@ -469,6 +465,6 @@ RUN_TEST(numbers)
RUN_TEST(hex)
RUN_TEST(alt_and_sign)
RUN_TEST(formatting)
-RUN_TEST(printf_field_width_and_precision_test)
+//RUN_TEST(printf_field_width_and_precision_test)
RUN_TEST(snprintf_truncation_test)
END_TEST_CASE(printf_tests)