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