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