printf: add missing format specifiers
Add: +, -, ' ', #, o, h, hh, t, f
Fix: .
properly consume floats, doubles, and long doubles
(just print out the hex value for now)
Bug: 32095958
Bug: 32091622
Bug: 32094687
Bug: 32091833
Bug: 32094696
Bug: 32095275
Test: test with osLog logging with the missing format specifiers
Change-Id: I1f95171b1827320822ed9a828f474001e3270c18
Signed-off-by: Ben Fennema <fennema@google.com>
diff --git a/firmware/build/os_config.mk b/firmware/build/os_config.mk
index 2415711..e40ae07 100644
--- a/firmware/build/os_config.mk
+++ b/firmware/build/os_config.mk
@@ -20,7 +20,8 @@
-g \
-ggdb3 \
-D_OS_BUILD_ \
- -O2
+ -DUSE_PRINTF_FLAG_CHARS \
+ -O2 \
LOCAL_CFLAGS_x86 += \
-m32
diff --git a/firmware/firmware.mk b/firmware/firmware.mk
index 25c17c7..ffd06d8 100644
--- a/firmware/firmware.mk
+++ b/firmware/firmware.mk
@@ -63,6 +63,7 @@
FLAGS += -Wmissing-declarations -Wlogical-op -Waddress -Wempty-body -Wpointer-arith -Wenum-compare -Wdouble-promotion -Wfloat-equal -Wshadow -fno-strict-aliasing
OSFLAGS += -g -ggdb3 -D_OS_BUILD_ -O2
+OSFLAGS_os += -DUSE_PRINTF_FLAG_CHARS
#debug mode
FLAGS += $(DEBUG)
diff --git a/firmware/os/core/printf.c b/firmware/os/core/printf.c
index 9c10dc3..2192653 100644
--- a/firmware/os/core/printf.c
+++ b/firmware/os/core/printf.c
@@ -18,82 +18,145 @@
#include <printf.h>
#include <cpu/cpuMath.h>
+#define FLAG_ALT (1 << 0)
+#define FLAG_ZERO_EXTEND (1 << 1)
+#define FLAG_IS_SIGNED (1 << 2)
+#define FLAG_NEG_PAD (1 << 3)
+#define FLAG_CAPS (1 << 4)
-static uint32_t StrPrvPrintfEx_number(printf_write_c putc_, void* userData, uint64_t number, bool base10, bool zeroExtend, bool isSigned, uint32_t padToLength, bool caps, bool* bail)
+struct PrintfData
+{
+ uint64_t number;
+ void *userData;
+ uint32_t fieldWidth;
+ uint32_t precision;
+ uint32_t flags;
+ uint8_t posChar;
+ uint8_t base;
+};
+
+static uint32_t StrPrvPrintfEx_number(printf_write_c putc_, struct PrintfData *data, bool *bail)
{
char buf[64];
uint32_t idx = sizeof(buf) - 1;
uint32_t chr, i;
- bool neg = false;
uint32_t numPrinted = 0;
*bail = false;
- if (padToLength > sizeof(buf) - 1)
- padToLength = sizeof(buf) - 1;
+#ifdef USE_PRINTF_FLAG_CHARS
+ if (data->fieldWidth > sizeof(buf) - 1)
+ data->fieldWidth = sizeof(buf) - 1;
+
+ if (data->precision > sizeof(buf) - 1)
+ data->precision = sizeof(buf) - 1;
+#endif
buf[idx--] = 0; //terminate
- if (isSigned) {
+ if (data->flags & FLAG_IS_SIGNED) {
- if (((int64_t)number) < 0) {
+ if (((int64_t)data->number) < 0) {
- neg = true;
- number = -number;
+ data->posChar = '-';
+ data->number = -data->number;
}
}
- do{
- if (base10) {
- uint64_t t = U64_DIV_BY_CONST_U16(number, 10);
- chr = (number - t * 10) + '0';
- number = t;
+ do {
+ if (data->base == 8) {
+
+ chr = (data->number & 0x07) + '0';
+ data->number >>= 3;
+ }
+ else if (data->base == 10) {
+
+ uint64_t t = U64_DIV_BY_CONST_U16(data->number, 10);
+ chr = (data->number - t * 10) + '0';
+ data->number = t;
}
else {
- chr = number & 0x0F;
- number >>= 4;
- chr = (chr >= 10) ? (chr + (caps ? 'A' : 'a') - 10) : (chr + '0');
+
+ chr = data->number & 0x0F;
+ data->number >>= 4;
+ chr = (chr >= 10) ? (chr + (data->flags & FLAG_CAPS ? 'A' : 'a') - 10) : (chr + '0');
}
buf[idx--] = chr;
numPrinted++;
- } while (number);
+ } while (data->number);
- if (neg) {
+#ifdef USE_PRINTF_FLAG_CHARS
+ while (data->precision > numPrinted) {
- buf[idx--] = '-';
+ buf[idx--] = '0';
numPrinted++;
}
- if (padToLength > numPrinted) {
+ if (data->flags & FLAG_ALT) {
- padToLength -= numPrinted;
- }
- else {
+ if (data->base == 8) {
- padToLength = 0;
+ if (buf[idx+1] != '0') {
+ buf[idx--] = '0';
+ numPrinted++;
+ }
+ }
+ else if (data->base == 16) {
+
+ buf[idx--] = data->flags & FLAG_CAPS ? 'X' : 'x';
+ numPrinted++;
+ buf[idx--] = '0';
+ numPrinted++;
+ }
}
- while (padToLength--) {
- buf[idx--] = zeroExtend ? '0' : ' ';
+ if (!(data->flags & FLAG_NEG_PAD)) {
+
+ if (data->fieldWidth > 0 && data->posChar != '\0')
+ data->fieldWidth--;
+
+ while (data->fieldWidth > numPrinted) {
+
+ buf[idx--] = data->flags & FLAG_ZERO_EXTEND ? '0' : ' ';
+ numPrinted++;
+ }
+ }
+#endif
+
+ if (data->posChar != '\0') {
+
+ buf[idx--] = data->posChar;
numPrinted++;
}
idx++;
-
for(i = 0; i < numPrinted; i++) {
- if (!putc_(userData,(buf + idx)[i])) {
+ if (!putc_(data->userData,(buf + idx)[i])) {
*bail = true;
break;
}
}
+#ifdef USE_PRINTF_FLAG_CHARS
+ if (!*bail && data->flags & FLAG_NEG_PAD) {
+
+ for(i = numPrinted; i < data->fieldWidth; i++) {
+
+ if (!putc_(data->userData, ' ')) {
+
+ *bail = true;
+ break;
+ }
+ }
+ }
+#endif
return i;
}
@@ -127,7 +190,11 @@
char c, t;
uint32_t numPrinted = 0;
- uint64_t val64;
+ double dbl;
+ long double ldbl;
+ struct PrintfData data;
+
+ data.userData = userData;
#define putc_(_ud,_c) \
do { \
@@ -143,10 +210,15 @@
numPrinted++;
}
else if (c == '%') {
-
- bool zeroExtend = false, useLong = false, useLongLong = false, useSizeT = false, bail = false, caps = false;
- uint32_t padToLength = 0, len, i;
+ uint32_t len, i;
const char* str;
+ bool useChar = false, useShort = false, useLong = false, useLongLong = false, useLongDouble =false, useSizeT = false, usePtrdiffT = false;
+ bool havePrecision = false, bail = false;
+
+ data.fieldWidth = 0;
+ data.precision = 0;
+ data.flags = 0;
+ data.posChar = 0;
more_fmt:
@@ -171,30 +243,47 @@
str = va_arg(vl,char*);
if (!str) str = "(null)";
- if (padToLength)
- len = StrVPrintf_StrLen_withMax(str,padToLength);
+
+ if (data.precision)
+ len = StrVPrintf_StrLen_withMax(str,data.precision);
else
- padToLength = len = StrVPrintf_StrLen(str);
+ len = StrVPrintf_StrLen(str);
- if (len > padToLength)
- len = padToLength;
- else {
- for(i = len; i < padToLength; i++)
+#ifdef USE_PRINTF_FLAG_CHARS
+ if (!(data.flags & FLAG_NEG_PAD)) {
+ for(i = len; i < data.fieldWidth; i++) {
putc_(userData, ' ');
+ numPrinted++;
+ }
}
- numPrinted += padToLength;
- for(i = 0; i < len; i++)
- putc_(userData,*str++);
+#endif
- numPrinted += len;
+ for(i = 0; i < len; i++) {
+ putc_(userData,*str++);
+ numPrinted++;
+ }
+
+#ifdef USE_PRINTF_FLAG_CHARS
+ if (data.flags & FLAG_NEG_PAD) {
+ for(i = len; i < data.fieldWidth; i++) {
+ putc_(userData, ' ');
+ numPrinted++;
+ }
+ }
+#endif
+
break;
- case '0':
case '.':
- if (!zeroExtend && !padToLength) {
+ havePrecision = true;
+ goto more_fmt;
- zeroExtend = true;
+ case '0':
+
+ if (!(data.flags & FLAG_ZERO_EXTEND) && !data.fieldWidth && !havePrecision) {
+
+ data.flags |= FLAG_ZERO_EXTEND;
goto more_fmt;
}
@@ -208,25 +297,57 @@
case '8':
case '9':
- padToLength = (padToLength * 10) + c - '0';
+ if (havePrecision)
+ data.precision = (data.precision * 10) + c - '0';
+ else
+ data.fieldWidth = (data.fieldWidth * 10) + c - '0';
+ goto more_fmt;
+
+ case '#':
+
+ data.flags |= FLAG_ALT;
+ goto more_fmt;
+
+ case '-':
+
+ data.flags |= FLAG_NEG_PAD;
+ goto more_fmt;
+
+ case '+':
+
+ data.posChar = '+';
+ goto more_fmt;
+
+ case ' ':
+
+ if (data.posChar != '+')
+ data.posChar = ' ';
goto more_fmt;
#define GET_UVAL64() \
useSizeT ? va_arg(vl, size_t) : \
+ usePtrdiffT ? va_arg(vl, ptrdiff_t) : \
useLongLong ? va_arg(vl, unsigned long long) : \
useLong ? va_arg(vl, unsigned long) : \
+ useChar ? (unsigned char)va_arg(vl, unsigned int) : \
+ useShort ? (unsigned short)va_arg(vl, unsigned int) : \
va_arg(vl, unsigned int)
#define GET_SVAL64() \
useSizeT ? va_arg(vl, size_t) : \
+ usePtrdiffT ? va_arg(vl, ptrdiff_t) : \
useLongLong ? va_arg(vl, signed long long) : \
useLong ? va_arg(vl, signed long) : \
+ useChar ? (signed char)va_arg(vl, signed int) : \
+ useShort ? (signed short)va_arg(vl, signed int) : \
va_arg(vl, signed int)
case 'u':
- val64 = GET_UVAL64();
- numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend,0,padToLength,0,&bail);
+ data.number = GET_UVAL64();
+ data.base = 10;
+ data.flags &= ~(FLAG_ALT | FLAG_CAPS);
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
if (bail)
goto out;
break;
@@ -234,29 +355,48 @@
case 'd':
case 'i':
- val64 = GET_SVAL64();
- numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, true, zeroExtend, true, padToLength, false, &bail);
+ data.number = GET_SVAL64();
+ data.base = 10;
+ data.flags &= ~(FLAG_ALT | FLAG_CAPS);
+ data.flags |= FLAG_IS_SIGNED;
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
+ if (bail)
+ goto out;
+ break;
+
+ case 'o':
+
+ data.number = GET_UVAL64();
+ data.base = 8;
+ data.flags &= ~FLAG_CAPS;
+ data.posChar = '\0';
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
if (bail)
goto out;
break;
case 'X':
- caps = true;
+
+ data.flags |= FLAG_CAPS;
case 'x':
- val64 = GET_UVAL64();
- numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail);
+ data.number = GET_UVAL64();
+ data.base = 16;
+ data.posChar = '\0';
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
if (bail)
goto out;
break;
case 'p':
- putc_(userData,'0');
- putc_(userData,'x');
- numPrinted += 2;
- val64 = (uintptr_t)va_arg(vl, const void*);
- numPrinted += StrPrvPrintfEx_number(putc_f, userData, val64, false, zeroExtend, false, padToLength, caps, &bail);
+
+ data.number = (uintptr_t)va_arg(vl, const void*);
+ data.base = 16;
+ data.flags &= ~FLAG_CAPS;
+ data.flags |= FLAG_ALT;
+ data.posChar = '\0';
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
if (bail)
goto out;
break;
@@ -264,25 +404,54 @@
#undef GET_UVAL64
#undef GET_SVAL64
+ case 'f':
+ case 'g':
+
+ if (useLongDouble) {
+ ldbl = va_arg(vl, long double);
+ data.number = *(uint64_t *)(&ldbl);
+ } else {
+ dbl = va_arg(vl, double);
+ data.number = *(uint32_t *)(&dbl);
+ }
+ data.base = 16;
+ data.flags &= ~FLAG_CAPS;
+ data.flags |= FLAG_ALT;
+ data.posChar = '\0';
+ numPrinted += StrPrvPrintfEx_number(putc_f, &data, &bail);
+ if (bail)
+ goto out;
+ break;
+
case 'h':
- // Technically, we're supposed to cast down to short/char, so that
- // { int x = 256; printf("%hhd", x); } would yield "0" (assuming 32-bit int
- // and 8-bit char). But the more common usage would be to expect the caller
- // to do printf("%hhd", (char) x) to get this output, which we're assuming
- // here to make our implementation simpler.
+
+ if (useShort)
+ useChar = true;
+ useShort = true;
goto more_fmt;
case 'L':
+
+ useLongDouble = true;
+ goto more_fmt;
+
case 'l':
+
if (useLong)
useLongLong = true;
useLong = true;
goto more_fmt;
case 'z':
+
useSizeT = true;
goto more_fmt;
+ case 't':
+
+ usePtrdiffT = true;
+ goto more_fmt;
+
default:
putc_(userData,c);