]>
Commit | Line | Data |
---|---|---|
7d9cde10 SR |
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 | ||
45313e83 SG |
16 | struct printf_info { |
17 | char *bf; /* Digit buffer */ | |
18 | char zs; /* non-zero if a digit has been written */ | |
19 | char *outstr; /* Next output position for sprintf() */ | |
7d9cde10 | 20 | |
45313e83 SG |
21 | /* Output a character */ |
22 | void (*putc)(struct printf_info *info, char ch); | |
23 | }; | |
5c411d88 | 24 | |
45313e83 | 25 | void putc_normal(struct printf_info *info, char ch) |
7d9cde10 | 26 | { |
45313e83 | 27 | putc(ch); |
7d9cde10 SR |
28 | } |
29 | ||
45313e83 | 30 | static void out(struct printf_info *info, char c) |
7d9cde10 | 31 | { |
45313e83 | 32 | *info->bf++ = c; |
7d9cde10 SR |
33 | } |
34 | ||
45313e83 SG |
35 | static void out_dgt(struct printf_info *info, char dgt) |
36 | { | |
37 | out(info, dgt + (dgt < 10 ? '0' : 'a' - 10)); | |
38 | info->zs = 1; | |
39 | } | |
40 | ||
a28e1d98 AP |
41 | static void div_out(struct printf_info *info, unsigned long *num, |
42 | unsigned long div) | |
7d9cde10 SR |
43 | { |
44 | unsigned char dgt = 0; | |
45 | ||
a5ecdd08 SR |
46 | while (*num >= div) { |
47 | *num -= div; | |
7d9cde10 SR |
48 | dgt++; |
49 | } | |
50 | ||
45313e83 SG |
51 | if (info->zs || dgt > 0) |
52 | out_dgt(info, dgt); | |
7d9cde10 SR |
53 | } |
54 | ||
45313e83 | 55 | int _vprintf(struct printf_info *info, const char *fmt, va_list va) |
7d9cde10 | 56 | { |
7d9cde10 SR |
57 | char ch; |
58 | char *p; | |
a28e1d98 | 59 | unsigned long num; |
a5ecdd08 | 60 | char buf[12]; |
a28e1d98 | 61 | unsigned long div; |
7d9cde10 | 62 | |
7d9cde10 SR |
63 | while ((ch = *(fmt++))) { |
64 | if (ch != '%') { | |
45313e83 | 65 | info->putc(info, ch); |
7d9cde10 | 66 | } else { |
1fb67608 SG |
67 | bool lz = false; |
68 | int width = 0; | |
a28e1d98 | 69 | bool islong = false; |
7d9cde10 SR |
70 | |
71 | ch = *(fmt++); | |
1c853629 AP |
72 | if (ch == '-') |
73 | ch = *(fmt++); | |
74 | ||
7d9cde10 SR |
75 | if (ch == '0') { |
76 | ch = *(fmt++); | |
77 | lz = 1; | |
78 | } | |
79 | ||
80 | if (ch >= '0' && ch <= '9') { | |
1fb67608 | 81 | width = 0; |
7d9cde10 | 82 | while (ch >= '0' && ch <= '9') { |
1fb67608 | 83 | width = (width * 10) + ch - '0'; |
7d9cde10 SR |
84 | ch = *fmt++; |
85 | } | |
86 | } | |
a28e1d98 AP |
87 | if (ch == 'l') { |
88 | ch = *(fmt++); | |
89 | islong = true; | |
90 | } | |
91 | ||
45313e83 SG |
92 | info->bf = buf; |
93 | p = info->bf; | |
94 | info->zs = 0; | |
7d9cde10 SR |
95 | |
96 | switch (ch) { | |
1fb67608 | 97 | case '\0': |
7d9cde10 SR |
98 | goto abort; |
99 | case 'u': | |
100 | case 'd': | |
a28e1d98 AP |
101 | div = 1000000000; |
102 | if (islong) { | |
103 | num = va_arg(va, unsigned long); | |
104 | if (sizeof(long) > 4) | |
105 | div *= div * 10; | |
106 | } else { | |
107 | num = va_arg(va, unsigned int); | |
108 | } | |
109 | ||
110 | if (ch == 'd') { | |
111 | if (islong && (long)num < 0) { | |
112 | num = -(long)num; | |
113 | out(info, '-'); | |
114 | } else if (!islong && (int)num < 0) { | |
115 | num = -(int)num; | |
116 | out(info, '-'); | |
117 | } | |
7d9cde10 | 118 | } |
74b1320a | 119 | if (!num) { |
45313e83 | 120 | out_dgt(info, 0); |
74b1320a | 121 | } else { |
a28e1d98 | 122 | for (; div; div /= 10) |
45313e83 | 123 | div_out(info, &num, div); |
74b1320a | 124 | } |
7d9cde10 SR |
125 | break; |
126 | case 'x': | |
a28e1d98 AP |
127 | if (islong) { |
128 | num = va_arg(va, unsigned long); | |
129 | div = 1UL << (sizeof(long) * 8 - 4); | |
130 | } else { | |
131 | num = va_arg(va, unsigned int); | |
132 | div = 0x10000000; | |
133 | } | |
74b1320a | 134 | if (!num) { |
45313e83 | 135 | out_dgt(info, 0); |
74b1320a | 136 | } else { |
a28e1d98 | 137 | for (; div; div /= 0x10) |
45313e83 | 138 | div_out(info, &num, div); |
74b1320a | 139 | } |
7d9cde10 SR |
140 | break; |
141 | case 'c': | |
45313e83 | 142 | out(info, (char)(va_arg(va, int))); |
7d9cde10 SR |
143 | break; |
144 | case 's': | |
145 | p = va_arg(va, char*); | |
146 | break; | |
147 | case '%': | |
45313e83 | 148 | out(info, '%'); |
7d9cde10 SR |
149 | default: |
150 | break; | |
151 | } | |
152 | ||
45313e83 SG |
153 | *info->bf = 0; |
154 | info->bf = p; | |
155 | while (*info->bf++ && width > 0) | |
1fb67608 SG |
156 | width--; |
157 | while (width-- > 0) | |
45313e83 | 158 | info->putc(info, lz ? '0' : ' '); |
8e31681c SG |
159 | if (p) { |
160 | while ((ch = *p++)) | |
45313e83 | 161 | info->putc(info, ch); |
8e31681c | 162 | } |
7d9cde10 SR |
163 | } |
164 | } | |
165 | ||
166 | abort: | |
7d9cde10 SR |
167 | return 0; |
168 | } | |
962a43cc | 169 | |
da70b4d1 HG |
170 | int vprintf(const char *fmt, va_list va) |
171 | { | |
45313e83 SG |
172 | struct printf_info info; |
173 | ||
174 | info.putc = putc_normal; | |
175 | return _vprintf(&info, fmt, va); | |
da70b4d1 HG |
176 | } |
177 | ||
962a43cc SS |
178 | int printf(const char *fmt, ...) |
179 | { | |
45313e83 SG |
180 | struct printf_info info; |
181 | ||
962a43cc SS |
182 | va_list va; |
183 | int ret; | |
184 | ||
45313e83 | 185 | info.putc = putc_normal; |
962a43cc | 186 | va_start(va, fmt); |
45313e83 | 187 | ret = _vprintf(&info, fmt, va); |
5c411d88 SG |
188 | va_end(va); |
189 | ||
190 | return ret; | |
191 | } | |
192 | ||
45313e83 | 193 | static void putc_outstr(struct printf_info *info, char ch) |
5c411d88 | 194 | { |
45313e83 | 195 | *info->outstr++ = ch; |
5c411d88 SG |
196 | } |
197 | ||
abeb272d | 198 | int sprintf(char *buf, const char *fmt, ...) |
5c411d88 | 199 | { |
45313e83 | 200 | struct printf_info info; |
5c411d88 SG |
201 | va_list va; |
202 | int ret; | |
203 | ||
204 | va_start(va, fmt); | |
45313e83 SG |
205 | info.outstr = buf; |
206 | info.putc = putc_outstr; | |
207 | ret = _vprintf(&info, fmt, va); | |
962a43cc | 208 | va_end(va); |
45313e83 | 209 | *info.outstr = '\0'; |
962a43cc SS |
210 | |
211 | return ret; | |
212 | } | |
abeb272d MV |
213 | |
214 | /* Note that size is ignored */ | |
215 | int snprintf(char *buf, size_t size, const char *fmt, ...) | |
216 | { | |
45313e83 | 217 | struct printf_info info; |
abeb272d MV |
218 | va_list va; |
219 | int ret; | |
220 | ||
221 | va_start(va, fmt); | |
45313e83 SG |
222 | info.outstr = buf; |
223 | info.putc = putc_outstr; | |
224 | ret = _vprintf(&info, fmt, va); | |
abeb272d | 225 | va_end(va); |
45313e83 | 226 | *info.outstr = '\0'; |
abeb272d MV |
227 | |
228 | return ret; | |
229 | } | |
e2409139 SG |
230 | |
231 | void __assert_fail(const char *assertion, const char *file, unsigned line, | |
232 | const char *function) | |
233 | { | |
234 | /* This will not return */ | |
235 | printf("%s:%u: %s: Assertion `%s' failed.", file, line, function, | |
236 | assertion); | |
237 | hang(); | |
238 | } |