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 <stddef.h>
11 #include <stdint.h>
12 #include <stdio.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 /* num_buf is only large enough for radix >= 10 */
47 if (radix < 10) {
48 assert(0);
49 return 0;
50 }
51
52 do {
53 rem = unum % radix;
54 if (rem < 0xa)
55 num_buf[i] = '0' + rem;
56 else
57 num_buf[i] = 'a' + (rem - 0xa);
58 i++;
59 unum /= radix;
60 } while (unum > 0U);
61
62 if (padn > 0) {
63 while (i < padn) {
64 (void)putchar(padc);
65 count++;
66 padn--;
67 }
68 }
69
70 while (--i >= 0) {
71 (void)putchar(num_buf[i]);
72 count++;
73 }
74
75 return count;
76 }
77
78 /*******************************************************************
79 * Reduced format print for Trusted firmware.
80 * The following type specifiers are supported by this print
81 * %x - hexadecimal format
82 * %s - string format
83 * %d or %i - signed decimal format
84 * %u - unsigned decimal format
85 * %p - pointer format
86 *
87 * The following length specifiers are supported by this print
88 * %l - long int (64-bit on AArch64)
89 * %ll - long long int (64-bit on AArch64)
90 * %z - size_t sized integer formats (64 bit on AArch64)
91 *
92 * The following padding specifiers are supported by this print
93 * %0NN - Left-pad the number with 0s (NN is a decimal number)
94 *
95 * The print exits on all other formats specifiers other than valid
96 * combinations of the above specifiers.
97 *******************************************************************/
vprintf(const char * fmt,va_list args)98 int vprintf(const char *fmt, va_list args)
99 {
100 int l_count;
101 long long int num;
102 unsigned long long int unum;
103 char *str;
104 char padc = '\0'; /* Padding character */
105 int padn; /* Number of characters to pad */
106 int count = 0; /* Number of printed characters */
107
108 while (*fmt != '\0') {
109 l_count = 0;
110 padn = 0;
111
112 if (*fmt == '%') {
113 fmt++;
114 /* Check the format specifier */
115 loop:
116 switch (*fmt) {
117 case '%':
118 (void)putchar('%');
119 break;
120 case 'i': /* Fall through to next one */
121 case 'd':
122 num = get_num_va_args(args, l_count);
123 if (num < 0) {
124 (void)putchar('-');
125 unum = (unsigned long long int)-num;
126 padn--;
127 } else
128 unum = (unsigned long long int)num;
129
130 count += unsigned_num_print(unum, 10,
131 padc, padn);
132 break;
133 case 's':
134 str = va_arg(args, char *);
135 count += string_print(str);
136 break;
137 case 'p':
138 unum = (uintptr_t)va_arg(args, void *);
139 if (unum > 0U) {
140 count += string_print("0x");
141 padn -= 2;
142 }
143
144 count += unsigned_num_print(unum, 16,
145 padc, padn);
146 break;
147 case 'x':
148 unum = get_unum_va_args(args, l_count);
149 count += unsigned_num_print(unum, 16,
150 padc, padn);
151 break;
152 case 'z':
153 if (sizeof(size_t) == 8U)
154 l_count = 2;
155
156 fmt++;
157 goto loop;
158 case 'l':
159 l_count++;
160 fmt++;
161 goto loop;
162 case 'u':
163 unum = get_unum_va_args(args, l_count);
164 count += unsigned_num_print(unum, 10,
165 padc, padn);
166 break;
167 case '0':
168 padc = '0';
169 padn = 0;
170 fmt++;
171
172 for (;;) {
173 char ch = *fmt;
174 if ((ch < '0') || (ch > '9')) {
175 goto loop;
176 }
177 padn = (padn * 10) + (ch - '0');
178 fmt++;
179 }
180 assert(0); /* Unreachable */
181 default:
182 /* Exit on any other format specifier */
183 return -1;
184 }
185 fmt++;
186 continue;
187 }
188 (void)putchar(*fmt);
189 fmt++;
190 count++;
191 }
192
193 return count;
194 }
195
printf(const char * fmt,...)196 int printf(const char *fmt, ...)
197 {
198 int count;
199 va_list va;
200
201 va_start(va, fmt);
202 count = vprintf(fmt, va);
203 va_end(va);
204
205 return count;
206 }
207