xref: /openbmc/linux/arch/x86/boot/printf.c (revision 96ae6ea0be1b902c28b3b463c27da42b41e2b63a)
1*96ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
2*96ae6ea0SThomas Gleixner  *
3*96ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
4*96ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5*96ae6ea0SThomas Gleixner  *
6*96ae6ea0SThomas Gleixner  *   This file is part of the Linux kernel, and is made available under
7*96ae6ea0SThomas Gleixner  *   the terms of the GNU General Public License version 2.
8*96ae6ea0SThomas Gleixner  *
9*96ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
10*96ae6ea0SThomas Gleixner 
11*96ae6ea0SThomas Gleixner /*
12*96ae6ea0SThomas Gleixner  * arch/i386/boot/printf.c
13*96ae6ea0SThomas Gleixner  *
14*96ae6ea0SThomas Gleixner  * Oh, it's a waste of space, but oh-so-yummy for debugging.  This
15*96ae6ea0SThomas Gleixner  * version of printf() does not include 64-bit support.  "Live with
16*96ae6ea0SThomas Gleixner  * it."
17*96ae6ea0SThomas Gleixner  *
18*96ae6ea0SThomas Gleixner  */
19*96ae6ea0SThomas Gleixner 
20*96ae6ea0SThomas Gleixner #include "boot.h"
21*96ae6ea0SThomas Gleixner 
22*96ae6ea0SThomas Gleixner static int skip_atoi(const char **s)
23*96ae6ea0SThomas Gleixner {
24*96ae6ea0SThomas Gleixner 	int i = 0;
25*96ae6ea0SThomas Gleixner 
26*96ae6ea0SThomas Gleixner 	while (isdigit(**s))
27*96ae6ea0SThomas Gleixner 		i = i * 10 + *((*s)++) - '0';
28*96ae6ea0SThomas Gleixner 	return i;
29*96ae6ea0SThomas Gleixner }
30*96ae6ea0SThomas Gleixner 
31*96ae6ea0SThomas Gleixner #define ZEROPAD	1		/* pad with zero */
32*96ae6ea0SThomas Gleixner #define SIGN	2		/* unsigned/signed long */
33*96ae6ea0SThomas Gleixner #define PLUS	4		/* show plus */
34*96ae6ea0SThomas Gleixner #define SPACE	8		/* space if plus */
35*96ae6ea0SThomas Gleixner #define LEFT	16		/* left justified */
36*96ae6ea0SThomas Gleixner #define SPECIAL	32		/* 0x */
37*96ae6ea0SThomas Gleixner #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
38*96ae6ea0SThomas Gleixner 
39*96ae6ea0SThomas Gleixner #define do_div(n,base) ({ \
40*96ae6ea0SThomas Gleixner int __res; \
41*96ae6ea0SThomas Gleixner __res = ((unsigned long) n) % (unsigned) base; \
42*96ae6ea0SThomas Gleixner n = ((unsigned long) n) / (unsigned) base; \
43*96ae6ea0SThomas Gleixner __res; })
44*96ae6ea0SThomas Gleixner 
45*96ae6ea0SThomas Gleixner static char *number(char *str, long num, int base, int size, int precision,
46*96ae6ea0SThomas Gleixner 		    int type)
47*96ae6ea0SThomas Gleixner {
48*96ae6ea0SThomas Gleixner 	char c, sign, tmp[66];
49*96ae6ea0SThomas Gleixner 	const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
50*96ae6ea0SThomas Gleixner 	int i;
51*96ae6ea0SThomas Gleixner 
52*96ae6ea0SThomas Gleixner 	if (type & LARGE)
53*96ae6ea0SThomas Gleixner 		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
54*96ae6ea0SThomas Gleixner 	if (type & LEFT)
55*96ae6ea0SThomas Gleixner 		type &= ~ZEROPAD;
56*96ae6ea0SThomas Gleixner 	if (base < 2 || base > 36)
57*96ae6ea0SThomas Gleixner 		return 0;
58*96ae6ea0SThomas Gleixner 	c = (type & ZEROPAD) ? '0' : ' ';
59*96ae6ea0SThomas Gleixner 	sign = 0;
60*96ae6ea0SThomas Gleixner 	if (type & SIGN) {
61*96ae6ea0SThomas Gleixner 		if (num < 0) {
62*96ae6ea0SThomas Gleixner 			sign = '-';
63*96ae6ea0SThomas Gleixner 			num = -num;
64*96ae6ea0SThomas Gleixner 			size--;
65*96ae6ea0SThomas Gleixner 		} else if (type & PLUS) {
66*96ae6ea0SThomas Gleixner 			sign = '+';
67*96ae6ea0SThomas Gleixner 			size--;
68*96ae6ea0SThomas Gleixner 		} else if (type & SPACE) {
69*96ae6ea0SThomas Gleixner 			sign = ' ';
70*96ae6ea0SThomas Gleixner 			size--;
71*96ae6ea0SThomas Gleixner 		}
72*96ae6ea0SThomas Gleixner 	}
73*96ae6ea0SThomas Gleixner 	if (type & SPECIAL) {
74*96ae6ea0SThomas Gleixner 		if (base == 16)
75*96ae6ea0SThomas Gleixner 			size -= 2;
76*96ae6ea0SThomas Gleixner 		else if (base == 8)
77*96ae6ea0SThomas Gleixner 			size--;
78*96ae6ea0SThomas Gleixner 	}
79*96ae6ea0SThomas Gleixner 	i = 0;
80*96ae6ea0SThomas Gleixner 	if (num == 0)
81*96ae6ea0SThomas Gleixner 		tmp[i++] = '0';
82*96ae6ea0SThomas Gleixner 	else
83*96ae6ea0SThomas Gleixner 		while (num != 0)
84*96ae6ea0SThomas Gleixner 			tmp[i++] = digits[do_div(num, base)];
85*96ae6ea0SThomas Gleixner 	if (i > precision)
86*96ae6ea0SThomas Gleixner 		precision = i;
87*96ae6ea0SThomas Gleixner 	size -= precision;
88*96ae6ea0SThomas Gleixner 	if (!(type & (ZEROPAD + LEFT)))
89*96ae6ea0SThomas Gleixner 		while (size-- > 0)
90*96ae6ea0SThomas Gleixner 			*str++ = ' ';
91*96ae6ea0SThomas Gleixner 	if (sign)
92*96ae6ea0SThomas Gleixner 		*str++ = sign;
93*96ae6ea0SThomas Gleixner 	if (type & SPECIAL) {
94*96ae6ea0SThomas Gleixner 		if (base == 8)
95*96ae6ea0SThomas Gleixner 			*str++ = '0';
96*96ae6ea0SThomas Gleixner 		else if (base == 16) {
97*96ae6ea0SThomas Gleixner 			*str++ = '0';
98*96ae6ea0SThomas Gleixner 			*str++ = digits[33];
99*96ae6ea0SThomas Gleixner 		}
100*96ae6ea0SThomas Gleixner 	}
101*96ae6ea0SThomas Gleixner 	if (!(type & LEFT))
102*96ae6ea0SThomas Gleixner 		while (size-- > 0)
103*96ae6ea0SThomas Gleixner 			*str++ = c;
104*96ae6ea0SThomas Gleixner 	while (i < precision--)
105*96ae6ea0SThomas Gleixner 		*str++ = '0';
106*96ae6ea0SThomas Gleixner 	while (i-- > 0)
107*96ae6ea0SThomas Gleixner 		*str++ = tmp[i];
108*96ae6ea0SThomas Gleixner 	while (size-- > 0)
109*96ae6ea0SThomas Gleixner 		*str++ = ' ';
110*96ae6ea0SThomas Gleixner 	return str;
111*96ae6ea0SThomas Gleixner }
112*96ae6ea0SThomas Gleixner 
113*96ae6ea0SThomas Gleixner int vsprintf(char *buf, const char *fmt, va_list args)
114*96ae6ea0SThomas Gleixner {
115*96ae6ea0SThomas Gleixner 	int len;
116*96ae6ea0SThomas Gleixner 	unsigned long num;
117*96ae6ea0SThomas Gleixner 	int i, base;
118*96ae6ea0SThomas Gleixner 	char *str;
119*96ae6ea0SThomas Gleixner 	const char *s;
120*96ae6ea0SThomas Gleixner 
121*96ae6ea0SThomas Gleixner 	int flags;		/* flags to number() */
122*96ae6ea0SThomas Gleixner 
123*96ae6ea0SThomas Gleixner 	int field_width;	/* width of output field */
124*96ae6ea0SThomas Gleixner 	int precision;		/* min. # of digits for integers; max
125*96ae6ea0SThomas Gleixner 				   number of chars for from string */
126*96ae6ea0SThomas Gleixner 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
127*96ae6ea0SThomas Gleixner 
128*96ae6ea0SThomas Gleixner 	for (str = buf; *fmt; ++fmt) {
129*96ae6ea0SThomas Gleixner 		if (*fmt != '%') {
130*96ae6ea0SThomas Gleixner 			*str++ = *fmt;
131*96ae6ea0SThomas Gleixner 			continue;
132*96ae6ea0SThomas Gleixner 		}
133*96ae6ea0SThomas Gleixner 
134*96ae6ea0SThomas Gleixner 		/* process flags */
135*96ae6ea0SThomas Gleixner 		flags = 0;
136*96ae6ea0SThomas Gleixner 	      repeat:
137*96ae6ea0SThomas Gleixner 		++fmt;		/* this also skips first '%' */
138*96ae6ea0SThomas Gleixner 		switch (*fmt) {
139*96ae6ea0SThomas Gleixner 		case '-':
140*96ae6ea0SThomas Gleixner 			flags |= LEFT;
141*96ae6ea0SThomas Gleixner 			goto repeat;
142*96ae6ea0SThomas Gleixner 		case '+':
143*96ae6ea0SThomas Gleixner 			flags |= PLUS;
144*96ae6ea0SThomas Gleixner 			goto repeat;
145*96ae6ea0SThomas Gleixner 		case ' ':
146*96ae6ea0SThomas Gleixner 			flags |= SPACE;
147*96ae6ea0SThomas Gleixner 			goto repeat;
148*96ae6ea0SThomas Gleixner 		case '#':
149*96ae6ea0SThomas Gleixner 			flags |= SPECIAL;
150*96ae6ea0SThomas Gleixner 			goto repeat;
151*96ae6ea0SThomas Gleixner 		case '0':
152*96ae6ea0SThomas Gleixner 			flags |= ZEROPAD;
153*96ae6ea0SThomas Gleixner 			goto repeat;
154*96ae6ea0SThomas Gleixner 		}
155*96ae6ea0SThomas Gleixner 
156*96ae6ea0SThomas Gleixner 		/* get field width */
157*96ae6ea0SThomas Gleixner 		field_width = -1;
158*96ae6ea0SThomas Gleixner 		if (isdigit(*fmt))
159*96ae6ea0SThomas Gleixner 			field_width = skip_atoi(&fmt);
160*96ae6ea0SThomas Gleixner 		else if (*fmt == '*') {
161*96ae6ea0SThomas Gleixner 			++fmt;
162*96ae6ea0SThomas Gleixner 			/* it's the next argument */
163*96ae6ea0SThomas Gleixner 			field_width = va_arg(args, int);
164*96ae6ea0SThomas Gleixner 			if (field_width < 0) {
165*96ae6ea0SThomas Gleixner 				field_width = -field_width;
166*96ae6ea0SThomas Gleixner 				flags |= LEFT;
167*96ae6ea0SThomas Gleixner 			}
168*96ae6ea0SThomas Gleixner 		}
169*96ae6ea0SThomas Gleixner 
170*96ae6ea0SThomas Gleixner 		/* get the precision */
171*96ae6ea0SThomas Gleixner 		precision = -1;
172*96ae6ea0SThomas Gleixner 		if (*fmt == '.') {
173*96ae6ea0SThomas Gleixner 			++fmt;
174*96ae6ea0SThomas Gleixner 			if (isdigit(*fmt))
175*96ae6ea0SThomas Gleixner 				precision = skip_atoi(&fmt);
176*96ae6ea0SThomas Gleixner 			else if (*fmt == '*') {
177*96ae6ea0SThomas Gleixner 				++fmt;
178*96ae6ea0SThomas Gleixner 				/* it's the next argument */
179*96ae6ea0SThomas Gleixner 				precision = va_arg(args, int);
180*96ae6ea0SThomas Gleixner 			}
181*96ae6ea0SThomas Gleixner 			if (precision < 0)
182*96ae6ea0SThomas Gleixner 				precision = 0;
183*96ae6ea0SThomas Gleixner 		}
184*96ae6ea0SThomas Gleixner 
185*96ae6ea0SThomas Gleixner 		/* get the conversion qualifier */
186*96ae6ea0SThomas Gleixner 		qualifier = -1;
187*96ae6ea0SThomas Gleixner 		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
188*96ae6ea0SThomas Gleixner 			qualifier = *fmt;
189*96ae6ea0SThomas Gleixner 			++fmt;
190*96ae6ea0SThomas Gleixner 		}
191*96ae6ea0SThomas Gleixner 
192*96ae6ea0SThomas Gleixner 		/* default base */
193*96ae6ea0SThomas Gleixner 		base = 10;
194*96ae6ea0SThomas Gleixner 
195*96ae6ea0SThomas Gleixner 		switch (*fmt) {
196*96ae6ea0SThomas Gleixner 		case 'c':
197*96ae6ea0SThomas Gleixner 			if (!(flags & LEFT))
198*96ae6ea0SThomas Gleixner 				while (--field_width > 0)
199*96ae6ea0SThomas Gleixner 					*str++ = ' ';
200*96ae6ea0SThomas Gleixner 			*str++ = (unsigned char)va_arg(args, int);
201*96ae6ea0SThomas Gleixner 			while (--field_width > 0)
202*96ae6ea0SThomas Gleixner 				*str++ = ' ';
203*96ae6ea0SThomas Gleixner 			continue;
204*96ae6ea0SThomas Gleixner 
205*96ae6ea0SThomas Gleixner 		case 's':
206*96ae6ea0SThomas Gleixner 			s = va_arg(args, char *);
207*96ae6ea0SThomas Gleixner 			len = strnlen(s, precision);
208*96ae6ea0SThomas Gleixner 
209*96ae6ea0SThomas Gleixner 			if (!(flags & LEFT))
210*96ae6ea0SThomas Gleixner 				while (len < field_width--)
211*96ae6ea0SThomas Gleixner 					*str++ = ' ';
212*96ae6ea0SThomas Gleixner 			for (i = 0; i < len; ++i)
213*96ae6ea0SThomas Gleixner 				*str++ = *s++;
214*96ae6ea0SThomas Gleixner 			while (len < field_width--)
215*96ae6ea0SThomas Gleixner 				*str++ = ' ';
216*96ae6ea0SThomas Gleixner 			continue;
217*96ae6ea0SThomas Gleixner 
218*96ae6ea0SThomas Gleixner 		case 'p':
219*96ae6ea0SThomas Gleixner 			if (field_width == -1) {
220*96ae6ea0SThomas Gleixner 				field_width = 2 * sizeof(void *);
221*96ae6ea0SThomas Gleixner 				flags |= ZEROPAD;
222*96ae6ea0SThomas Gleixner 			}
223*96ae6ea0SThomas Gleixner 			str = number(str,
224*96ae6ea0SThomas Gleixner 				     (unsigned long)va_arg(args, void *), 16,
225*96ae6ea0SThomas Gleixner 				     field_width, precision, flags);
226*96ae6ea0SThomas Gleixner 			continue;
227*96ae6ea0SThomas Gleixner 
228*96ae6ea0SThomas Gleixner 		case 'n':
229*96ae6ea0SThomas Gleixner 			if (qualifier == 'l') {
230*96ae6ea0SThomas Gleixner 				long *ip = va_arg(args, long *);
231*96ae6ea0SThomas Gleixner 				*ip = (str - buf);
232*96ae6ea0SThomas Gleixner 			} else {
233*96ae6ea0SThomas Gleixner 				int *ip = va_arg(args, int *);
234*96ae6ea0SThomas Gleixner 				*ip = (str - buf);
235*96ae6ea0SThomas Gleixner 			}
236*96ae6ea0SThomas Gleixner 			continue;
237*96ae6ea0SThomas Gleixner 
238*96ae6ea0SThomas Gleixner 		case '%':
239*96ae6ea0SThomas Gleixner 			*str++ = '%';
240*96ae6ea0SThomas Gleixner 			continue;
241*96ae6ea0SThomas Gleixner 
242*96ae6ea0SThomas Gleixner 			/* integer number formats - set up the flags and "break" */
243*96ae6ea0SThomas Gleixner 		case 'o':
244*96ae6ea0SThomas Gleixner 			base = 8;
245*96ae6ea0SThomas Gleixner 			break;
246*96ae6ea0SThomas Gleixner 
247*96ae6ea0SThomas Gleixner 		case 'X':
248*96ae6ea0SThomas Gleixner 			flags |= LARGE;
249*96ae6ea0SThomas Gleixner 		case 'x':
250*96ae6ea0SThomas Gleixner 			base = 16;
251*96ae6ea0SThomas Gleixner 			break;
252*96ae6ea0SThomas Gleixner 
253*96ae6ea0SThomas Gleixner 		case 'd':
254*96ae6ea0SThomas Gleixner 		case 'i':
255*96ae6ea0SThomas Gleixner 			flags |= SIGN;
256*96ae6ea0SThomas Gleixner 		case 'u':
257*96ae6ea0SThomas Gleixner 			break;
258*96ae6ea0SThomas Gleixner 
259*96ae6ea0SThomas Gleixner 		default:
260*96ae6ea0SThomas Gleixner 			*str++ = '%';
261*96ae6ea0SThomas Gleixner 			if (*fmt)
262*96ae6ea0SThomas Gleixner 				*str++ = *fmt;
263*96ae6ea0SThomas Gleixner 			else
264*96ae6ea0SThomas Gleixner 				--fmt;
265*96ae6ea0SThomas Gleixner 			continue;
266*96ae6ea0SThomas Gleixner 		}
267*96ae6ea0SThomas Gleixner 		if (qualifier == 'l')
268*96ae6ea0SThomas Gleixner 			num = va_arg(args, unsigned long);
269*96ae6ea0SThomas Gleixner 		else if (qualifier == 'h') {
270*96ae6ea0SThomas Gleixner 			num = (unsigned short)va_arg(args, int);
271*96ae6ea0SThomas Gleixner 			if (flags & SIGN)
272*96ae6ea0SThomas Gleixner 				num = (short)num;
273*96ae6ea0SThomas Gleixner 		} else if (flags & SIGN)
274*96ae6ea0SThomas Gleixner 			num = va_arg(args, int);
275*96ae6ea0SThomas Gleixner 		else
276*96ae6ea0SThomas Gleixner 			num = va_arg(args, unsigned int);
277*96ae6ea0SThomas Gleixner 		str = number(str, num, base, field_width, precision, flags);
278*96ae6ea0SThomas Gleixner 	}
279*96ae6ea0SThomas Gleixner 	*str = '\0';
280*96ae6ea0SThomas Gleixner 	return str - buf;
281*96ae6ea0SThomas Gleixner }
282*96ae6ea0SThomas Gleixner 
283*96ae6ea0SThomas Gleixner int sprintf(char *buf, const char *fmt, ...)
284*96ae6ea0SThomas Gleixner {
285*96ae6ea0SThomas Gleixner 	va_list args;
286*96ae6ea0SThomas Gleixner 	int i;
287*96ae6ea0SThomas Gleixner 
288*96ae6ea0SThomas Gleixner 	va_start(args, fmt);
289*96ae6ea0SThomas Gleixner 	i = vsprintf(buf, fmt, args);
290*96ae6ea0SThomas Gleixner 	va_end(args);
291*96ae6ea0SThomas Gleixner 	return i;
292*96ae6ea0SThomas Gleixner }
293*96ae6ea0SThomas Gleixner 
294*96ae6ea0SThomas Gleixner int printf(const char *fmt, ...)
295*96ae6ea0SThomas Gleixner {
296*96ae6ea0SThomas Gleixner 	char printf_buf[1024];
297*96ae6ea0SThomas Gleixner 	va_list args;
298*96ae6ea0SThomas Gleixner 	int printed;
299*96ae6ea0SThomas Gleixner 
300*96ae6ea0SThomas Gleixner 	va_start(args, fmt);
301*96ae6ea0SThomas Gleixner 	printed = vsprintf(printf_buf, fmt, args);
302*96ae6ea0SThomas Gleixner 	va_end(args);
303*96ae6ea0SThomas Gleixner 
304*96ae6ea0SThomas Gleixner 	puts(printf_buf);
305*96ae6ea0SThomas Gleixner 
306*96ae6ea0SThomas Gleixner 	return printed;
307*96ae6ea0SThomas Gleixner }
308