blob: 42faa269dba7d53464e78b999b80cedd68aaf3f5 [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
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010013static void string_print(char **s, size_t n, size_t *chars_printed,
14 const char *str)
15{
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010016 while (*str != '\0') {
17 if (*chars_printed < n) {
18 *(*s) = *str;
19 (*s)++;
20 }
21
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010022 (*chars_printed)++;
23 str++;
24 }
25}
26
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010027static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
28 unsigned long long int unum,
29 unsigned int radix, char padc, int padn,
30 bool capitalise)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010031{
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010032 /* Just need enough space to store 64 bit decimal integer */
33 char num_buf[20];
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010034 int i = 0;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010035 int width;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010036 unsigned int rem;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010037 char ascii_a = capitalise ? 'A' : 'a';
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010038
39 do {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010040 rem = unum % radix;
41 if (rem < 10U) {
42 num_buf[i] = '0' + rem;
43 } else {
44 num_buf[i] = ascii_a + (rem - 10U);
45 }
46 i++;
47 unum /= radix;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010048 } while (unum > 0U);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010049
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010050 width = i;
51 if (padn > width) {
52 (*chars_printed) += (size_t)padn;
53 } else {
54 (*chars_printed) += (size_t)width;
55 }
56
57 if (*chars_printed < n) {
58
59 if (padn > 0) {
60 while (width < padn) {
61 *(*s)++ = padc;
62 padn--;
63 }
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +010064 }
65
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010066 while (--i >= 0) {
67 *(*s)++ = num_buf[i];
68 }
69
70 if (padn < 0) {
71 while (width < -padn) {
72 *(*s)++ = padc;
73 padn++;
74 }
75 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010076 }
77}
78
79/*******************************************************************
Madhukar Pappireddy38629702020-09-08 19:00:00 -050080 * Reduced vsnprintf to be used for Trusted firmware.
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010081 * The following type specifiers are supported:
82 *
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010083 * %x (or %X) - hexadecimal format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010084 * %d or %i - signed decimal format
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +010085 * %s - string format
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010086 * %u - unsigned decimal format
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +010087 * %p - pointer format
88 *
89 * The following padding specifiers are supported by this print
90 * %0NN - Left-pad the number with 0s (NN is a decimal number)
91 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
92 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +010093 *
94 * The function panics on all other formats specifiers.
95 *
96 * It returns the number of characters that would be written if the
97 * buffer was big enough. If it returns a value lower than n, the
98 * whole string has been written.
99 *******************************************************************/
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500100int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100101{
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100102 int num;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100103 unsigned long long int unum;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100104 char *str;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100105 char padc; /* Padding character */
106 int padn; /* Number of characters to pad */
107 bool left;
108 bool capitalise;
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100109 size_t chars_printed = 0U;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100110
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100111 if (n == 0U) {
112 /* There isn't space for anything. */
113 } else if (n == 1U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100114 /* Buffer is too small to actually write anything else. */
115 *s = '\0';
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100116 n = 0U;
117 } else {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100118 /* Reserve space for the terminator character. */
119 n--;
120 }
121
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100122 while (*fmt != '\0') {
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100123 left = false;
124 padc ='\0';
125 padn = 0;
126 capitalise = false;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100127
128 if (*fmt == '%') {
129 fmt++;
130 /* Check the format specifier. */
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100131loop:
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100132 switch (*fmt) {
Heyi Guo11a16c82020-10-27 08:36:40 +0800133 case '%':
134 if (chars_printed < n) {
135 *s = '%';
136 s++;
137 }
138 chars_printed++;
139 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) {
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100168 if (chars_printed < n) {
169 *s = '-';
170 s++;
171 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100172 chars_printed++;
173
174 unum = (unsigned int)-num;
175 } else {
176 unum = (unsigned int)num;
177 }
178
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100179 unsigned_num_print(&s, n, &chars_printed,
180 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100181 break;
Antonio Nino Diaz9fec10f2018-08-09 15:30:47 +0100182 case 's':
183 str = va_arg(args, char *);
184 string_print(&s, n, &chars_printed, str);
185 break;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100186 case 'u':
187 unum = va_arg(args, unsigned int);
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100188 unsigned_num_print(&s, n, &chars_printed,
189 unum, 10, padc, padn, false);
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100190 break;
Javier Almansa Sobrinoc58a13e2020-08-21 17:32:03 +0100191 case 'p':
192 unum = (uintptr_t)va_arg(args, void *);
193 if (unum > 0U) {
194 string_print(&s, n, &chars_printed, "0x");
195 padn -= 2;
196 }
197 unsigned_num_print(&s, n, &chars_printed,
198 unum, 16, padc, padn, false);
199 break;
200 case 'X':
201 capitalise = true;
202 case 'x':
203 unum = va_arg(args, unsigned int);
204 unsigned_num_print(&s, n, &chars_printed,
205 unum, 16, padc, padn,
206 capitalise);
207 break;
208
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100209 default:
210 /* Panic on any other format specifier. */
Antonio Nino Diazc0c8eb62018-08-15 17:02:28 +0100211 ERROR("snprintf: specifier with ASCII code '%d' not supported.",
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100212 *fmt);
213 plat_panic_handler();
Daniel Boulby8942a1b2018-06-22 14:16:03 +0100214 assert(0); /* Unreachable */
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100215 }
216 fmt++;
217 continue;
218 }
219
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100220 if (chars_printed < n) {
221 *s = *fmt;
222 s++;
223 }
224
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100225 fmt++;
226 chars_printed++;
227 }
228
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500229 if (n > 0U) {
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100230 *s = '\0';
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500231 }
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100232
Antonio Nino Diaz2e74f9b2018-08-23 15:11:46 +0100233 return (int)chars_printed;
Antonio Nino Diaz9c107fa2017-05-17 15:34:22 +0100234}
Madhukar Pappireddy38629702020-09-08 19:00:00 -0500235
236/*******************************************************************
237 * Reduced snprintf to be used for Trusted firmware.
238 * The following type specifiers are supported:
239 *
240 * %x (or %X) - hexadecimal format
241 * %d or %i - signed decimal format
242 * %s - string format
243 * %u - unsigned decimal format
244 * %p - pointer format
245 *
246 * The following padding specifiers are supported by this print
247 * %0NN - Left-pad the number with 0s (NN is a decimal number)
248 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
249 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
250 *
251 * The function panics on all other formats specifiers.
252 *
253 * It returns the number of characters that would be written if the
254 * buffer was big enough. If it returns a value lower than n, the
255 * whole string has been written.
256 *******************************************************************/
257int snprintf(char *s, size_t n, const char *fmt, ...)
258{
259 int count;
260 va_list all_args;
261
262 va_start(all_args, fmt);
263 count = vsnprintf(s, n, fmt, all_args);
264 va_end(all_args);
265
266 return count;
267}