xref: /rk3399_ARM-atf/lib/libc/printf.c (revision 52e486f6a6192bd18d36cdcbc35c59092eefc810)
1 /*
2  * Copyright (c) 2014-2023, 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 
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 
38 static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
39 			      char padc, int padn, bool uppercase)
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 < 10U) {
48 		assert(0);
49 		return 0;
50 	}
51 
52 	do {
53 		rem = (uint32_t)(unum % radix);
54 		if (rem < 0xaU) {
55 			num_buf[i] = '0' + rem;
56 		} else if (uppercase) {
57 			num_buf[i] = 'A' + (rem - 0xaU);
58 		} else {
59 			num_buf[i] = 'a' + (rem - 0xaU);
60 		}
61 		i++;
62 		unum /= radix;
63 	} while (unum > 0U);
64 
65 	if (padn > 0) {
66 		while (i < padn) {
67 			(void)putchar((int32_t)padc);
68 			count++;
69 			padn--;
70 		}
71 	}
72 
73 	while (--i >= 0) {
74 		(void)putchar((int32_t)num_buf[i]);
75 		count++;
76 	}
77 
78 	return count;
79 }
80 
81 /*******************************************************************
82  * Reduced format print for Trusted firmware.
83  * The following type specifiers are supported by this print
84  * %x - hexadecimal format
85  * %s - string format
86  * %d or %i - signed decimal format
87  * %c - character format
88  * %u - unsigned decimal format
89  * %p - pointer format
90  *
91  * The following length specifiers are supported by this print
92  * %l - long int (64-bit on AArch64)
93  * %ll - long long int (64-bit on AArch64)
94  * %z - size_t sized integer formats (64 bit on AArch64)
95  *
96  * The following padding specifiers are supported by this print
97  * %0NN - Left-pad the number with 0s (NN is a decimal number)
98  * %NN - Left-pad the number with spaces (NN is a decimal number)
99  *
100  * The print exits on all other formats specifiers other than valid
101  * combinations of the above specifiers.
102  *******************************************************************/
103 int vprintf(const char *fmt, va_list args)
104 {
105 	int l_count;
106 	long long int num;
107 	unsigned long long int unum;
108 	const char *str;
109 	char padc = '\0'; /* Padding character */
110 	int padn; /* Number of characters to pad */
111 	int count = 0; /* Number of printed characters */
112 	bool uppercase; /* Print characters in uppercase */
113 
114 	while (*fmt != '\0') {
115 		uppercase = false;
116 		l_count = 0;
117 		padn = 0;
118 
119 		if (*fmt == '%') {
120 			fmt++;
121 			/* Check the format specifier */
122 loop:
123 			switch (*fmt) {
124 			case '%':
125 				(void)putchar((int32_t)'%');
126 				break;
127 			case 'i': /* Fall through to next one */
128 			case 'd':
129 				num = get_num_va_args(args, l_count);
130 				if (num < 0) {
131 					(void)putchar((int32_t)'-');
132 					unum = (unsigned long long int)-num;
133 					padn--;
134 				} else {
135 					unum = (unsigned long long int)num;
136 				}
137 
138 				count += unsigned_num_print(unum, 10,
139 							    padc, padn, uppercase);
140 				break;
141 			case 'c':
142 				(void)putchar(va_arg(args, int));
143 				count++;
144 				break;
145 			case 's':
146 				str = va_arg(args, const char *);
147 				count += string_print(str);
148 				break;
149 			case 'p':
150 				unum = (uintptr_t)va_arg(args, void *);
151 				if (unum > 0U) {
152 					count += string_print("0x");
153 					padn -= 2;
154 				}
155 
156 				count += unsigned_num_print(unum, 16,
157 							    padc, padn, uppercase);
158 				break;
159 			case 'X':
160 				uppercase = true;
161 				// fall through
162 			case 'x':
163 				unum = get_unum_va_args(args, l_count);
164 				count += unsigned_num_print(unum, 16,
165 							    padc, padn, uppercase);
166 				break;
167 			case 'z':
168 				if (sizeof(size_t) == 8U) {
169 					l_count = 2;
170 				}
171 
172 				fmt++;
173 				goto loop;
174 			case 'l':
175 				l_count++;
176 				fmt++;
177 				goto loop;
178 			case 'u':
179 				unum = get_unum_va_args(args, l_count);
180 				count += unsigned_num_print(unum, 10,
181 							    padc, padn, uppercase);
182 				break;
183 			case '0':
184 				padc = '0';
185 				padn = 0;
186 				fmt++;
187 
188 				for (;;) {
189 					char ch = *fmt;
190 					if ((ch < '0') || (ch > '9')) {
191 						goto loop;
192 					}
193 					padn = (padn * 10) + (ch - '0');
194 					fmt++;
195 				}
196 				assert(0); /* Unreachable */
197 			case '1':
198 			case '2':
199 			case '3':
200 			case '4':
201 			case '5':
202 			case '6':
203 			case '7':
204 			case '8':
205 			case '9':
206 				padc = ' ';
207 				padn = 0;
208 
209 				for (;;) {
210 					char ch = *fmt;
211 					if ((ch < '0') || (ch > '9')) {
212 						goto loop;
213 					}
214 					padn = (padn * 10) + (ch - '0');
215 					fmt++;
216 				}
217 				assert(0); /* Unreachable */
218 			default:
219 				/* Exit on any other format specifier */
220 				return -1;
221 			}
222 			fmt++;
223 			continue;
224 		}
225 		(void)putchar(*fmt);
226 		fmt++;
227 		count++;
228 	}
229 
230 	return count;
231 }
232 
233 int printf(const char *fmt, ...)
234 {
235 	int count;
236 	va_list va;
237 
238 	va_start(va, fmt);
239 	count = vprintf(fmt, va);
240 	va_end(va);
241 
242 	return count;
243 }
244