blob: 675d2430d3b896c1199975e61c6b912112c294ac [file] [log] [blame]
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +01001/*
Yann Gautiereee19592022-02-14 10:29:32 +01002 * Copyright (c) 2017-2022, 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>
Andre Przywara94faff82022-01-27 17:47:55 +00009#include <stdint.h>
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010010
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011#include <common/debug.h>
12#include <plat/common/platform.h>
13
Heyi Guo58bf3bf2021-01-20 13:55:25 +080014#define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \
15 do { \
16 if ((chars_printed) < (size)) { \
17 *(buf) = (ch); \
18 (buf)++; \
19 } \
20 (chars_printed)++; \
21 } while (false)
22
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010023static void string_print(char **s, size_t n, size_t *chars_printed,
24 const char *str)
25{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010026 while (*str != '\0') {
Heyi Guo58bf3bf2021-01-20 13:55:25 +080027 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str);
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010028 str++;
29 }
30}
31
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010032static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
33 unsigned long long int unum,
34 unsigned int radix, char padc, int padn,
35 bool capitalise)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010036{
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010037 /* Just need enough space to store 64 bit decimal integer */
38 char num_buf[20];
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010039 int i = 0;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010040 int width;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010041 unsigned int rem;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010042 char ascii_a = capitalise ? 'A' : 'a';
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010043
Andre Przywara933cc5d2022-01-24 18:16:10 +000044 if (radix < 10) {
Yann Gautiereee19592022-02-14 10:29:32 +010045 ERROR("snprintf: unsupported radix '%u'.", radix);
Andre Przywara933cc5d2022-01-24 18:16:10 +000046 plat_panic_handler();
47 assert(0); /* Unreachable */
48 }
49
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010050 do {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010051 rem = unum % radix;
52 if (rem < 10U) {
53 num_buf[i] = '0' + rem;
54 } else {
55 num_buf[i] = ascii_a + (rem - 10U);
56 }
57 i++;
58 unum /= radix;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010059 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010060
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010061 width = i;
Andre Przywara3d959092021-12-21 12:35:54 +000062 for (i = padn - width; i > 0; i--) {
63 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
64 }
65 for (i = width; i > 0; i--) {
66 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, num_buf[i - 1]);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010067 }
Andre Przywara3d959092021-12-21 12:35:54 +000068 for (i = width + padn; i < 0; i++) {
69 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010070 }
71}
72
73/*******************************************************************
Madhukar Pappireddy38629702020-09-08 19:00:00 -050074 * Reduced vsnprintf to be used for Trusted firmware.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010075 * The following type specifiers are supported:
76 *
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010077 * %x (or %X) - hexadecimal format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010078 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010079 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010080 * %u - unsigned decimal format
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010081 * %p - pointer format
82 *
83 * The following padding specifiers are supported by this print
84 * %0NN - Left-pad the number with 0s (NN is a decimal number)
85 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
86 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010087 *
88 * The function panics on all other formats specifiers.
89 *
90 * It returns the number of characters that would be written if the
91 * buffer was big enough. If it returns a value lower than n, the
92 * whole string has been written.
93 *******************************************************************/
Madhukar Pappireddy38629702020-09-08 19:00:00 -050094int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010095{
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010096 int num;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010097 unsigned long long int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010098 char *str;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010099 char padc; /* Padding character */
100 int padn; /* Number of characters to pad */
101 bool left;
102 bool capitalise;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100103 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100104
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100105 if (n == 0U) {
106 /* There isn't space for anything. */
107 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100108 /* Buffer is too small to actually write anything else. */
109 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100110 n = 0U;
111 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100112 /* Reserve space for the terminator character. */
113 n--;
114 }
115
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100116 while (*fmt != '\0') {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100117 left = false;
118 padc ='\0';
119 padn = 0;
120 capitalise = false;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100121
122 if (*fmt == '%') {
123 fmt++;
124 /* Check the format specifier. */
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100125loop:
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100126 switch (*fmt) {
Heyi Guo11a16c82020-10-27 08:36:40 +0800127 case '%':
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800128 CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
Heyi Guo11a16c82020-10-27 08:36:40 +0800129 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100130 case '0':
131 case '1':
132 case '2':
133 case '3':
134 case '4':
135 case '5':
136 case '6':
137 case '7':
138 case '8':
139 case '9':
140 padc = (*fmt == '0') ? '0' : ' ';
141 for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
142 padn = (padn * 10) + (*fmt - '0');
143 }
144 if (left) {
145 padn = -padn;
146 }
147 goto loop;
148 case '-':
149 left = true;
150 fmt++;
151 goto loop;
152
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100153 case 'i':
154 case 'd':
155 num = va_arg(args, int);
156
157 if (num < 0) {
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800158 CHECK_AND_PUT_CHAR(s, n, chars_printed,
159 '-');
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100160 unum = (unsigned int)-num;
161 } else {
162 unum = (unsigned int)num;
163 }
164
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100165 unsigned_num_print(&s, n, &chars_printed,
166 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100167 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100168 case 's':
169 str = va_arg(args, char *);
170 string_print(&s, n, &chars_printed, str);
171 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100172 case 'u':
173 unum = va_arg(args, unsigned int);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100174 unsigned_num_print(&s, n, &chars_printed,
175 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100176 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100177 case 'p':
178 unum = (uintptr_t)va_arg(args, void *);
179 if (unum > 0U) {
180 string_print(&s, n, &chars_printed, "0x");
181 padn -= 2;
182 }
183 unsigned_num_print(&s, n, &chars_printed,
184 unum, 16, padc, padn, false);
185 break;
186 case 'X':
187 capitalise = true;
188 case 'x':
189 unum = va_arg(args, unsigned int);
190 unsigned_num_print(&s, n, &chars_printed,
191 unum, 16, padc, padn,
192 capitalise);
193 break;
194
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100195 default:
196 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100197 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100198 *fmt);
199 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100200 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100201 }
202 fmt++;
203 continue;
204 }
205
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800206 CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100207
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100208 fmt++;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100209 }
210
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500211 if (n > 0U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100212 *s = '\0';
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500213 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100214
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100215 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100216}
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500217
218/*******************************************************************
219 * Reduced snprintf to be used for Trusted firmware.
220 * The following type specifiers are supported:
221 *
222 * %x (or %X) - hexadecimal format
223 * %d or %i - signed decimal format
224 * %s - string format
225 * %u - unsigned decimal format
226 * %p - pointer format
227 *
228 * The following padding specifiers are supported by this print
229 * %0NN - Left-pad the number with 0s (NN is a decimal number)
230 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
231 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
232 *
233 * The function panics on all other formats specifiers.
234 *
235 * It returns the number of characters that would be written if the
236 * buffer was big enough. If it returns a value lower than n, the
237 * whole string has been written.
238 *******************************************************************/
239int snprintf(char *s, size_t n, const char *fmt, ...)
240{
241 int count;
242 va_list all_args;
243
244 va_start(all_args, fmt);
245 count = vsnprintf(s, n, fmt, all_args);
246 va_end(all_args);
247
248 return count;
249}