]> git.ipfire.org Git - people/ms/u-boot.git/blame - lib/tiny-printf.c
SPL: tiny-printf: add "l" modifier
[people/ms/u-boot.git] / lib / tiny-printf.c
CommitLineData
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
16struct 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 25void putc_normal(struct printf_info *info, char ch)
7d9cde10 26{
45313e83 27 putc(ch);
7d9cde10
SR
28}
29
45313e83 30static void out(struct printf_info *info, char c)
7d9cde10 31{
45313e83 32 *info->bf++ = c;
7d9cde10
SR
33}
34
45313e83
SG
35static 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
41static 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 55int _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
163abort:
7d9cde10
SR
164 return 0;
165}
962a43cc 166
da70b4d1
HG
167int 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
175int 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 190static void putc_outstr(struct printf_info *info, char ch)
5c411d88 191{
45313e83 192 *info->outstr++ = ch;
5c411d88
SG
193}
194
abeb272d 195int 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 */
212int 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
228void __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}