diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/assert.c | 28 | ||||
-rw-r--r-- | lib/libc/libc.mk | 2 | ||||
-rw-r--r-- | lib/libc/printf.c | 70 | ||||
-rw-r--r-- | lib/libc/snprintf.c | 201 |
4 files changed, 219 insertions, 82 deletions
diff --git a/lib/libc/assert.c b/lib/libc/assert.c index 60f1a8660..dbf8507d0 100644 --- a/lib/libc/assert.c +++ b/lib/libc/assert.c @@ -9,35 +9,9 @@ #include <stdio.h> #include <common/debug.h> -#include <drivers/console.h> -#include <plat/common/platform.h> -/* - * Only print the output if PLAT_LOG_LEVEL_ASSERT is higher or equal to - * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1. - */ - -#if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE void __assert(const char *file, unsigned int line, const char *assertion) { printf("ASSERT: %s:%d:%s\n", file, line, assertion); - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); -} -#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO -void __assert(const char *file, unsigned int line) -{ - printf("ASSERT: %s:%d\n", file, line); - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); -} -#else -void __assert(void) -{ - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); + panic(); } -#endif diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk index e1b5560f8..729b91c06 100644 --- a/lib/libc/libc.mk +++ b/lib/libc/libc.mk @@ -16,12 +16,14 @@ LIBC_SRCS := $(addprefix lib/libc/, \ printf.c \ putchar.c \ puts.c \ + rand.c \ snprintf.c \ strchr.c \ strcmp.c \ strlcpy.c \ strlen.c \ strncmp.c \ + strncpy.c \ strnlen.c \ strrchr.c) diff --git a/lib/libc/printf.c b/lib/libc/printf.c index 2715a72d4..60203fb32 100644 --- a/lib/libc/printf.c +++ b/lib/libc/printf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -21,17 +21,36 @@ (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \ va_arg(_args, unsigned int))) -static int string_print(const char *str) +static int string_print(const char *str, char padc, int padn) { - int count = 0; + int i = 0, count = 0; assert(str != NULL); + while (str[i] != '\0') + i++; + + if (padn > 0) { + while (i < padn) { + (void)putchar(padc); + count++; + padn--; + } + } + for ( ; *str != '\0'; str++) { (void)putchar(*str); count++; } + if (padn < 0) { + while (i < -padn) { + (void)putchar(padc); + count++; + padn++; + } + } + return count; } @@ -41,6 +60,7 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, /* Just need enough space to store 64 bit decimal integer */ char num_buf[20]; int i = 0, count = 0; + int width; unsigned int rem; do { @@ -53,8 +73,10 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, unum /= radix; } while (unum > 0U); + width = i; + if (padn > 0) { - while (i < padn) { + while (width < padn) { (void)putchar(padc); count++; padn--; @@ -66,11 +88,19 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, count++; } + if (padn < 0) { + while (width < -padn) { + (void)putchar(padc); + count++; + padn++; + } + } + return count; } /******************************************************************* - * Reduced format print for Trusted firmware. + * Simplified version of printf() with smaller memory footprint. * The following type specifiers are supported by this print * %x - hexadecimal format * %s - string format @@ -85,6 +115,8 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, * * 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 print exits on all other formats specifiers other than valid * combinations of the above specifiers. @@ -92,15 +124,18 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, int vprintf(const char *fmt, va_list args) { int l_count; + int left; long long int num; unsigned long long int unum; char *str; - char padc = '\0'; /* Padding character */ + char padc; /* Padding character */ int padn; /* Number of characters to pad */ int count = 0; /* Number of printed characters */ while (*fmt != '\0') { l_count = 0; + left = 0; + padc = '\0'; padn = 0; if (*fmt == '%') { @@ -108,6 +143,25 @@ int vprintf(const char *fmt, va_list args) /* Check the format specifier */ loop: switch (*fmt) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + padc = ' '; + for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) + padn = (padn * 10) + (*fmt - '0'); + if (left) + padn = -padn; + goto loop; + case '-': + left = 1; + fmt++; + goto loop; case 'i': /* Fall through to next one */ case 'd': num = get_num_va_args(args, l_count); @@ -123,12 +177,12 @@ loop: break; case 's': str = va_arg(args, char *); - count += string_print(str); + count += string_print(str, padc, padn); break; case 'p': unum = (uintptr_t)va_arg(args, void *); if (unum > 0U) { - count += string_print("0x"); + count += string_print("0x", padc, 0); padn -= 2; } diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c index 38ad1c71a..29c50df4d 100644 --- a/lib/libc/snprintf.c +++ b/lib/libc/snprintf.c @@ -1,15 +1,26 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include <assert.h> #include <stdarg.h> +#include <stdlib.h> #include <common/debug.h> #include <plat/common/platform.h> +#define get_num_va_args(_args, _lcount) \ + (((_lcount) > 1) ? va_arg(_args, long long int) : \ + (((_lcount) == 1) ? 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) == 1) ? va_arg(_args, unsigned long int) : \ + va_arg(_args, unsigned int))) + static void string_print(char **s, size_t n, size_t *chars_printed, const char *str) { @@ -24,51 +35,72 @@ static void string_print(char **s, size_t n, size_t *chars_printed, } } -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 *count, + unsigned long long int unum, unsigned int radix, + char padc, int padn) { - /* 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; do { - rem = unum % 10U; - num_buf[i++] = '0' + rem; - unum /= 10U; + rem = unum % radix; + if (rem < 0xa) + num_buf[i] = '0' + rem; + else + num_buf[i] = 'a' + (rem - 0xa); + i++; + unum /= radix; } while (unum > 0U); + width = i; + + if (padn > 0) { + while (width < padn) { + if (*count < n) { + *(*s) = padc; + (*s)++; + } + (*count)++; + padn--; + } + } + while (--i >= 0) { - if (*chars_printed < n) { + if (*count < n) { *(*s) = num_buf[i]; (*s)++; } + (*count)++; + } - (*chars_printed)++; + if (padn < 0) { + while (width < -padn) { + if (*count < n) { + *(*s) = padc; + (*s)++; + } + (*count)++; + padn++; + } } } -/******************************************************************* - * Reduced snprintf to be used for Trusted firmware. - * The following type specifiers are supported: - * - * %d or %i - signed decimal format - * %s - string format - * %u - unsigned decimal format - * - * The function panics on all other formats specifiers. - * - * It returns the number of characters that would be written if the - * buffer was big enough. If it returns a value lower than n, the - * whole string has been written. - *******************************************************************/ -int snprintf(char *s, size_t n, const char *fmt, ...) +/* + * Scaled down version of vsnprintf(3). + */ +int vsnprintf(char *s, size_t n, const char *fmt, va_list args) { - va_list args; - int num; - unsigned int unum; + int l_count; + int left; char *str; - size_t chars_printed = 0U; + int num; + unsigned long long int unum; + char padc; /* Padding character */ + int padn; /* Number of characters to pad */ + size_t count = 0U; if (n == 0U) { /* There isn't space for anything. */ @@ -81,63 +113,138 @@ int snprintf(char *s, size_t n, const char *fmt, ...) n--; } - va_start(args, fmt); while (*fmt != '\0') { + l_count = 0; + left = 0; + padc = '\0'; + padn = 0; if (*fmt == '%') { fmt++; /* Check the format specifier. */ +loop: switch (*fmt) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + padc = ' '; + for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) + padn = (padn * 10) + (*fmt - '0'); + if (left) + padn = -padn; + goto loop; + case '-': + left = 1; + fmt++; + goto loop; case 'i': case 'd': - num = va_arg(args, int); + num = get_num_va_args(args, l_count); if (num < 0) { - if (chars_printed < n) { + if (count < n) { *s = '-'; s++; } - chars_printed++; + count++; unum = (unsigned int)-num; } else { unum = (unsigned int)num; } - unsigned_dec_print(&s, n, &chars_printed, unum); + unsigned_num_print(&s, n, &count, unum, 10, + padc, padn); break; + case 'l': + l_count++; + fmt++; + goto loop; case 's': str = va_arg(args, char *); - string_print(&s, n, &chars_printed, str); + string_print(&s, n, &count, str); break; case 'u': - unum = va_arg(args, unsigned int); - unsigned_dec_print(&s, n, &chars_printed, unum); + unum = get_unum_va_args(args, l_count); + unsigned_num_print(&s, n, &count, unum, 10, + padc, padn); break; - default: - /* Panic on any other format specifier. */ - ERROR("snprintf: specifier with ASCII code '%d' not supported.", - *fmt); - plat_panic_handler(); + case 'x': + unum = get_unum_va_args(args, l_count); + unsigned_num_print(&s, n, &count, unum, 16, + padc, padn); + break; + case '0': + padc = '0'; + padn = 0; + fmt++; + + for (;;) { + char ch = *fmt; + if ((ch < '0') || (ch > '9')) { + goto loop; + } + padn = (padn * 10) + (ch - '0'); + fmt++; + } assert(0); /* Unreachable */ + default: + /* + * Exit on any other format specifier and abort + * when in debug mode. + */ + WARN("snprintf: specifier with ASCII code '%d' not supported.\n", + *fmt); + assert(0); + return -1; } fmt++; continue; } - if (chars_printed < n) { + if (count < n) { *s = *fmt; s++; } fmt++; - chars_printed++; + count++; } - va_end(args); - if (n > 0U) *s = '\0'; - return (int)chars_printed; + return (int)count; +} + +/******************************************************************* + * Reduced snprintf to be used for Trusted firmware. + * The following type specifiers are supported: + * + * %d or %i - signed decimal format + * %s - string format + * %u - unsigned decimal format + * + * The function panics on all other formats specifiers. + * + * It returns the number of characters that would be written if the + * buffer was big enough. If it returns a value lower than n, the + * whole string has been written. + *******************************************************************/ +int snprintf(char *s, size_t n, const char *fmt, ...) +{ + va_list args; + int chars_printed; + + va_start(args, fmt); + chars_printed = vsnprintf(s, n, fmt, args); + va_end(args); + + return chars_printed; } |