1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <stdarg.h>
9*54fd6939SJiyong Park
10*54fd6939SJiyong Park #include <common/debug.h>
11*54fd6939SJiyong Park #include <plat/common/platform.h>
12*54fd6939SJiyong Park
13*54fd6939SJiyong Park #define CHECK_AND_PUT_CHAR(buf, size, chars_printed, ch) \
14*54fd6939SJiyong Park do { \
15*54fd6939SJiyong Park if ((chars_printed) < (size)) { \
16*54fd6939SJiyong Park *(buf) = (ch); \
17*54fd6939SJiyong Park (buf)++; \
18*54fd6939SJiyong Park } \
19*54fd6939SJiyong Park (chars_printed)++; \
20*54fd6939SJiyong Park } while (false)
21*54fd6939SJiyong Park
string_print(char ** s,size_t n,size_t * chars_printed,const char * str)22*54fd6939SJiyong Park static void string_print(char **s, size_t n, size_t *chars_printed,
23*54fd6939SJiyong Park const char *str)
24*54fd6939SJiyong Park {
25*54fd6939SJiyong Park while (*str != '\0') {
26*54fd6939SJiyong Park CHECK_AND_PUT_CHAR(*s, n, *chars_printed, *str);
27*54fd6939SJiyong Park str++;
28*54fd6939SJiyong Park }
29*54fd6939SJiyong Park }
30*54fd6939SJiyong Park
unsigned_num_print(char ** s,size_t n,size_t * chars_printed,unsigned long long int unum,unsigned int radix,char padc,int padn,bool capitalise)31*54fd6939SJiyong Park static void unsigned_num_print(char **s, size_t n, size_t *chars_printed,
32*54fd6939SJiyong Park unsigned long long int unum,
33*54fd6939SJiyong Park unsigned int radix, char padc, int padn,
34*54fd6939SJiyong Park bool capitalise)
35*54fd6939SJiyong Park {
36*54fd6939SJiyong Park /* Just need enough space to store 64 bit decimal integer */
37*54fd6939SJiyong Park char num_buf[20];
38*54fd6939SJiyong Park int i = 0;
39*54fd6939SJiyong Park int width;
40*54fd6939SJiyong Park unsigned int rem;
41*54fd6939SJiyong Park char ascii_a = capitalise ? 'A' : 'a';
42*54fd6939SJiyong Park
43*54fd6939SJiyong Park do {
44*54fd6939SJiyong Park rem = unum % radix;
45*54fd6939SJiyong Park if (rem < 10U) {
46*54fd6939SJiyong Park num_buf[i] = '0' + rem;
47*54fd6939SJiyong Park } else {
48*54fd6939SJiyong Park num_buf[i] = ascii_a + (rem - 10U);
49*54fd6939SJiyong Park }
50*54fd6939SJiyong Park i++;
51*54fd6939SJiyong Park unum /= radix;
52*54fd6939SJiyong Park } while (unum > 0U);
53*54fd6939SJiyong Park
54*54fd6939SJiyong Park width = i;
55*54fd6939SJiyong Park if (padn > width) {
56*54fd6939SJiyong Park (*chars_printed) += (size_t)padn;
57*54fd6939SJiyong Park } else {
58*54fd6939SJiyong Park (*chars_printed) += (size_t)width;
59*54fd6939SJiyong Park }
60*54fd6939SJiyong Park
61*54fd6939SJiyong Park if (*chars_printed < n) {
62*54fd6939SJiyong Park
63*54fd6939SJiyong Park if (padn > 0) {
64*54fd6939SJiyong Park while (width < padn) {
65*54fd6939SJiyong Park *(*s)++ = padc;
66*54fd6939SJiyong Park padn--;
67*54fd6939SJiyong Park }
68*54fd6939SJiyong Park }
69*54fd6939SJiyong Park
70*54fd6939SJiyong Park while (--i >= 0) {
71*54fd6939SJiyong Park *(*s)++ = num_buf[i];
72*54fd6939SJiyong Park }
73*54fd6939SJiyong Park
74*54fd6939SJiyong Park if (padn < 0) {
75*54fd6939SJiyong Park while (width < -padn) {
76*54fd6939SJiyong Park *(*s)++ = padc;
77*54fd6939SJiyong Park padn++;
78*54fd6939SJiyong Park }
79*54fd6939SJiyong Park }
80*54fd6939SJiyong Park }
81*54fd6939SJiyong Park }
82*54fd6939SJiyong Park
83*54fd6939SJiyong Park /*******************************************************************
84*54fd6939SJiyong Park * Reduced vsnprintf to be used for Trusted firmware.
85*54fd6939SJiyong Park * The following type specifiers are supported:
86*54fd6939SJiyong Park *
87*54fd6939SJiyong Park * %x (or %X) - hexadecimal format
88*54fd6939SJiyong Park * %d or %i - signed decimal format
89*54fd6939SJiyong Park * %s - string format
90*54fd6939SJiyong Park * %u - unsigned decimal format
91*54fd6939SJiyong Park * %p - pointer format
92*54fd6939SJiyong Park *
93*54fd6939SJiyong Park * The following padding specifiers are supported by this print
94*54fd6939SJiyong Park * %0NN - Left-pad the number with 0s (NN is a decimal number)
95*54fd6939SJiyong Park * %NN - Left-pad the number or string with spaces (NN is a decimal number)
96*54fd6939SJiyong Park * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
97*54fd6939SJiyong Park *
98*54fd6939SJiyong Park * The function panics on all other formats specifiers.
99*54fd6939SJiyong Park *
100*54fd6939SJiyong Park * It returns the number of characters that would be written if the
101*54fd6939SJiyong Park * buffer was big enough. If it returns a value lower than n, the
102*54fd6939SJiyong Park * whole string has been written.
103*54fd6939SJiyong Park *******************************************************************/
vsnprintf(char * s,size_t n,const char * fmt,va_list args)104*54fd6939SJiyong Park int vsnprintf(char *s, size_t n, const char *fmt, va_list args)
105*54fd6939SJiyong Park {
106*54fd6939SJiyong Park int num;
107*54fd6939SJiyong Park unsigned long long int unum;
108*54fd6939SJiyong Park char *str;
109*54fd6939SJiyong Park char padc; /* Padding character */
110*54fd6939SJiyong Park int padn; /* Number of characters to pad */
111*54fd6939SJiyong Park bool left;
112*54fd6939SJiyong Park bool capitalise;
113*54fd6939SJiyong Park size_t chars_printed = 0U;
114*54fd6939SJiyong Park
115*54fd6939SJiyong Park if (n == 0U) {
116*54fd6939SJiyong Park /* There isn't space for anything. */
117*54fd6939SJiyong Park } else if (n == 1U) {
118*54fd6939SJiyong Park /* Buffer is too small to actually write anything else. */
119*54fd6939SJiyong Park *s = '\0';
120*54fd6939SJiyong Park n = 0U;
121*54fd6939SJiyong Park } else {
122*54fd6939SJiyong Park /* Reserve space for the terminator character. */
123*54fd6939SJiyong Park n--;
124*54fd6939SJiyong Park }
125*54fd6939SJiyong Park
126*54fd6939SJiyong Park while (*fmt != '\0') {
127*54fd6939SJiyong Park left = false;
128*54fd6939SJiyong Park padc ='\0';
129*54fd6939SJiyong Park padn = 0;
130*54fd6939SJiyong Park capitalise = false;
131*54fd6939SJiyong Park
132*54fd6939SJiyong Park if (*fmt == '%') {
133*54fd6939SJiyong Park fmt++;
134*54fd6939SJiyong Park /* Check the format specifier. */
135*54fd6939SJiyong Park loop:
136*54fd6939SJiyong Park switch (*fmt) {
137*54fd6939SJiyong Park case '%':
138*54fd6939SJiyong Park CHECK_AND_PUT_CHAR(s, n, chars_printed, '%');
139*54fd6939SJiyong Park break;
140*54fd6939SJiyong Park case '0':
141*54fd6939SJiyong Park case '1':
142*54fd6939SJiyong Park case '2':
143*54fd6939SJiyong Park case '3':
144*54fd6939SJiyong Park case '4':
145*54fd6939SJiyong Park case '5':
146*54fd6939SJiyong Park case '6':
147*54fd6939SJiyong Park case '7':
148*54fd6939SJiyong Park case '8':
149*54fd6939SJiyong Park case '9':
150*54fd6939SJiyong Park padc = (*fmt == '0') ? '0' : ' ';
151*54fd6939SJiyong Park for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) {
152*54fd6939SJiyong Park padn = (padn * 10) + (*fmt - '0');
153*54fd6939SJiyong Park }
154*54fd6939SJiyong Park if (left) {
155*54fd6939SJiyong Park padn = -padn;
156*54fd6939SJiyong Park }
157*54fd6939SJiyong Park goto loop;
158*54fd6939SJiyong Park case '-':
159*54fd6939SJiyong Park left = true;
160*54fd6939SJiyong Park fmt++;
161*54fd6939SJiyong Park goto loop;
162*54fd6939SJiyong Park
163*54fd6939SJiyong Park case 'i':
164*54fd6939SJiyong Park case 'd':
165*54fd6939SJiyong Park num = va_arg(args, int);
166*54fd6939SJiyong Park
167*54fd6939SJiyong Park if (num < 0) {
168*54fd6939SJiyong Park CHECK_AND_PUT_CHAR(s, n, chars_printed,
169*54fd6939SJiyong Park '-');
170*54fd6939SJiyong Park unum = (unsigned int)-num;
171*54fd6939SJiyong Park } else {
172*54fd6939SJiyong Park unum = (unsigned int)num;
173*54fd6939SJiyong Park }
174*54fd6939SJiyong Park
175*54fd6939SJiyong Park unsigned_num_print(&s, n, &chars_printed,
176*54fd6939SJiyong Park unum, 10, padc, padn, false);
177*54fd6939SJiyong Park break;
178*54fd6939SJiyong Park case 's':
179*54fd6939SJiyong Park str = va_arg(args, char *);
180*54fd6939SJiyong Park string_print(&s, n, &chars_printed, str);
181*54fd6939SJiyong Park break;
182*54fd6939SJiyong Park case 'u':
183*54fd6939SJiyong Park unum = va_arg(args, unsigned int);
184*54fd6939SJiyong Park unsigned_num_print(&s, n, &chars_printed,
185*54fd6939SJiyong Park unum, 10, padc, padn, false);
186*54fd6939SJiyong Park break;
187*54fd6939SJiyong Park case 'p':
188*54fd6939SJiyong Park unum = (uintptr_t)va_arg(args, void *);
189*54fd6939SJiyong Park if (unum > 0U) {
190*54fd6939SJiyong Park string_print(&s, n, &chars_printed, "0x");
191*54fd6939SJiyong Park padn -= 2;
192*54fd6939SJiyong Park }
193*54fd6939SJiyong Park unsigned_num_print(&s, n, &chars_printed,
194*54fd6939SJiyong Park unum, 16, padc, padn, false);
195*54fd6939SJiyong Park break;
196*54fd6939SJiyong Park case 'X':
197*54fd6939SJiyong Park capitalise = true;
198*54fd6939SJiyong Park case 'x':
199*54fd6939SJiyong Park unum = va_arg(args, unsigned int);
200*54fd6939SJiyong Park unsigned_num_print(&s, n, &chars_printed,
201*54fd6939SJiyong Park unum, 16, padc, padn,
202*54fd6939SJiyong Park capitalise);
203*54fd6939SJiyong Park break;
204*54fd6939SJiyong Park
205*54fd6939SJiyong Park default:
206*54fd6939SJiyong Park /* Panic on any other format specifier. */
207*54fd6939SJiyong Park ERROR("snprintf: specifier with ASCII code '%d' not supported.",
208*54fd6939SJiyong Park *fmt);
209*54fd6939SJiyong Park plat_panic_handler();
210*54fd6939SJiyong Park assert(0); /* Unreachable */
211*54fd6939SJiyong Park }
212*54fd6939SJiyong Park fmt++;
213*54fd6939SJiyong Park continue;
214*54fd6939SJiyong Park }
215*54fd6939SJiyong Park
216*54fd6939SJiyong Park CHECK_AND_PUT_CHAR(s, n, chars_printed, *fmt);
217*54fd6939SJiyong Park
218*54fd6939SJiyong Park fmt++;
219*54fd6939SJiyong Park }
220*54fd6939SJiyong Park
221*54fd6939SJiyong Park if (n > 0U) {
222*54fd6939SJiyong Park *s = '\0';
223*54fd6939SJiyong Park }
224*54fd6939SJiyong Park
225*54fd6939SJiyong Park return (int)chars_printed;
226*54fd6939SJiyong Park }
227*54fd6939SJiyong Park
228*54fd6939SJiyong Park /*******************************************************************
229*54fd6939SJiyong Park * Reduced snprintf to be used for Trusted firmware.
230*54fd6939SJiyong Park * The following type specifiers are supported:
231*54fd6939SJiyong Park *
232*54fd6939SJiyong Park * %x (or %X) - hexadecimal format
233*54fd6939SJiyong Park * %d or %i - signed decimal format
234*54fd6939SJiyong Park * %s - string format
235*54fd6939SJiyong Park * %u - unsigned decimal format
236*54fd6939SJiyong Park * %p - pointer format
237*54fd6939SJiyong Park *
238*54fd6939SJiyong Park * The following padding specifiers are supported by this print
239*54fd6939SJiyong Park * %0NN - Left-pad the number with 0s (NN is a decimal number)
240*54fd6939SJiyong Park * %NN - Left-pad the number or string with spaces (NN is a decimal number)
241*54fd6939SJiyong Park * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
242*54fd6939SJiyong Park *
243*54fd6939SJiyong Park * The function panics on all other formats specifiers.
244*54fd6939SJiyong Park *
245*54fd6939SJiyong Park * It returns the number of characters that would be written if the
246*54fd6939SJiyong Park * buffer was big enough. If it returns a value lower than n, the
247*54fd6939SJiyong Park * whole string has been written.
248*54fd6939SJiyong Park *******************************************************************/
snprintf(char * s,size_t n,const char * fmt,...)249*54fd6939SJiyong Park int snprintf(char *s, size_t n, const char *fmt, ...)
250*54fd6939SJiyong Park {
251*54fd6939SJiyong Park int count;
252*54fd6939SJiyong Park va_list all_args;
253*54fd6939SJiyong Park
254*54fd6939SJiyong Park va_start(all_args, fmt);
255*54fd6939SJiyong Park count = vsnprintf(s, n, fmt, all_args);
256*54fd6939SJiyong Park va_end(all_args);
257*54fd6939SJiyong Park
258*54fd6939SJiyong Park return count;
259*54fd6939SJiyong Park }
260