aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/assert.c28
-rw-r--r--lib/libc/libc.mk2
-rw-r--r--lib/libc/printf.c70
-rw-r--r--lib/libc/snprintf.c201
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;
}