blob: 16611435bddc9b3e046dfbc4ebd230b4a804cd21 [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
43 do {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010044 rem = unum % radix;
45 if (rem < 10U) {
46 num_buf[i] = '0' + rem;
47 } else {
48 num_buf[i] = ascii_a + (rem - 10U);
49 }
50 i++;
51 unum /= radix;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010052 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010053
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010054 width = i;
Andre Przywara3d959092021-12-21 12:35:54 +000055 for (i = padn - width; i > 0; i--) {
56 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
57 }
58 for (i = width; i > 0; i--) {
59 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, num_buf[i - 1]);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010060 }
Andre Przywara3d959092021-12-21 12:35:54 +000061 for (i = width + padn; i < 0; i++) {
62 CHECK_AND_PUT_CHAR(*s, n, *chars_printed, padc);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010063 }
64}
65
66/*******************************************************************
Madhukar Pappireddy38629702020-09-08 19:00:00 -050067 * Reduced vsnprintf to be used for Trusted firmware.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010068 * The following type specifiers are supported:
69 *
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010070 * %x (or %X) - hexadecimal format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010071 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010072 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010073 * %u - unsigned decimal format
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010074 * %p - pointer format
75 *
76 * The following padding specifiers are supported by this print
77 * %0NN - Left-pad the number with 0s (NN is a decimal number)
78 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
79 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010080 *
81 * The function panics on all other formats specifiers.
82 *
83 * It returns the number of characters that would be written if the
84 * buffer was big enough. If it returns a value lower than n, the
85 * whole string has been written.
86 *******************************************************************/
Madhukar Pappireddy38629702020-09-08 19:00:00 -050087int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010088{
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010089 int num;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010090 unsigned long long int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010091 char *str;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010092 char padc; /* Padding character */
93 int padn; /* Number of characters to pad */
94 bool left;
95 bool capitalise;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010096 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010097
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010098 if (n == 0U) {
99 /* There isn't space for anything. */
100 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100101 /* Buffer is too small to actually write anything else. */
102 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100103 n = 0U;
104 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100105 /* Reserve space for the terminator character. */
106 n--;
107 }
108
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100109 while (*fmt != '\0') {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100110 left = false;
111 padc ='\0';
112 padn = 0;
113 capitalise = false;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100114
115 if (*fmt == '%') {
116 fmt++;
117 /* Check the format specifier. */
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100118loop:
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100119 switch (*fmt) {
Heyi Guo11a16c82020-10-27 08:36:40 +0800120 case '%':
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800121 CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
Heyi Guo11a16c82020-10-27 08:36:40 +0800122 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100123 case '0':
124 case '1':
125 case '2':
126 case '3':
127 case '4':
128 case '5':
129 case '6':
130 case '7':
131 case '8':
132 case '9':
133 padc = (*fmt == '0') ? '0' : ' ';
134 for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
135 padn = (padn * 10) + (*fmt - '0');
136 }
137 if (left) {
138 padn = -padn;
139 }
140 goto loop;
141 case '-':
142 left = true;
143 fmt++;
144 goto loop;
145
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100146 case 'i':
147 case 'd':
148 num = va_arg(args, int);
149
150 if (num < 0) {
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800151 CHECK_AND_PUT_CHAR(s, n, chars_printed,
152 '-');
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100153 unum = (unsigned int)-num;
154 } else {
155 unum = (unsigned int)num;
156 }
157
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100158 unsigned_num_print(&s, n, &chars_printed,
159 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100160 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100161 case 's':
162 str = va_arg(args, char *);
163 string_print(&s, n, &chars_printed, str);
164 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100165 case 'u':
166 unum = va_arg(args, unsigned int);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100167 unsigned_num_print(&s, n, &chars_printed,
168 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100169 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100170 case 'p':
171 unum = (uintptr_t)va_arg(args, void *);
172 if (unum > 0U) {
173 string_print(&s, n, &chars_printed, "0x");
174 padn -= 2;
175 }
176 unsigned_num_print(&s, n, &chars_printed,
177 unum, 16, padc, padn, false);
178 break;
179 case 'X':
180 capitalise = true;
181 case 'x':
182 unum = va_arg(args, unsigned int);
183 unsigned_num_print(&s, n, &chars_printed,
184 unum, 16, padc, padn,
185 capitalise);
186 break;
187
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100188 default:
189 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100190 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100191 *fmt);
192 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100193 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100194 }
195 fmt++;
196 continue;
197 }
198
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800199 CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100200
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100201 fmt++;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100202 }
203
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500204 if (n > 0U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100205 *s = '\0';
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500206 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100207
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100208 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100209}
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500210
211/*******************************************************************
212 * Reduced snprintf to be used for Trusted firmware.
213 * The following type specifiers are supported:
214 *
215 * %x (or %X) - hexadecimal format
216 * %d or %i - signed decimal format
217 * %s - string format
218 * %u - unsigned decimal format
219 * %p - pointer format
220 *
221 * The following padding specifiers are supported by this print
222 * %0NN - Left-pad the number with 0s (NN is a decimal number)
223 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
224 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
225 *
226 * The function panics on all other formats specifiers.
227 *
228 * It returns the number of characters that would be written if the
229 * buffer was big enough. If it returns a value lower than n, the
230 * whole string has been written.
231 *******************************************************************/
232int snprintf(char *s, size_t n, const char *fmt, ...)
233{
234 int count;
235 va_list all_args;
236
237 va_start(all_args, fmt);
238 count = vsnprintf(s, n, fmt, all_args);
239 va_end(all_args);
240
241 return count;
242}