1 /*
2 * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <stdarg.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11
12 #include <common/debug.h>
13
14 #define get_num_va_args(_args, _lcount) \
15 (((_lcount) > 1) ? va_arg(_args, long long int) : \
16 (((_lcount) == 1) ? va_arg(_args, long int) : \
17 va_arg(_args, int)))
18
19 #define get_unum_va_args(_args, _lcount) \
20 (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \
21 (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \
22 va_arg(_args, unsigned int)))
23
string_print(const char * str)24 static int string_print(const char *str)
25 {
26 int count = 0;
27
28 assert(str != NULL);
29
30 for ( ; *str != '\0'; str++) {
31 (void)putchar(*str);
32 count++;
33 }
34
35 return count;
36 }
37
unsigned_num_print(unsigned long long int unum,unsigned int radix,char padc,int padn)38 static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
39 char padc, int padn)
40 {
41 /* Just need enough space to store 64 bit decimal integer */
42 char num_buf[20];
43 int i = 0, count = 0;
44 unsigned int rem;
45
46 do {
47 rem = unum % radix;
48 if (rem < 0xa)
49 num_buf[i] = '0' + rem;
50 else
51 num_buf[i] = 'a' + (rem - 0xa);
52 i++;
53 unum /= radix;
54 } while (unum > 0U);
55
56 if (padn > 0) {
57 while (i < padn) {
58 (void)putchar(padc);
59 count++;
60 padn--;
61 }
62 }
63
64 while (--i >= 0) {
65 (void)putchar(num_buf[i]);
66 count++;
67 }
68
69 return count;
70 }
71
72 /*******************************************************************
73 * Reduced format print for Trusted firmware.
74 * The following type specifiers are supported by this print
75 * %x - hexadecimal format
76 * %s - string format
77 * %d or %i - signed decimal format
78 * %u - unsigned decimal format
79 * %p - pointer format
80 *
81 * The following length specifiers are supported by this print
82 * %l - long int (64-bit on AArch64)
83 * %ll - long long int (64-bit on AArch64)
84 * %z - size_t sized integer formats (64 bit on AArch64)
85 *
86 * The following padding specifiers are supported by this print
87 * %0NN - Left-pad the number with 0s (NN is a decimal number)
88 *
89 * The print exits on all other formats specifiers other than valid
90 * combinations of the above specifiers.
91 *******************************************************************/
vprintf(const char * fmt,va_list args)92 int vprintf(const char *fmt, va_list args)
93 {
94 int l_count;
95 long long int num;
96 unsigned long long int unum;
97 char *str;
98 char padc = '\0'; /* Padding character */
99 int padn; /* Number of characters to pad */
100 int count = 0; /* Number of printed characters */
101
102 while (*fmt != '\0') {
103 l_count = 0;
104 padn = 0;
105
106 if (*fmt == '%') {
107 fmt++;
108 /* Check the format specifier */
109 loop:
110 switch (*fmt) {
111 case '%':
112 (void)putchar('%');
113 break;
114 case 'i': /* Fall through to next one */
115 case 'd':
116 num = get_num_va_args(args, l_count);
117 if (num < 0) {
118 (void)putchar('-');
119 unum = (unsigned long long int)-num;
120 padn--;
121 } else
122 unum = (unsigned long long int)num;
123
124 count += unsigned_num_print(unum, 10,
125 padc, padn);
126 break;
127 case 's':
128 str = va_arg(args, char *);
129 count += string_print(str);
130 break;
131 case 'p':
132 unum = (uintptr_t)va_arg(args, void *);
133 if (unum > 0U) {
134 count += string_print("0x");
135 padn -= 2;
136 }
137
138 count += unsigned_num_print(unum, 16,
139 padc, padn);
140 break;
141 case 'x':
142 unum = get_unum_va_args(args, l_count);
143 count += unsigned_num_print(unum, 16,
144 padc, padn);
145 break;
146 case 'z':
147 if (sizeof(size_t) == 8U)
148 l_count = 2;
149
150 fmt++;
151 goto loop;
152 case 'l':
153 l_count++;
154 fmt++;
155 goto loop;
156 case 'u':
157 unum = get_unum_va_args(args, l_count);
158 count += unsigned_num_print(unum, 10,
159 padc, padn);
160 break;
161 case '0':
162 padc = '0';
163 padn = 0;
164 fmt++;
165
166 for (;;) {
167 char ch = *fmt;
168 if ((ch < '0') || (ch > '9')) {
169 goto loop;
170 }
171 padn = (padn * 10) + (ch - '0');
172 fmt++;
173 }
174 assert(0); /* Unreachable */
175 default:
176 /* Exit on any other format specifier */
177 return -1;
178 }
179 fmt++;
180 continue;
181 }
182 (void)putchar(*fmt);
183 fmt++;
184 count++;
185 }
186
187 return count;
188 }
189
printf(const char * fmt,...)190 int printf(const char *fmt, ...)
191 {
192 int count;
193 va_list va;
194
195 va_start(va, fmt);
196 count = vprintf(fmt, va);
197 va_end(va);
198
199 return count;
200 }
201