Merge "Add support for hexadecimal and pointer format specifiers to snprintf()" into integration
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
index 38ad1c7..2686327 100644
--- a/lib/libc/snprintf.c
+++ b/lib/libc/snprintf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,27 +24,55 @@
}
}
-static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
- unsigned int unum)
+static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
+ unsigned long long int unum,
+ unsigned int radix, char padc, int padn,
+ bool capitalise)
{
- /* Enough for a 32-bit unsigned decimal integer (4294967295). */
- char num_buf[10];
+ /* Just need enough space to store 64 bit decimal integer */
+ char num_buf[20];
int i = 0;
+ int width;
unsigned int rem;
+ char ascii_a = capitalise ? 'A' : 'a';
do {
- rem = unum % 10U;
- num_buf[i++] = '0' + rem;
- unum /= 10U;
+ rem = unum % radix;
+ if (rem < 10U) {
+ num_buf[i] = '0' + rem;
+ } else {
+ num_buf[i] = ascii_a + (rem - 10U);
+ }
+ i++;
+ unum /= radix;
} while (unum > 0U);
- while (--i >= 0) {
- if (*chars_printed < n) {
- *(*s) = num_buf[i];
- (*s)++;
+ width = i;
+ if (padn > width) {
+ (*chars_printed) += (size_t)padn;
+ } else {
+ (*chars_printed) += (size_t)width;
+ }
+
+ if (*chars_printed < n) {
+
+ if (padn > 0) {
+ while (width < padn) {
+ *(*s)++ = padc;
+ padn--;
+ }
}
- (*chars_printed)++;
+ while (--i >= 0) {
+ *(*s)++ = num_buf[i];
+ }
+
+ if (padn < 0) {
+ while (width < -padn) {
+ *(*s)++ = padc;
+ padn++;
+ }
+ }
}
}
@@ -52,9 +80,16 @@
* Reduced snprintf to be used for Trusted firmware.
* The following type specifiers are supported:
*
+ * %x (or %X) - hexadecimal format
* %d or %i - signed decimal format
* %s - string format
* %u - unsigned decimal format
+ * %p - pointer format
+ *
+ * The following padding specifiers are supported by this print
+ * %0NN - Left-pad the number with 0s (NN is a decimal number)
+ * %NN - Left-pad the number or string with spaces (NN is a decimal number)
+ * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
*
* The function panics on all other formats specifiers.
*
@@ -66,8 +101,12 @@
{
va_list args;
int num;
- unsigned int unum;
+ unsigned long long int unum;
char *str;
+ char padc; /* Padding character */
+ int padn; /* Number of characters to pad */
+ bool left;
+ bool capitalise;
size_t chars_printed = 0U;
if (n == 0U) {
@@ -83,11 +122,39 @@
va_start(args, fmt);
while (*fmt != '\0') {
+ left = false;
+ padc ='\0';
+ padn = 0;
+ capitalise = false;
if (*fmt == '%') {
fmt++;
/* Check the format specifier. */
+loop:
switch (*fmt) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ padc = (*fmt == '0') ? '0' : ' ';
+ for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
+ padn = (padn * 10) + (*fmt - '0');
+ }
+ if (left) {
+ padn = -padn;
+ }
+ goto loop;
+ case '-':
+ left = true;
+ fmt++;
+ goto loop;
+
case 'i':
case 'd':
num = va_arg(args, int);
@@ -104,7 +171,8 @@
unum = (unsigned int)num;
}
- unsigned_dec_print(&s, n, &chars_printed, unum);
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 10, padc, padn, false);
break;
case 's':
str = va_arg(args, char *);
@@ -112,8 +180,27 @@
break;
case 'u':
unum = va_arg(args, unsigned int);
- unsigned_dec_print(&s, n, &chars_printed, unum);
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 10, padc, padn, false);
break;
+ case 'p':
+ unum = (uintptr_t)va_arg(args, void *);
+ if (unum > 0U) {
+ string_print(&s, n, &chars_printed, "0x");
+ padn -= 2;
+ }
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 16, padc, padn, false);
+ break;
+ case 'X':
+ capitalise = true;
+ case 'x':
+ unum = va_arg(args, unsigned int);
+ unsigned_num_print(&s, n, &chars_printed,
+ unum, 16, padc, padn,
+ capitalise);
+ break;
+
default:
/* Panic on any other format specifier. */
ERROR("snprintf: specifier with ASCII code '%d' not supported.",