blob: 3b175ed6a5580de00f2a522edd6b9a0403d45b3c [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;
55 if (padn > width) {
56 (*chars_printed) += (size_t)padn;
57 } else {
58 (*chars_printed) += (size_t)width;
59 }
60
61 if (*chars_printed < n) {
62
63 if (padn > 0) {
64 while (width < padn) {
65 *(*s)++ = padc;
66 padn--;
67 }
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010068 }
69
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010070 while (--i >= 0) {
71 *(*s)++ = num_buf[i];
72 }
73
74 if (padn < 0) {
75 while (width < -padn) {
76 *(*s)++ = padc;
77 padn++;
78 }
79 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010080 }
81}
82
83/*******************************************************************
Madhukar Pappireddy38629702020-09-08 19:00:00 -050084 * Reduced vsnprintf to be used for Trusted firmware.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010085 * The following type specifiers are supported:
86 *
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010087 * %x (or %X) - hexadecimal format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010088 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010089 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010090 * %u - unsigned decimal format
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010091 * %p - pointer format
92 *
93 * The following padding specifiers are supported by this print
94 * %0NN - Left-pad the number with 0s (NN is a decimal number)
95 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
96 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010097 *
98 * The function panics on all other formats specifiers.
99 *
100 * It returns the number of characters that would be written if the
101 * buffer was big enough. If it returns a value lower than n, the
102 * whole string has been written.
103 *******************************************************************/
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500104int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100105{
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100106 int num;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100107 unsigned long long int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100108 char *str;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100109 char padc; /* Padding character */
110 int padn; /* Number of characters to pad */
111 bool left;
112 bool capitalise;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100113 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100114
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100115 if (n == 0U) {
116 /* There isn't space for anything. */
117 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100118 /* Buffer is too small to actually write anything else. */
119 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100120 n = 0U;
121 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100122 /* Reserve space for the terminator character. */
123 n--;
124 }
125
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100126 while (*fmt != '\0') {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100127 left = false;
128 padc ='\0';
129 padn = 0;
130 capitalise = false;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100131
132 if (*fmt == '%') {
133 fmt++;
134 /* Check the format specifier. */
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100135loop:
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100136 switch (*fmt) {
Heyi Guo11a16c82020-10-27 08:36:40 +0800137 case '%':
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800138 CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
Heyi Guo11a16c82020-10-27 08:36:40 +0800139 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100140 case '0':
141 case '1':
142 case '2':
143 case '3':
144 case '4':
145 case '5':
146 case '6':
147 case '7':
148 case '8':
149 case '9':
150 padc = (*fmt == '0') ? '0' : ' ';
151 for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
152 padn = (padn * 10) + (*fmt - '0');
153 }
154 if (left) {
155 padn = -padn;
156 }
157 goto loop;
158 case '-':
159 left = true;
160 fmt++;
161 goto loop;
162
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100163 case 'i':
164 case 'd':
165 num = va_arg(args, int);
166
167 if (num < 0) {
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800168 CHECK_AND_PUT_CHAR(s, n, chars_printed,
169 '-');
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100170 unum = (unsigned int)-num;
171 } else {
172 unum = (unsigned int)num;
173 }
174
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100175 unsigned_num_print(&s, n, &chars_printed,
176 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100177 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100178 case 's':
179 str = va_arg(args, char *);
180 string_print(&s, n, &chars_printed, str);
181 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100182 case 'u':
183 unum = va_arg(args, unsigned int);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100184 unsigned_num_print(&s, n, &chars_printed,
185 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100186 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100187 case 'p':
188 unum = (uintptr_t)va_arg(args, void *);
189 if (unum > 0U) {
190 string_print(&s, n, &chars_printed, "0x");
191 padn -= 2;
192 }
193 unsigned_num_print(&s, n, &chars_printed,
194 unum, 16, padc, padn, false);
195 break;
196 case 'X':
197 capitalise = true;
198 case 'x':
199 unum = va_arg(args, unsigned int);
200 unsigned_num_print(&s, n, &chars_printed,
201 unum, 16, padc, padn,
202 capitalise);
203 break;
204
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100205 default:
206 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100207 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100208 *fmt);
209 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100210 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100211 }
212 fmt++;
213 continue;
214 }
215
Heyi Guo58bf3bf2021-01-20 13:55:25 +0800216 CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100217
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100218 fmt++;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100219 }
220
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500221 if (n > 0U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100222 *s = '\0';
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500223 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100224
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100225 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100226}
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500227
228/*******************************************************************
229 * Reduced snprintf to be used for Trusted firmware.
230 * The following type specifiers are supported:
231 *
232 * %x (or %X) - hexadecimal format
233 * %d or %i - signed decimal format
234 * %s - string format
235 * %u - unsigned decimal format
236 * %p - pointer format
237 *
238 * The following padding specifiers are supported by this print
239 * %0NN - Left-pad the number with 0s (NN is a decimal number)
240 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
241 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
242 *
243 * The function panics on all other formats specifiers.
244 *
245 * It returns the number of characters that would be written if the
246 * buffer was big enough. If it returns a value lower than n, the
247 * whole string has been written.
248 *******************************************************************/
249int snprintf(char *s, size_t n, const char *fmt, ...)
250{
251 int count;
252 va_list all_args;
253
254 va_start(all_args, fmt);
255 count = vsnprintf(s, n, fmt, all_args);
256 va_end(all_args);
257
258 return count;
259}