diff options
author | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2018-08-15 17:02:28 +0100 |
---|---|---|
committer | Antonio Nino Diaz <antonio.ninodiaz@arm.com> | 2018-08-22 10:26:05 +0100 |
commit | 870ce3ddd3b33c59418a7dba703e8a66ec75f98f (patch) | |
tree | 263cf675728e0ec8e0b560cf31f7043cb895df41 /lib/libc/printf.c | |
parent | cb6dbfe3dc56088895c06b0492cfce289288444e (diff) | |
download | trusted-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.c | 190 |
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; +} |