xref: /rk3399_rockchip-uboot/lib/tiny-printf.c (revision 433cbfb3b37404d6150a1aba94309bc0ed661689)
17d9cde10SStefan Roese /*
27d9cde10SStefan Roese  * Tiny printf version for SPL
37d9cde10SStefan Roese  *
47d9cde10SStefan Roese  * Copied from:
57d9cde10SStefan Roese  * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
67d9cde10SStefan Roese  *
77d9cde10SStefan Roese  * Copyright (C) 2004,2008  Kustaa Nyholm
87d9cde10SStefan Roese  *
97d9cde10SStefan Roese  * SPDX-License-Identifier:	LGPL-2.1+
107d9cde10SStefan Roese  */
117d9cde10SStefan Roese 
127d9cde10SStefan Roese #include <common.h>
137d9cde10SStefan Roese #include <stdarg.h>
147d9cde10SStefan Roese #include <serial.h>
157d9cde10SStefan Roese 
1645313e83SSimon Glass struct printf_info {
1745313e83SSimon Glass 	char *bf;	/* Digit buffer */
1845313e83SSimon Glass 	char zs;	/* non-zero if a digit has been written */
1945313e83SSimon Glass 	char *outstr;	/* Next output position for sprintf() */
207d9cde10SStefan Roese 
2145313e83SSimon Glass 	/* Output a character */
2245313e83SSimon Glass 	void (*putc)(struct printf_info *info, char ch);
2345313e83SSimon Glass };
245c411d88SSimon Glass 
25*433cbfb3SMasahiro Yamada static void putc_normal(struct printf_info *info, char ch)
267d9cde10SStefan Roese {
2745313e83SSimon Glass 	putc(ch);
287d9cde10SStefan Roese }
297d9cde10SStefan Roese 
3045313e83SSimon Glass static void out(struct printf_info *info, char c)
317d9cde10SStefan Roese {
3245313e83SSimon Glass 	*info->bf++ = c;
337d9cde10SStefan Roese }
347d9cde10SStefan Roese 
3545313e83SSimon Glass static void out_dgt(struct printf_info *info, char dgt)
3645313e83SSimon Glass {
3745313e83SSimon Glass 	out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
3845313e83SSimon Glass 	info->zs = 1;
3945313e83SSimon Glass }
4045313e83SSimon Glass 
41a28e1d98SAndre Przywara static void div_out(struct printf_info *info, unsigned long *num,
42a28e1d98SAndre Przywara 		    unsigned long div)
437d9cde10SStefan Roese {
447d9cde10SStefan Roese 	unsigned char dgt = 0;
457d9cde10SStefan Roese 
46a5ecdd08SStefan Roese 	while (*num >= div) {
47a5ecdd08SStefan Roese 		*num -= div;
487d9cde10SStefan Roese 		dgt++;
497d9cde10SStefan Roese 	}
507d9cde10SStefan Roese 
5145313e83SSimon Glass 	if (info->zs || dgt > 0)
5245313e83SSimon Glass 		out_dgt(info, dgt);
537d9cde10SStefan Roese }
547d9cde10SStefan Roese 
55*433cbfb3SMasahiro Yamada static int _vprintf(struct printf_info *info, const char *fmt, va_list va)
567d9cde10SStefan Roese {
577d9cde10SStefan Roese 	char ch;
587d9cde10SStefan Roese 	char *p;
59a28e1d98SAndre Przywara 	unsigned long num;
60a5ecdd08SStefan Roese 	char buf[12];
61a28e1d98SAndre Przywara 	unsigned long div;
627d9cde10SStefan Roese 
637d9cde10SStefan Roese 	while ((ch = *(fmt++))) {
647d9cde10SStefan Roese 		if (ch != '%') {
6545313e83SSimon Glass 			info->putc(info, ch);
667d9cde10SStefan Roese 		} else {
671fb67608SSimon Glass 			bool lz = false;
681fb67608SSimon Glass 			int width = 0;
69a28e1d98SAndre Przywara 			bool islong = false;
707d9cde10SStefan Roese 
717d9cde10SStefan Roese 			ch = *(fmt++);
721c853629SAndre Przywara 			if (ch == '-')
731c853629SAndre Przywara 				ch = *(fmt++);
741c853629SAndre Przywara 
757d9cde10SStefan Roese 			if (ch == '0') {
767d9cde10SStefan Roese 				ch = *(fmt++);
777d9cde10SStefan Roese 				lz = 1;
787d9cde10SStefan Roese 			}
797d9cde10SStefan Roese 
807d9cde10SStefan Roese 			if (ch >= '0' && ch <= '9') {
811fb67608SSimon Glass 				width = 0;
827d9cde10SStefan Roese 				while (ch >= '0' && ch <= '9') {
831fb67608SSimon Glass 					width = (width * 10) + ch - '0';
847d9cde10SStefan Roese 					ch = *fmt++;
857d9cde10SStefan Roese 				}
867d9cde10SStefan Roese 			}
87a28e1d98SAndre Przywara 			if (ch == 'l') {
88a28e1d98SAndre Przywara 				ch = *(fmt++);
89a28e1d98SAndre Przywara 				islong = true;
90a28e1d98SAndre Przywara 			}
91a28e1d98SAndre Przywara 
9245313e83SSimon Glass 			info->bf = buf;
9345313e83SSimon Glass 			p = info->bf;
9445313e83SSimon Glass 			info->zs = 0;
957d9cde10SStefan Roese 
967d9cde10SStefan Roese 			switch (ch) {
971fb67608SSimon Glass 			case '\0':
987d9cde10SStefan Roese 				goto abort;
997d9cde10SStefan Roese 			case 'u':
1007d9cde10SStefan Roese 			case 'd':
101a28e1d98SAndre Przywara 				div = 1000000000;
102a28e1d98SAndre Przywara 				if (islong) {
103a28e1d98SAndre Przywara 					num = va_arg(va, unsigned long);
104a28e1d98SAndre Przywara 					if (sizeof(long) > 4)
105a28e1d98SAndre Przywara 						div *= div * 10;
106a28e1d98SAndre Przywara 				} else {
1077d9cde10SStefan Roese 					num = va_arg(va, unsigned int);
108a28e1d98SAndre Przywara 				}
109a28e1d98SAndre Przywara 
110a28e1d98SAndre Przywara 				if (ch == 'd') {
111a28e1d98SAndre Przywara 					if (islong && (long)num < 0) {
112a28e1d98SAndre Przywara 						num = -(long)num;
113a28e1d98SAndre Przywara 						out(info, '-');
114a28e1d98SAndre Przywara 					} else if (!islong && (int)num < 0) {
1157d9cde10SStefan Roese 						num = -(int)num;
11645313e83SSimon Glass 						out(info, '-');
1177d9cde10SStefan Roese 					}
118a28e1d98SAndre Przywara 				}
11974b1320aSSimon Glass 				if (!num) {
12045313e83SSimon Glass 					out_dgt(info, 0);
12174b1320aSSimon Glass 				} else {
122a28e1d98SAndre Przywara 					for (; div; div /= 10)
12345313e83SSimon Glass 						div_out(info, &num, div);
12474b1320aSSimon Glass 				}
1257d9cde10SStefan Roese 				break;
1267d9cde10SStefan Roese 			case 'x':
127a28e1d98SAndre Przywara 				if (islong) {
128a28e1d98SAndre Przywara 					num = va_arg(va, unsigned long);
129a28e1d98SAndre Przywara 					div = 1UL << (sizeof(long) * 8 - 4);
130a28e1d98SAndre Przywara 				} else {
1317d9cde10SStefan Roese 					num = va_arg(va, unsigned int);
132a28e1d98SAndre Przywara 					div = 0x10000000;
133a28e1d98SAndre Przywara 				}
13474b1320aSSimon Glass 				if (!num) {
13545313e83SSimon Glass 					out_dgt(info, 0);
13674b1320aSSimon Glass 				} else {
137a28e1d98SAndre Przywara 					for (; div; div /= 0x10)
13845313e83SSimon Glass 						div_out(info, &num, div);
13974b1320aSSimon Glass 				}
1407d9cde10SStefan Roese 				break;
1417d9cde10SStefan Roese 			case 'c':
14245313e83SSimon Glass 				out(info, (char)(va_arg(va, int)));
1437d9cde10SStefan Roese 				break;
1447d9cde10SStefan Roese 			case 's':
1457d9cde10SStefan Roese 				p = va_arg(va, char*);
1467d9cde10SStefan Roese 				break;
1477d9cde10SStefan Roese 			case '%':
14845313e83SSimon Glass 				out(info, '%');
1497d9cde10SStefan Roese 			default:
1507d9cde10SStefan Roese 				break;
1517d9cde10SStefan Roese 			}
1527d9cde10SStefan Roese 
15345313e83SSimon Glass 			*info->bf = 0;
15445313e83SSimon Glass 			info->bf = p;
15545313e83SSimon Glass 			while (*info->bf++ && width > 0)
1561fb67608SSimon Glass 				width--;
1571fb67608SSimon Glass 			while (width-- > 0)
15845313e83SSimon Glass 				info->putc(info, lz ? '0' : ' ');
1598e31681cSSimon Glass 			if (p) {
1607d9cde10SStefan Roese 				while ((ch = *p++))
16145313e83SSimon Glass 					info->putc(info, ch);
1627d9cde10SStefan Roese 			}
1637d9cde10SStefan Roese 		}
1648e31681cSSimon Glass 	}
1657d9cde10SStefan Roese 
1667d9cde10SStefan Roese abort:
1677d9cde10SStefan Roese 	return 0;
1687d9cde10SStefan Roese }
169962a43ccSSjoerd Simons 
170da70b4d1SHans de Goede int vprintf(const char *fmt, va_list va)
171da70b4d1SHans de Goede {
17245313e83SSimon Glass 	struct printf_info info;
17345313e83SSimon Glass 
17445313e83SSimon Glass 	info.putc = putc_normal;
17545313e83SSimon Glass 	return _vprintf(&info, fmt, va);
176da70b4d1SHans de Goede }
177da70b4d1SHans de Goede 
178962a43ccSSjoerd Simons int printf(const char *fmt, ...)
179962a43ccSSjoerd Simons {
18045313e83SSimon Glass 	struct printf_info info;
18145313e83SSimon Glass 
182962a43ccSSjoerd Simons 	va_list va;
183962a43ccSSjoerd Simons 	int ret;
184962a43ccSSjoerd Simons 
18545313e83SSimon Glass 	info.putc = putc_normal;
186962a43ccSSjoerd Simons 	va_start(va, fmt);
18745313e83SSimon Glass 	ret = _vprintf(&info, fmt, va);
188962a43ccSSjoerd Simons 	va_end(va);
189962a43ccSSjoerd Simons 
190962a43ccSSjoerd Simons 	return ret;
191962a43ccSSjoerd Simons }
1925c411d88SSimon Glass 
19345313e83SSimon Glass static void putc_outstr(struct printf_info *info, char ch)
1945c411d88SSimon Glass {
19545313e83SSimon Glass 	*info->outstr++ = ch;
1965c411d88SSimon Glass }
1975c411d88SSimon Glass 
198abeb272dSMarek Vasut int sprintf(char *buf, const char *fmt, ...)
1995c411d88SSimon Glass {
20045313e83SSimon Glass 	struct printf_info info;
2015c411d88SSimon Glass 	va_list va;
2025c411d88SSimon Glass 	int ret;
2035c411d88SSimon Glass 
2045c411d88SSimon Glass 	va_start(va, fmt);
20545313e83SSimon Glass 	info.outstr = buf;
20645313e83SSimon Glass 	info.putc = putc_outstr;
20745313e83SSimon Glass 	ret = _vprintf(&info, fmt, va);
2085c411d88SSimon Glass 	va_end(va);
20945313e83SSimon Glass 	*info.outstr = '\0';
2105c411d88SSimon Glass 
2115c411d88SSimon Glass 	return ret;
2125c411d88SSimon Glass }
213abeb272dSMarek Vasut 
214abeb272dSMarek Vasut /* Note that size is ignored */
215abeb272dSMarek Vasut int snprintf(char *buf, size_t size, const char *fmt, ...)
216abeb272dSMarek Vasut {
21745313e83SSimon Glass 	struct printf_info info;
218abeb272dSMarek Vasut 	va_list va;
219abeb272dSMarek Vasut 	int ret;
220abeb272dSMarek Vasut 
221abeb272dSMarek Vasut 	va_start(va, fmt);
22245313e83SSimon Glass 	info.outstr = buf;
22345313e83SSimon Glass 	info.putc = putc_outstr;
22445313e83SSimon Glass 	ret = _vprintf(&info, fmt, va);
225abeb272dSMarek Vasut 	va_end(va);
22645313e83SSimon Glass 	*info.outstr = '\0';
227abeb272dSMarek Vasut 
228abeb272dSMarek Vasut 	return ret;
229abeb272dSMarek Vasut }
230e2409139SSimon Glass 
231e2409139SSimon Glass void __assert_fail(const char *assertion, const char *file, unsigned line,
232e2409139SSimon Glass 		   const char *function)
233e2409139SSimon Glass {
234e2409139SSimon Glass 	/* This will not return */
235e2409139SSimon Glass 	printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
236e2409139SSimon Glass 	       assertion);
237e2409139SSimon Glass 	hang();
238e2409139SSimon Glass }
239