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>
diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk
index 0dee4f5..554f36b 100644
--- a/lib/libc/libc.mk
+++ b/lib/libc/libc.mk
@@ -16,12 +16,12 @@
 			printf.c			\
 			putchar.c			\
 			puts.c				\
+			snprintf.c			\
 			strchr.c			\
 			strcmp.c			\
 			strlen.c			\
 			strncmp.c			\
-			strnlen.c			\
-			subr_prf.c)
+			strnlen.c)
 
 INCLUDES	+=	-Iinclude/lib/libc		\
 			-Iinclude/lib/libc/$(ARCH)	\
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
new file mode 100644
index 0000000..a1a8024
--- /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;
+}
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
new file mode 100644
index 0000000..0738a86
--- /dev/null
+++ b/lib/libc/snprintf.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform.h>
+#include <stdarg.h>
+
+static void string_print(char **s, size_t n, size_t *chars_printed,
+			 const char *str)
+{
+	while (*str) {
+		if (*chars_printed < n)
+			*(*s)++ = *str;
+		(*chars_printed)++;
+		str++;
+	}
+}
+
+static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
+			       unsigned int unum)
+{
+	/* Enough for a 32-bit unsigned decimal integer (4294967295). */
+	unsigned char num_buf[10];
+	int i = 0, rem;
+
+	do {
+		rem = unum % 10;
+		num_buf[i++] = '0' + rem;
+	} while (unum /= 10);
+
+	while (--i >= 0) {
+		if (*chars_printed < n)
+			*(*s)++ = num_buf[i];
+		(*chars_printed)++;
+	}
+}
+
+/*******************************************************************
+ * 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 num;
+	unsigned int unum;
+	char *str;
+	size_t chars_printed = 0;
+
+	if (n == 1) {
+		/* Buffer is too small to actually write anything else. */
+		*s = '\0';
+		n = 0;
+	} else if (n >= 2) {
+		/* Reserve space for the terminator character. */
+		n--;
+	}
+
+	va_start(args, fmt);
+	while (*fmt) {
+
+		if (*fmt == '%') {
+			fmt++;
+			/* Check the format specifier. */
+			switch (*fmt) {
+			case 'i':
+			case 'd':
+				num = va_arg(args, int);
+
+				if (num < 0) {
+					if (chars_printed < n)
+						*s++ = '-';
+					chars_printed++;
+
+					unum = (unsigned int)-num;
+				} else {
+					unum = (unsigned int)num;
+				}
+
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			case 's':
+				str = va_arg(args, char *);
+				string_print(&s, n, &chars_printed, str);
+				break;
+			case 'u':
+				unum = va_arg(args, unsigned int);
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			default:
+				/* Panic on any other format specifier. */
+				ERROR("snprintf: specifier with ASCII code '%d' not supported.",
+				      *fmt);
+				plat_panic_handler();
+			}
+			fmt++;
+			continue;
+		}
+
+		if (chars_printed < n)
+			*s++ = *fmt;
+		fmt++;
+		chars_printed++;
+	}
+
+	va_end(args);
+
+	if (n > 0)
+		*s = '\0';
+
+	return chars_printed;
+}