blob: 7141091bb19a6fb3f04ec28c70809aba1e9661bf [file] [log] [blame]
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01001/*
Heyi Guo11a16c82020-10-27 08:36:40 +08002 * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Daniel Boulby8942a1b2018-06-22 14:16:03 +01007#include <assert.h>
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01008#include <stdarg.h>
9
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <common/debug.h>
11#include <plat/common/platform.h>
12
Heyi Guo58bf3bf2021-01-20 13:55:25 +080013#define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \
14 do { \
15 if ((chars_printed) < (size)) { \
16 *(buf) = (ch); \
17 (buf)++; \
18 } \
19 (chars_printed)++; \
20 } while (false)
21
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010022static void string_print(char **s, size_t n, size_t *chars_printed,
23 const char *str)
24{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010025 while (*str != '\0') {
Heyi Guo58bf3bf2021-01-20 13:55:25 +080026 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str);
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010027 str++;
28 }
29}
30
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010031static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
32 unsigned long long int unum,
33 unsigned int radix, char padc, int padn,
34 bool capitalise)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010035{
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010036 /* Just need enough space to store 64 bit decimal integer */
37 char num_buf[20];
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010038 int i = 0;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010039 int width;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010040 unsigned int rem;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010041 char ascii_a = capitalise ? 'A' : 'a';
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010042
Andre Przywara933cc5d2022-01-24 18:16:10 +000043 if (radix < 10) {
44 ERROR("snprintf: unsupported radix '%d'.", radix);
45 plat_panic_handler();
46 assert(0); /* Unreachable */
47 }
48
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010049 do {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010050 rem = unum % radix;
51 if (rem < 10U) {
52 num_buf[i] = '0' + rem;
53 } else {
54 num_buf[i] = ascii_a + (rem - 10U);
55 }
56 i++;
57 unum /= radix;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010058 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010059
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010060 width = i;
Andre Przywara3d959092021-12-21 12:35:54 +000061 for (i = padn - width; i > 0; i--) {
62 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
63 }
64 for (i = width; i > 0; i--) {
65 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, num_buf[i - 1]);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010066 }
Andre Przywara3d959092021-12-21 12:35:54 +000067 for (i = width + padn; i < 0; i++) {
68 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010069 }
70}
71
72/*******************************************************************
Madhukar Pappireddy38629702020-09-08 19:00:00 -050073 * Reduced vsnprintf to be used for Trusted firmware.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010074 * The following type specifiers are supported:
75 *
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010076 * %x (or %X) - hexadecimal format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010077 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010078 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010079 * %u - unsigned decimal format
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010080 * %p - pointer format
81 *
82 * The following padding specifiers are supported by this print
83 * %0NN - Left-pad the number with 0s (NN is a decimal number)
84 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
85 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010086 *
87 * The function panics on all other formats specifiers.
88 *
89 * It returns the number of characters that would be written if the
90 * buffer was big enough. If it returns a value lower than n, the
91 * whole string has been written.
92 *******************************************************************/
Madhukar Pappireddy38629702020-09-08 19:00:00 -050093int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010094{
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010095 int num;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010096 unsigned long long int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010097 char *str;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010098 char padc; /* Padding character */
99 int padn; /* Number of characters to pad */
100 bool left;
101 bool capitalise;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100102 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100103
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100104 if (n == 0U) {
105 /* There isn't space for anything. */
106 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100107 /* Buffer is too small to actually write anything else. */
108 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100109 n = 0U;
110 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100111 /* Reserve space for the terminator character. */
112 n--;
113 }
114
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100115 while (*fmt != '\0') {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100116 left = false;
117 padc ='\0';
118 padn = 0;
119 capitalise = false;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100120
121 if (*fmt == '%') {
122 fmt++;
123 /* Check the format specifier. */
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100124loop:
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100125 switch (*fmt) {
Heyi Guo11a16c82020-10-27 08:36:40 +0800126 case '%':
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800127 CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
Heyi Guo11a16c82020-10-27 08:36:40 +0800128 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100129 case '0':
130 case '1':
131 case '2':
132 case '3':
133 case '4':
134 case '5':
135 case '6':
136 case '7':
137 case '8':
138 case '9':
139 padc = (*fmt == '0') ? '0' : ' ';
140 for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
141 padn = (padn * 10) + (*fmt - '0');
142 }
143 if (left) {
144 padn = -padn;
145 }
146 goto loop;
147 case '-':
148 left = true;
149 fmt++;
150 goto loop;
151
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100152 case 'i':
153 case 'd':
154 num = va_arg(args, int);
155
156 if (num < 0) {
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800157 CHECK_AND_PUT_CHAR(s, n, chars_printed,
158 '-');
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100159 unum = (unsigned int)-num;
160 } else {
161 unum = (unsigned int)num;
162 }
163
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100164 unsigned_num_print(&s, n, &chars_printed,
165 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100166 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100167 case 's':
168 str = va_arg(args, char *);
169 string_print(&s, n, &chars_printed, str);
170 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100171 case 'u':
172 unum = va_arg(args, unsigned int);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100173 unsigned_num_print(&s, n, &chars_printed,
174 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100175 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100176 case 'p':
177 unum = (uintptr_t)va_arg(args, void *);
178 if (unum > 0U) {
179 string_print(&s, n, &chars_printed, "0x");
180 padn -= 2;
181 }
182 unsigned_num_print(&s, n, &chars_printed,
183 unum, 16, padc, padn, false);
184 break;
185 case 'X':
186 capitalise = true;
187 case 'x':
188 unum = va_arg(args, unsigned int);
189 unsigned_num_print(&s, n, &chars_printed,
190 unum, 16, padc, padn,
191 capitalise);
192 break;
193
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100194 default:
195 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100196 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100197 *fmt);
198 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100199 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100200 }
201 fmt++;
202 continue;
203 }
204
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800205 CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100206
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100207 fmt++;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100208 }
209
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500210 if (n > 0U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100211 *s = '\0';
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500212 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100213
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100214 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100215}
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500216
217/*******************************************************************
218 * Reduced snprintf to be used for Trusted firmware.
219 * The following type specifiers are supported:
220 *
221 * %x (or %X) - hexadecimal format
222 * %d or %i - signed decimal format
223 * %s - string format
224 * %u - unsigned decimal format
225 * %p - pointer format
226 *
227 * The following padding specifiers are supported by this print
228 * %0NN - Left-pad the number with 0s (NN is a decimal number)
229 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
230 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
231 *
232 * The function panics on all other formats specifiers.
233 *
234 * It returns the number of characters that would be written if the
235 * buffer was big enough. If it returns a value lower than n, the
236 * whole string has been written.
237 *******************************************************************/
238int snprintf(char *s, size_t n, const char *fmt, ...)
239{
240 int count;
241 va_list all_args;
242
243 va_start(all_args, fmt);
244 count = vsnprintf(s, n, fmt, all_args);
245 va_end(all_args);
246
247 return count;
248}