]>
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++); | |
72 | if (ch == '0') { | |
73 | ch = *(fmt++); | |
74 | lz = 1; | |
75 | } | |
76 | ||
77 | if (ch >= '0' && ch <= '9') { | |
1fb67608 | 78 | width = 0; |
7d9cde10 | 79 | while (ch >= '0' && ch <= '9') { |
1fb67608 | 80 | width = (width * 10) + ch - '0'; |
7d9cde10 SR |
81 | ch = *fmt++; |
82 | } | |
83 | } | |
a28e1d98 AP |
84 | if (ch == 'l') { |
85 | ch = *(fmt++); | |
86 | islong = true; | |
87 | } | |
88 | ||
45313e83 SG |
89 | info->bf = buf; |
90 | p = info->bf; | |
91 | info->zs = 0; | |
7d9cde10 SR |
92 | |
93 | switch (ch) { | |
1fb67608 | 94 | case '\0': |
7d9cde10 SR |
95 | goto abort; |
96 | case 'u': | |
97 | case 'd': | |
a28e1d98 AP |
98 | div = 1000000000; |
99 | if (islong) { | |
100 | num = va_arg(va, unsigned long); | |
101 | if (sizeof(long) > 4) | |
102 | div *= div * 10; | |
103 | } else { | |
104 | num = va_arg(va, unsigned int); | |
105 | } | |
106 | ||
107 | if (ch == 'd') { | |
108 | if (islong && (long)num < 0) { | |
109 | num = -(long)num; | |
110 | out(info, '-'); | |
111 | } else if (!islong && (int)num < 0) { | |
112 | num = -(int)num; | |
113 | out(info, '-'); | |
114 | } | |
7d9cde10 | 115 | } |
74b1320a | 116 | if (!num) { |
45313e83 | 117 | out_dgt(info, 0); |
74b1320a | 118 | } else { |
a28e1d98 | 119 | for (; div; div /= 10) |
45313e83 | 120 | div_out(info, &num, div); |
74b1320a | 121 | } |
7d9cde10 SR |
122 | break; |
123 | case 'x': | |
a28e1d98 AP |
124 | if (islong) { |
125 | num = va_arg(va, unsigned long); | |
126 | div = 1UL << (sizeof(long) * 8 - 4); | |
127 | } else { | |
128 | num = va_arg(va, unsigned int); | |
129 | div = 0x10000000; | |
130 | } | |
74b1320a | 131 | if (!num) { |
45313e83 | 132 | out_dgt(info, 0); |
74b1320a | 133 | } else { |
a28e1d98 | 134 | for (; div; div /= 0x10) |
45313e83 | 135 | div_out(info, &num, div); |
74b1320a | 136 | } |
7d9cde10 SR |
137 | break; |
138 | case 'c': | |
45313e83 | 139 | out(info, (char)(va_arg(va, int))); |
7d9cde10 SR |
140 | break; |
141 | case 's': | |
142 | p = va_arg(va, char*); | |
143 | break; | |
144 | case '%': | |
45313e83 | 145 | out(info, '%'); |
7d9cde10 SR |
146 | default: |
147 | break; | |
148 | } | |
149 | ||
45313e83 SG |
150 | *info->bf = 0; |
151 | info->bf = p; | |
152 | while (*info->bf++ && width > 0) | |
1fb67608 SG |
153 | width--; |
154 | while (width-- > 0) | |
45313e83 | 155 | info->putc(info, lz ? '0' : ' '); |
8e31681c SG |
156 | if (p) { |
157 | while ((ch = *p++)) | |
45313e83 | 158 | info->putc(info, ch); |
8e31681c | 159 | } |
7d9cde10 SR |
160 | } |
161 | } | |
162 | ||
163 | abort: | |
7d9cde10 SR |
164 | return 0; |
165 | } | |
962a43cc | 166 | |
da70b4d1 HG |
167 | int vprintf(const char *fmt, va_list va) |
168 | { | |
45313e83 SG |
169 | struct printf_info info; |
170 | ||
171 | info.putc = putc_normal; | |
172 | return _vprintf(&info, fmt, va); | |
da70b4d1 HG |
173 | } |
174 | ||
962a43cc SS |
175 | int printf(const char *fmt, ...) |
176 | { | |
45313e83 SG |
177 | struct printf_info info; |
178 | ||
962a43cc SS |
179 | va_list va; |
180 | int ret; | |
181 | ||
45313e83 | 182 | info.putc = putc_normal; |
962a43cc | 183 | va_start(va, fmt); |
45313e83 | 184 | ret = _vprintf(&info, fmt, va); |
5c411d88 SG |
185 | va_end(va); |
186 | ||
187 | return ret; | |
188 | } | |
189 | ||
45313e83 | 190 | static void putc_outstr(struct printf_info *info, char ch) |
5c411d88 | 191 | { |
45313e83 | 192 | *info->outstr++ = ch; |
5c411d88 SG |
193 | } |
194 | ||
abeb272d | 195 | int sprintf(char *buf, const char *fmt, ...) |
5c411d88 | 196 | { |
45313e83 | 197 | struct printf_info info; |
5c411d88 SG |
198 | va_list va; |
199 | int ret; | |
200 | ||
201 | va_start(va, fmt); | |
45313e83 SG |
202 | info.outstr = buf; |
203 | info.putc = putc_outstr; | |
204 | ret = _vprintf(&info, fmt, va); | |
962a43cc | 205 | va_end(va); |
45313e83 | 206 | *info.outstr = '\0'; |
962a43cc SS |
207 | |
208 | return ret; | |
209 | } | |
abeb272d MV |
210 | |
211 | /* Note that size is ignored */ | |
212 | int snprintf(char *buf, size_t size, const char *fmt, ...) | |
213 | { | |
45313e83 | 214 | struct printf_info info; |
abeb272d MV |
215 | va_list va; |
216 | int ret; | |
217 | ||
218 | va_start(va, fmt); | |
45313e83 SG |
219 | info.outstr = buf; |
220 | info.putc = putc_outstr; | |
221 | ret = _vprintf(&info, fmt, va); | |
abeb272d | 222 | va_end(va); |
45313e83 | 223 | *info.outstr = '\0'; |
abeb272d MV |
224 | |
225 | return ret; | |
226 | } | |
e2409139 SG |
227 | |
228 | void __assert_fail(const char *assertion, const char *file, unsigned line, | |
229 | const char *function) | |
230 | { | |
231 | /* This will not return */ | |
232 | printf("%s:%u: %s: Assertion `%s' failed.", file, line, function, | |
233 | assertion); | |
234 | hang(); | |
235 | } |