2 * This file is part of the coreboot project.
4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * vtxprintf.c, originally from linux/lib/vsprintf.c
18 #include <console/vtxprintf.h>
21 #define call_tx(x) tx_byte(x, data)
23 #if !IS_ENABLED(CONFIG_ARCH_MIPS)
24 #define SUPPORT_64BIT_INTS
27 /* haha, don't need ctype.c */
28 #define isdigit(c) ((c) >= '0' && (c) <= '9')
29 #define is_digit isdigit
30 #define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
32 static int skip_atoi(const char **s
)
37 i
= i
*10 + *((*s
)++) - '0';
41 #define ZEROPAD 1 /* pad with zero */
42 #define SIGN 2 /* unsigned/signed long */
43 #define PLUS 4 /* show plus */
44 #define SPACE 8 /* space if plus */
45 #define LEFT 16 /* left justified */
46 #define SPECIAL 32 /* 0x */
47 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
49 static int number(void (*tx_byte
)(unsigned char byte
, void *data
),
50 unsigned long long inum
, int base
, int size
, int precision
, int type
,
54 const char *digits
="0123456789abcdefghijklmnopqrstuvwxyz";
57 #ifdef SUPPORT_64BIT_INTS
58 unsigned long long num
= inum
;
60 unsigned long num
= (long)inum
;
63 /* Alert user to an incorrect result by printing #^!. */
71 digits
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
74 if (base
< 2 || base
> 36)
76 c
= (type
& ZEROPAD
) ? '0' : ' ';
79 if ((signed long long)num
< 0) {
83 } else if (type
& PLUS
) {
86 } else if (type
& SPACE
) {
100 else while (num
!= 0){
101 tmp
[i
++] = digits
[num
% base
];
107 if (!(type
&(ZEROPAD
+LEFT
)))
109 call_tx(' '), count
++;
111 call_tx(sign
), count
++;
112 if (type
& SPECIAL
) {
114 call_tx('0'), count
++;
115 else if (base
== 16) {
116 call_tx('0'), count
++;
117 call_tx(digits
[33]), count
++;
123 while (i
< precision
--)
124 call_tx('0'), count
++;
126 call_tx(tmp
[i
]), count
++;
128 call_tx(' '), count
++;
133 int vtxprintf(void (*tx_byte
)(unsigned char byte
, void *data
),
134 const char *fmt
, va_list args
, void *data
)
137 unsigned long long num
;
141 int flags
; /* flags to number() */
143 int field_width
; /* width of output field */
144 int precision
; /* min. # of digits for integers; max
145 number of chars for from string */
146 int qualifier
; /* 'h', 'H', 'l', or 'L' for integer fields */
150 for (count
=0; *fmt
; ++fmt
) {
152 call_tx(*fmt
), count
++;
159 ++fmt
; /* this also skips first '%' */
161 case '-': flags
|= LEFT
; goto repeat
;
162 case '+': flags
|= PLUS
; goto repeat
;
163 case ' ': flags
|= SPACE
; goto repeat
;
164 case '#': flags
|= SPECIAL
; goto repeat
;
165 case '0': flags
|= ZEROPAD
; goto repeat
;
168 /* get field width */
171 field_width
= skip_atoi(&fmt
);
172 else if (*fmt
== '*') {
174 /* it's the next argument */
175 field_width
= va_arg(args
, int);
176 if (field_width
< 0) {
177 field_width
= -field_width
;
182 /* get the precision */
187 precision
= skip_atoi(&fmt
);
188 else if (*fmt
== '*') {
190 /* it's the next argument */
191 precision
= va_arg(args
, int);
197 /* get the conversion qualifier */
199 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' || *fmt
== 'z') {
218 while (--field_width
> 0)
219 call_tx(' '), count
++;
220 call_tx((unsigned char) va_arg(args
, int)), count
++;
221 while (--field_width
> 0)
222 call_tx(' '), count
++;
226 s
= va_arg(args
, char *);
230 len
= strnlen(s
, (size_t)precision
);
233 while (len
< field_width
--)
234 call_tx(' '), count
++;
235 for (i
= 0; i
< len
; ++i
)
236 call_tx(*s
++), count
++;
237 while (len
< field_width
--)
238 call_tx(' '), count
++;
242 if (field_width
== -1) {
243 field_width
= 2*sizeof(void *);
246 count
+= number(tx_byte
,
247 (unsigned long) va_arg(args
, void *), 16,
248 field_width
, precision
, flags
, data
);
252 if (qualifier
== 'L') {
253 long long *ip
= va_arg(args
, long long *);
255 } else if (qualifier
== 'l') {
256 long * ip
= va_arg(args
, long *);
259 int * ip
= va_arg(args
, int *);
265 call_tx('%'), count
++;
268 /* integer number formats - set up the flags and "break" */
286 call_tx('%'), count
++;
288 call_tx(*fmt
), count
++;
293 if (qualifier
== 'L') {
294 num
= va_arg(args
, unsigned long long);
295 } else if (qualifier
== 'l') {
296 num
= va_arg(args
, unsigned long);
297 } else if (qualifier
== 'z') {
298 num
= va_arg(args
, size_t);
299 } else if (qualifier
== 'h') {
300 num
= (unsigned short) va_arg(args
, int);
303 } else if (qualifier
== 'H') {
304 num
= (unsigned char) va_arg(args
, int);
306 num
= (signed char) num
;
307 } else if (flags
& SIGN
) {
308 num
= va_arg(args
, int);
310 num
= va_arg(args
, unsigned int);
312 count
+= number(tx_byte
, num
, base
, field_width
, precision
, flags
, data
);