blob: 60203fb3282a9cfe689e58bc663aa52210e9cb37 [file] [log] [blame]
Ambroise Vincent4128f9f2019-02-11 13:34:41 +00001/*
Ambroise Vincent8a573de2019-02-11 13:54:30 +00002 * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
Ambroise Vincent4128f9f2019-02-11 13:34:41 +00003 *
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
Ambroise Vincent8a573de2019-02-11 13:54:30 +000024static int string_print(const char *str, char padc, int padn)
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000025{
Ambroise Vincent8a573de2019-02-11 13:54:30 +000026 int i = 0, count = 0;
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000027
28 assert(str != NULL);
29
Ambroise Vincent8a573de2019-02-11 13:54:30 +000030 while (str[i] != '\0')
31 i++;
32
33 if (padn > 0) {
34 while (i < padn) {
35 (void)putchar(padc);
36 count++;
37 padn--;
38 }
39 }
40
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000041 for ( ; *str != '\0'; str++) {
42 (void)putchar(*str);
43 count++;
44 }
45
Ambroise Vincent8a573de2019-02-11 13:54:30 +000046 if (padn < 0) {
47 while (i < -padn) {
48 (void)putchar(padc);
49 count++;
50 padn++;
51 }
52 }
53
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000054 return count;
55}
56
57static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
58 char padc, int padn)
59{
60 /* Just need enough space to store 64 bit decimal integer */
61 char num_buf[20];
62 int i = 0, count = 0;
Ambroise Vincent8a573de2019-02-11 13:54:30 +000063 int width;
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000064 unsigned int rem;
65
66 do {
67 rem = unum % radix;
68 if (rem < 0xa)
69 num_buf[i] = '0' + rem;
70 else
71 num_buf[i] = 'a' + (rem - 0xa);
72 i++;
73 unum /= radix;
74 } while (unum > 0U);
75
Ambroise Vincent8a573de2019-02-11 13:54:30 +000076 width = i;
77
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000078 if (padn > 0) {
Ambroise Vincent8a573de2019-02-11 13:54:30 +000079 while (width < padn) {
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000080 (void)putchar(padc);
81 count++;
82 padn--;
83 }
84 }
85
86 while (--i >= 0) {
87 (void)putchar(num_buf[i]);
88 count++;
89 }
90
Ambroise Vincent8a573de2019-02-11 13:54:30 +000091 if (padn < 0) {
92 while (width < -padn) {
93 (void)putchar(padc);
94 count++;
95 padn++;
96 }
97 }
98
Ambroise Vincent4128f9f2019-02-11 13:34:41 +000099 return count;
100}
101
102/*******************************************************************
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000103 * Simplified version of printf() with smaller memory footprint.
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000104 * The following type specifiers are supported by this print
105 * %x - hexadecimal format
106 * %s - string format
107 * %d or %i - signed decimal format
108 * %u - unsigned decimal format
109 * %p - pointer format
110 *
111 * The following length specifiers are supported by this print
112 * %l - long int (64-bit on AArch64)
113 * %ll - long long int (64-bit on AArch64)
114 * %z - size_t sized integer formats (64 bit on AArch64)
115 *
116 * The following padding specifiers are supported by this print
117 * %0NN - Left-pad the number with 0s (NN is a decimal number)
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000118 * %NN - Left-pad the number or string with spaces (NN is a decimal number)
119 * %-NN - Right-pad the number or string with spaces (NN is a decimal number)
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000120 *
121 * The print exits on all other formats specifiers other than valid
122 * combinations of the above specifiers.
123 *******************************************************************/
124int vprintf(const char *fmt, va_list args)
125{
126 int l_count;
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000127 int left;
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000128 long long int num;
129 unsigned long long int unum;
130 char *str;
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000131 char padc; /* Padding character */
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000132 int padn; /* Number of characters to pad */
133 int count = 0; /* Number of printed characters */
134
135 while (*fmt != '\0') {
136 l_count = 0;
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000137 left = 0;
138 padc = '\0';
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000139 padn = 0;
140
141 if (*fmt == '%') {
142 fmt++;
143 /* Check the format specifier */
144loop:
145 switch (*fmt) {
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000146 case '1':
147 case '2':
148 case '3':
149 case '4':
150 case '5':
151 case '6':
152 case '7':
153 case '8':
154 case '9':
155 padc = ' ';
156 for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++)
157 padn = (padn * 10) + (*fmt - '0');
158 if (left)
159 padn = -padn;
160 goto loop;
161 case '-':
162 left = 1;
163 fmt++;
164 goto loop;
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000165 case 'i': /* Fall through to next one */
166 case 'd':
167 num = get_num_va_args(args, l_count);
168 if (num < 0) {
169 (void)putchar('-');
170 unum = (unsigned long long int)-num;
171 padn--;
172 } else
173 unum = (unsigned long long int)num;
174
175 count += unsigned_num_print(unum, 10,
176 padc, padn);
177 break;
178 case 's':
179 str = va_arg(args, char *);
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000180 count += string_print(str, padc, padn);
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000181 break;
182 case 'p':
183 unum = (uintptr_t)va_arg(args, void *);
184 if (unum > 0U) {
Ambroise Vincent8a573de2019-02-11 13:54:30 +0000185 count += string_print("0x", padc, 0);
Ambroise Vincent4128f9f2019-02-11 13:34:41 +0000186 padn -= 2;
187 }
188
189 count += unsigned_num_print(unum, 16,
190 padc, padn);
191 break;
192 case 'x':
193 unum = get_unum_va_args(args, l_count);
194 count += unsigned_num_print(unum, 16,
195 padc, padn);
196 break;
197 case 'z':
198 if (sizeof(size_t) == 8U)
199 l_count = 2;
200
201 fmt++;
202 goto loop;
203 case 'l':
204 l_count++;
205 fmt++;
206 goto loop;
207 case 'u':
208 unum = get_unum_va_args(args, l_count);
209 count += unsigned_num_print(unum, 10,
210 padc, padn);
211 break;
212 case '0':
213 padc = '0';
214 padn = 0;
215 fmt++;
216
217 for (;;) {
218 char ch = *fmt;
219 if ((ch < '0') || (ch > '9')) {
220 goto loop;
221 }
222 padn = (padn * 10) + (ch - '0');
223 fmt++;
224 }
225 assert(0); /* Unreachable */
226 default:
227 /* Exit on any other format specifier */
228 return -1;
229 }
230 fmt++;
231 continue;
232 }
233 (void)putchar(*fmt);
234 fmt++;
235 count++;
236 }
237
238 return count;
239}
240
241int printf(const char *fmt, ...)
242{
243 int count;
244 va_list va;
245
246 va_start(va, fmt);
247 count = vprintf(fmt, va);
248 va_end(va);
249
250 return count;
251}