xref: /openbmc/u-boot/lib/tiny-printf.c (revision 135aa950)
1 /*
2  * Tiny printf version for SPL
3  *
4  * Copied from:
5  * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
6  *
7  * Copyright (C) 2004,2008  Kustaa Nyholm
8  *
9  * SPDX-License-Identifier:	LGPL-2.1+
10  */
11 
12 #include <common.h>
13 #include <stdarg.h>
14 #include <serial.h>
15 
16 static char *bf;
17 static char zs;
18 
19 /* Current position in sprintf() output string */
20 static char *outstr;
21 
22 static void out(char c)
23 {
24 	*bf++ = c;
25 }
26 
27 static void out_dgt(char dgt)
28 {
29 	out(dgt + (dgt < 10 ? '0' : 'a' - 10));
30 	zs = 1;
31 }
32 
33 static void div_out(unsigned int *num, unsigned int div)
34 {
35 	unsigned char dgt = 0;
36 
37 	while (*num >= div) {
38 		*num -= div;
39 		dgt++;
40 	}
41 
42 	if (zs || dgt > 0)
43 		out_dgt(dgt);
44 }
45 
46 int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
47 {
48 	char ch;
49 	char *p;
50 	unsigned int num;
51 	char buf[12];
52 	unsigned int div;
53 
54 	while ((ch = *(fmt++))) {
55 		if (ch != '%') {
56 			putc(ch);
57 		} else {
58 			bool lz = false;
59 			int width = 0;
60 
61 			ch = *(fmt++);
62 			if (ch == '0') {
63 				ch = *(fmt++);
64 				lz = 1;
65 			}
66 
67 			if (ch >= '0' && ch <= '9') {
68 				width = 0;
69 				while (ch >= '0' && ch <= '9') {
70 					width = (width * 10) + ch - '0';
71 					ch = *fmt++;
72 				}
73 			}
74 			bf = buf;
75 			p = bf;
76 			zs = 0;
77 
78 			switch (ch) {
79 			case '\0':
80 				goto abort;
81 			case 'u':
82 			case 'd':
83 				num = va_arg(va, unsigned int);
84 				if (ch == 'd' && (int)num < 0) {
85 					num = -(int)num;
86 					out('-');
87 				}
88 				if (!num) {
89 					out_dgt(0);
90 				} else {
91 					for (div = 1000000000; div; div /= 10)
92 						div_out(&num, div);
93 				}
94 				break;
95 			case 'x':
96 				num = va_arg(va, unsigned int);
97 				if (!num) {
98 					out_dgt(0);
99 				} else {
100 					for (div = 0x10000000; div; div /= 0x10)
101 						div_out(&num, div);
102 				}
103 				break;
104 			case 'c':
105 				out((char)(va_arg(va, int)));
106 				break;
107 			case 's':
108 				p = va_arg(va, char*);
109 				break;
110 			case '%':
111 				out('%');
112 			default:
113 				break;
114 			}
115 
116 			*bf = 0;
117 			bf = p;
118 			while (*bf++ && width > 0)
119 				width--;
120 			while (width-- > 0)
121 				putc(lz ? '0' : ' ');
122 			if (p) {
123 				while ((ch = *p++))
124 					putc(ch);
125 			}
126 		}
127 	}
128 
129 abort:
130 	return 0;
131 }
132 
133 int printf(const char *fmt, ...)
134 {
135 	va_list va;
136 	int ret;
137 
138 	va_start(va, fmt);
139 	ret = _vprintf(fmt, va, putc);
140 	va_end(va);
141 
142 	return ret;
143 }
144 
145 static void putc_outstr(char ch)
146 {
147 	*outstr++ = ch;
148 }
149 
150 int sprintf(char *buf, const char *fmt, ...)
151 {
152 	va_list va;
153 	int ret;
154 
155 	va_start(va, fmt);
156 	outstr = buf;
157 	ret = _vprintf(fmt, va, putc_outstr);
158 	va_end(va);
159 	*outstr = '\0';
160 
161 	return ret;
162 }
163 
164 /* Note that size is ignored */
165 int snprintf(char *buf, size_t size, const char *fmt, ...)
166 {
167 	va_list va;
168 	int ret;
169 
170 	va_start(va, fmt);
171 	outstr = buf;
172 	ret = _vprintf(fmt, va, putc_outstr);
173 	va_end(va);
174 	*outstr = '\0';
175 
176 	return ret;
177 }
178