aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/printf.c
diff options
context:
space:
mode:
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>2018-08-15 17:02:28 +0100
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>2018-08-22 10:26:05 +0100
commit870ce3ddd3b33c59418a7dba703e8a66ec75f98f (patch)
tree263cf675728e0ec8e0b560cf31f7043cb895df41 /lib/libc/printf.c
parentcb6dbfe3dc56088895c06b0492cfce289288444e (diff)
downloadtrusted-firmware-a-870ce3ddd3b33c59418a7dba703e8a66ec75f98f.tar.gz
libc: Move tf_printf and tf_snprintf to libc
Change their names to printf and snprintf. They are much smaller than the previous versions we had, which makes them better suited for the Trusted Firmware. Change-Id: Ia872af91b7b967c47fce012eccecede7873a3daf Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Diffstat (limited to 'lib/libc/printf.c')
-rw-r--r--lib/libc/printf.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
new file mode 100644
index 0000000000..a1a802483d
--- /dev/null
+++ b/lib/libc/printf.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <debug.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+/***********************************************************
+ * The tf_printf implementation for all BL stages
+ ***********************************************************/
+
+#define get_num_va_args(_args, _lcount) \
+ (((_lcount) > 1) ? va_arg(_args, long long int) : \
+ ((_lcount) ? va_arg(_args, long int) : va_arg(_args, int)))
+
+#define get_unum_va_args(_args, _lcount) \
+ (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \
+ ((_lcount) ? va_arg(_args, unsigned long int) : va_arg(_args, unsigned int)))
+
+static int string_print(const char *str)
+{
+ int count = 0;
+
+ assert(str);
+
+ while (*str) {
+ putchar(*str++);
+ count++;
+ }
+
+ return count;
+}
+
+static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
+ char padc, int padn)
+{
+ /* Just need enough space to store 64 bit decimal integer */
+ unsigned char num_buf[20];
+ int i = 0, rem, count = 0;
+
+ do {
+ rem = unum % radix;
+ if (rem < 0xa)
+ num_buf[i++] = '0' + rem;
+ else
+ num_buf[i++] = 'a' + (rem - 0xa);
+ } while (unum /= radix);
+
+ if (padn > 0) {
+ while (i < padn--) {
+ putchar(padc);
+ count++;
+ }
+ }
+
+ while (--i >= 0) {
+ putchar(num_buf[i]);
+ count++;
+ }
+
+ return count;
+}
+
+/*******************************************************************
+ * Reduced format print for Trusted firmware.
+ * The following type specifiers are supported by this print
+ * %x - hexadecimal format
+ * %s - string format
+ * %d or %i - signed decimal format
+ * %u - unsigned decimal format
+ * %p - pointer format
+ *
+ * The following length specifiers are supported by this print
+ * %l - long int (64-bit on AArch64)
+ * %ll - long long int (64-bit on AArch64)
+ * %z - size_t sized integer formats (64 bit on AArch64)
+ *
+ * The following padding specifiers are supported by this print
+ * %0NN - Left-pad the number with 0s (NN is a decimal number)
+ *
+ * The print exits on all other formats specifiers other than valid
+ * combinations of the above specifiers.
+ *******************************************************************/
+int vprintf(const char *fmt, va_list args)
+{
+ int l_count;
+ long long int num;
+ unsigned long long int unum;
+ char *str;
+ char padc = 0; /* Padding character */
+ int padn; /* Number of characters to pad */
+ int count = 0; /* Number of printed characters */
+
+ while (*fmt) {
+ l_count = 0;
+ padn = 0;
+
+ if (*fmt == '%') {
+ fmt++;
+ /* Check the format specifier */
+loop:
+ switch (*fmt) {
+ case 'i': /* Fall through to next one */
+ case 'd':
+ num = get_num_va_args(args, l_count);
+ if (num < 0) {
+ putchar('-');
+ unum = (unsigned long long int)-num;
+ padn--;
+ } else
+ unum = (unsigned long long int)num;
+
+ count += unsigned_num_print(unum, 10,
+ padc, padn);
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ count += string_print(str);
+ break;
+ case 'p':
+ unum = (uintptr_t)va_arg(args, void *);
+ if (unum) {
+ count += string_print("0x");
+ padn -= 2;
+ }
+
+ count += unsigned_num_print(unum, 16,
+ padc, padn);
+ break;
+ case 'x':
+ unum = get_unum_va_args(args, l_count);
+ count += unsigned_num_print(unum, 16,
+ padc, padn);
+ break;
+ case 'z':
+ if (sizeof(size_t) == 8)
+ l_count = 2;
+
+ fmt++;
+ goto loop;
+ case 'l':
+ l_count++;
+ fmt++;
+ goto loop;
+ case 'u':
+ unum = get_unum_va_args(args, l_count);
+ count += unsigned_num_print(unum, 10,
+ padc, padn);
+ break;
+ case '0':
+ padc = '0';
+ padn = 0;
+ fmt++;
+
+ while (1) {
+ char ch = *fmt;
+ if (ch < '0' || ch > '9') {
+ goto loop;
+ }
+ padn = (padn * 10) + (ch - '0');
+ fmt++;
+ }
+ default:
+ /* Exit on any other format specifier */
+ return -1;
+ }
+ fmt++;
+ continue;
+ }
+ putchar(*fmt++);
+ count++;
+ }
+
+ return count;
+}
+
+int printf(const char *fmt, ...)
+{
+ int count;
+ va_list va;
+
+ va_start(va, fmt);
+ count = vprintf(fmt, va);
+ va_end(va);
+
+ return count;
+}