1 /* SPDX-License-Identifier: GPL-2.0-only */
4 * vtxprintf.c, originally from linux/lib/vsprintf.c
7 #include <console/vtxprintf.h>
12 #define call_tx(x) tx_byte(x, data)
14 #define ZEROPAD 1 /* pad with zero */
15 #define SIGN 2 /* unsigned/signed long */
16 #define PLUS 4 /* show plus */
17 #define SPACE 8 /* space if plus */
18 #define LEFT 16 /* left justified */
19 #define SPECIAL 32 /* 0x */
20 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
22 static int number(void (*tx_byte
)(unsigned char byte
, void *data
),
23 unsigned long long inum
, int base
, int size
, int precision
, int type
,
26 char c
, sign
, tmp
[66];
27 const char *digits
= "0123456789abcdef";
30 unsigned long long num
= inum
;
34 digits
= "0123456789ABCDEF";
37 c
= (type
& ZEROPAD
) ? '0' : ' ';
44 } else if (type
& PLUS
) {
47 } else if (type
& SPACE
) {
63 tmp
[i
++] = digits
[num
% base
];
71 if (!(type
&(ZEROPAD
+LEFT
))) {
73 call_tx(' '), count
++;
76 call_tx(sign
), count
++;
80 call_tx('0'), count
++;
81 else if (base
== 16) {
82 call_tx('0'), count
++;
84 call_tx('X'), count
++;
86 call_tx('x'), count
++;
93 while (i
< precision
--)
94 call_tx('0'), count
++;
96 call_tx(tmp
[i
]), count
++;
98 call_tx(' '), count
++;
103 int vtxprintf(void (*tx_byte
)(unsigned char byte
, void *data
),
104 const char *fmt
, va_list args
, void *data
)
107 unsigned long long num
;
111 int flags
; /* flags to number() */
113 int field_width
; /* width of output field */
114 int precision
; /* min. # of digits for integers; max
115 number of chars for from string */
116 int qualifier
; /* 'h', 'H', 'l', 'L', 'z', or 'j' for integer fields */
120 for (count
= 0; *fmt
; ++fmt
) {
122 call_tx(*fmt
), count
++;
129 ++fmt
; /* this also skips first '%' */
131 case '-': flags
|= LEFT
; goto repeat
;
132 case '+': flags
|= PLUS
; goto repeat
;
133 case ' ': flags
|= SPACE
; goto repeat
;
134 case '#': flags
|= SPECIAL
; goto repeat
;
135 case '0': flags
|= ZEROPAD
; goto repeat
;
138 /* get field width */
141 field_width
= skip_atoi((char **)&fmt
);
142 } else if (*fmt
== '*') {
144 /* it's the next argument */
145 field_width
= va_arg(args
, int);
146 if (field_width
< 0) {
147 field_width
= -field_width
;
152 /* get the precision */
157 precision
= skip_atoi((char **)&fmt
);
158 } else if (*fmt
== '*') {
160 /* it's the next argument */
161 precision
= va_arg(args
, int);
168 /* get the conversion qualifier */
170 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' || *fmt
== 'z' || *fmt
== 'j') {
189 while (--field_width
> 0)
190 call_tx(' '), count
++;
191 call_tx((unsigned char) va_arg(args
, int)), count
++;
192 while (--field_width
> 0)
193 call_tx(' '), count
++;
197 s
= va_arg(args
, char *);
201 len
= strnlen(s
, (size_t)precision
);
203 if (!(flags
& LEFT
)) {
204 while (len
< field_width
--)
205 call_tx(' '), count
++;
207 for (i
= 0; i
< len
; ++i
)
208 call_tx(*s
++), count
++;
209 while (len
< field_width
--)
210 call_tx(' '), count
++;
214 /* even on 64-bit systems, coreboot only resides in the
215 low 4GB so pad pointers to 32-bit for readability. */
216 if (field_width
== -1 && precision
== -1)
217 precision
= 2*sizeof(uint32_t);
219 count
+= number(tx_byte
,
220 (unsigned long) va_arg(args
, void *), 16,
221 field_width
, precision
, flags
, data
);
225 if (qualifier
== 'L') {
226 long long *ip
= va_arg(args
, long long *);
228 } else if (qualifier
== 'l') {
229 long *ip
= va_arg(args
, long *);
232 int *ip
= va_arg(args
, int *);
238 call_tx('%'), count
++;
241 /* integer number formats - set up the flags and "break" */
260 call_tx('%'), count
++;
262 call_tx(*fmt
), count
++;
267 if (qualifier
== 'L') {
268 num
= va_arg(args
, unsigned long long);
269 } else if (qualifier
== 'l') {
270 num
= va_arg(args
, unsigned long);
271 } else if (qualifier
== 'z') {
272 num
= va_arg(args
, size_t);
273 } else if (qualifier
== 'j') {
274 num
= va_arg(args
, uintmax_t);
275 } else if (qualifier
== 'h') {
276 num
= (unsigned short) va_arg(args
, int);
279 } else if (qualifier
== 'H') {
280 num
= (unsigned char) va_arg(args
, int);
282 num
= (signed char) num
;
283 } else if (flags
& SIGN
) {
284 num
= va_arg(args
, int);
286 num
= va_arg(args
, unsigned int);
288 count
+= number(tx_byte
, num
, base
, field_width
, precision
, flags
, data
);