xref: /rk3399_ARM-atf/lib/libc/snprintf.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
1870ce3ddSAntonio Nino Diaz /*
2d5ccb754SAntonio Nino Diaz  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3870ce3ddSAntonio Nino Diaz  *
4870ce3ddSAntonio Nino Diaz  * SPDX-License-Identifier: BSD-3-Clause
5870ce3ddSAntonio Nino Diaz  */
6870ce3ddSAntonio Nino Diaz 
7a08a2014SDaniel Boulby #include <assert.h>
8870ce3ddSAntonio Nino Diaz #include <stdarg.h>
9870ce3ddSAntonio Nino Diaz 
10*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
11*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
12*09d40e0eSAntonio Nino Diaz 
13870ce3ddSAntonio Nino Diaz static void string_print(char **s, size_t n, size_t *chars_printed,
14870ce3ddSAntonio Nino Diaz 			 const char *str)
15870ce3ddSAntonio Nino Diaz {
16d5ccb754SAntonio Nino Diaz 	while (*str != '\0') {
17d5ccb754SAntonio Nino Diaz 		if (*chars_printed < n) {
18d5ccb754SAntonio Nino Diaz 			*(*s) = *str;
19d5ccb754SAntonio Nino Diaz 			(*s)++;
20d5ccb754SAntonio Nino Diaz 		}
21d5ccb754SAntonio Nino Diaz 
22870ce3ddSAntonio Nino Diaz 		(*chars_printed)++;
23870ce3ddSAntonio Nino Diaz 		str++;
24870ce3ddSAntonio Nino Diaz 	}
25870ce3ddSAntonio Nino Diaz }
26870ce3ddSAntonio Nino Diaz 
27870ce3ddSAntonio Nino Diaz static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
28870ce3ddSAntonio Nino Diaz 			       unsigned int unum)
29870ce3ddSAntonio Nino Diaz {
30870ce3ddSAntonio Nino Diaz 	/* Enough for a 32-bit unsigned decimal integer (4294967295). */
31d5ccb754SAntonio Nino Diaz 	char num_buf[10];
32d5ccb754SAntonio Nino Diaz 	int i = 0;
33d5ccb754SAntonio Nino Diaz 	unsigned int rem;
34870ce3ddSAntonio Nino Diaz 
35870ce3ddSAntonio Nino Diaz 	do {
36d5ccb754SAntonio Nino Diaz 		rem = unum % 10U;
37870ce3ddSAntonio Nino Diaz 		num_buf[i++] = '0' + rem;
38d5ccb754SAntonio Nino Diaz 		unum /= 10U;
39d5ccb754SAntonio Nino Diaz 	} while (unum > 0U);
40870ce3ddSAntonio Nino Diaz 
41870ce3ddSAntonio Nino Diaz 	while (--i >= 0) {
42d5ccb754SAntonio Nino Diaz 		if (*chars_printed < n) {
43d5ccb754SAntonio Nino Diaz 			*(*s) = num_buf[i];
44d5ccb754SAntonio Nino Diaz 			(*s)++;
45d5ccb754SAntonio Nino Diaz 		}
46d5ccb754SAntonio Nino Diaz 
47870ce3ddSAntonio Nino Diaz 		(*chars_printed)++;
48870ce3ddSAntonio Nino Diaz 	}
49870ce3ddSAntonio Nino Diaz }
50870ce3ddSAntonio Nino Diaz 
51870ce3ddSAntonio Nino Diaz /*******************************************************************
52870ce3ddSAntonio Nino Diaz  * Reduced snprintf to be used for Trusted firmware.
53870ce3ddSAntonio Nino Diaz  * The following type specifiers are supported:
54870ce3ddSAntonio Nino Diaz  *
55870ce3ddSAntonio Nino Diaz  * %d or %i - signed decimal format
56870ce3ddSAntonio Nino Diaz  * %s - string format
57870ce3ddSAntonio Nino Diaz  * %u - unsigned decimal format
58870ce3ddSAntonio Nino Diaz  *
59870ce3ddSAntonio Nino Diaz  * The function panics on all other formats specifiers.
60870ce3ddSAntonio Nino Diaz  *
61870ce3ddSAntonio Nino Diaz  * It returns the number of characters that would be written if the
62870ce3ddSAntonio Nino Diaz  * buffer was big enough. If it returns a value lower than n, the
63870ce3ddSAntonio Nino Diaz  * whole string has been written.
64870ce3ddSAntonio Nino Diaz  *******************************************************************/
65870ce3ddSAntonio Nino Diaz int snprintf(char *s, size_t n, const char *fmt, ...)
66870ce3ddSAntonio Nino Diaz {
67870ce3ddSAntonio Nino Diaz 	va_list args;
68870ce3ddSAntonio Nino Diaz 	int num;
69870ce3ddSAntonio Nino Diaz 	unsigned int unum;
70870ce3ddSAntonio Nino Diaz 	char *str;
71d5ccb754SAntonio Nino Diaz 	size_t chars_printed = 0U;
72870ce3ddSAntonio Nino Diaz 
73d5ccb754SAntonio Nino Diaz 	if (n == 0U) {
74d5ccb754SAntonio Nino Diaz 		/* There isn't space for anything. */
75d5ccb754SAntonio Nino Diaz 	} else if (n == 1U) {
76870ce3ddSAntonio Nino Diaz 		/* Buffer is too small to actually write anything else. */
77870ce3ddSAntonio Nino Diaz 		*s = '\0';
78d5ccb754SAntonio Nino Diaz 		n = 0U;
79d5ccb754SAntonio Nino Diaz 	} else {
80870ce3ddSAntonio Nino Diaz 		/* Reserve space for the terminator character. */
81870ce3ddSAntonio Nino Diaz 		n--;
82870ce3ddSAntonio Nino Diaz 	}
83870ce3ddSAntonio Nino Diaz 
84870ce3ddSAntonio Nino Diaz 	va_start(args, fmt);
85d5ccb754SAntonio Nino Diaz 	while (*fmt != '\0') {
86870ce3ddSAntonio Nino Diaz 
87870ce3ddSAntonio Nino Diaz 		if (*fmt == '%') {
88870ce3ddSAntonio Nino Diaz 			fmt++;
89870ce3ddSAntonio Nino Diaz 			/* Check the format specifier. */
90870ce3ddSAntonio Nino Diaz 			switch (*fmt) {
91870ce3ddSAntonio Nino Diaz 			case 'i':
92870ce3ddSAntonio Nino Diaz 			case 'd':
93870ce3ddSAntonio Nino Diaz 				num = va_arg(args, int);
94870ce3ddSAntonio Nino Diaz 
95870ce3ddSAntonio Nino Diaz 				if (num < 0) {
96d5ccb754SAntonio Nino Diaz 					if (chars_printed < n) {
97d5ccb754SAntonio Nino Diaz 						*s = '-';
98d5ccb754SAntonio Nino Diaz 						s++;
99d5ccb754SAntonio Nino Diaz 					}
100870ce3ddSAntonio Nino Diaz 					chars_printed++;
101870ce3ddSAntonio Nino Diaz 
102870ce3ddSAntonio Nino Diaz 					unum = (unsigned int)-num;
103870ce3ddSAntonio Nino Diaz 				} else {
104870ce3ddSAntonio Nino Diaz 					unum = (unsigned int)num;
105870ce3ddSAntonio Nino Diaz 				}
106870ce3ddSAntonio Nino Diaz 
107870ce3ddSAntonio Nino Diaz 				unsigned_dec_print(&s, n, &chars_printed, unum);
108870ce3ddSAntonio Nino Diaz 				break;
109870ce3ddSAntonio Nino Diaz 			case 's':
110870ce3ddSAntonio Nino Diaz 				str = va_arg(args, char *);
111870ce3ddSAntonio Nino Diaz 				string_print(&s, n, &chars_printed, str);
112870ce3ddSAntonio Nino Diaz 				break;
113870ce3ddSAntonio Nino Diaz 			case 'u':
114870ce3ddSAntonio Nino Diaz 				unum = va_arg(args, unsigned int);
115870ce3ddSAntonio Nino Diaz 				unsigned_dec_print(&s, n, &chars_printed, unum);
116870ce3ddSAntonio Nino Diaz 				break;
117870ce3ddSAntonio Nino Diaz 			default:
118870ce3ddSAntonio Nino Diaz 				/* Panic on any other format specifier. */
119870ce3ddSAntonio Nino Diaz 				ERROR("snprintf: specifier with ASCII code '%d' not supported.",
120870ce3ddSAntonio Nino Diaz 				      *fmt);
121870ce3ddSAntonio Nino Diaz 				plat_panic_handler();
122a08a2014SDaniel Boulby 				assert(0); /* Unreachable */
123870ce3ddSAntonio Nino Diaz 			}
124870ce3ddSAntonio Nino Diaz 			fmt++;
125870ce3ddSAntonio Nino Diaz 			continue;
126870ce3ddSAntonio Nino Diaz 		}
127870ce3ddSAntonio Nino Diaz 
128d5ccb754SAntonio Nino Diaz 		if (chars_printed < n) {
129d5ccb754SAntonio Nino Diaz 			*s = *fmt;
130d5ccb754SAntonio Nino Diaz 			s++;
131d5ccb754SAntonio Nino Diaz 		}
132d5ccb754SAntonio Nino Diaz 
133870ce3ddSAntonio Nino Diaz 		fmt++;
134870ce3ddSAntonio Nino Diaz 		chars_printed++;
135870ce3ddSAntonio Nino Diaz 	}
136870ce3ddSAntonio Nino Diaz 
137870ce3ddSAntonio Nino Diaz 	va_end(args);
138870ce3ddSAntonio Nino Diaz 
139d5ccb754SAntonio Nino Diaz 	if (n > 0U)
140870ce3ddSAntonio Nino Diaz 		*s = '\0';
141870ce3ddSAntonio Nino Diaz 
142d5ccb754SAntonio Nino Diaz 	return (int)chars_printed;
143870ce3ddSAntonio Nino Diaz }
144