xref: /rk3399_rockchip-uboot/lib/tiny-printf.c (revision da70b4d14116d2b3d63840cd2ea01d0badf39e41)
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 
167d9cde10SStefan Roese static char *bf;
177d9cde10SStefan Roese static char zs;
187d9cde10SStefan Roese 
195c411d88SSimon Glass /* Current position in sprintf() output string */
205c411d88SSimon Glass static char *outstr;
215c411d88SSimon Glass 
227d9cde10SStefan Roese static void out(char c)
237d9cde10SStefan Roese {
247d9cde10SStefan Roese 	*bf++ = c;
257d9cde10SStefan Roese }
267d9cde10SStefan Roese 
277d9cde10SStefan Roese static void out_dgt(char dgt)
287d9cde10SStefan Roese {
29a5ecdd08SStefan Roese 	out(dgt + (dgt < 10 ? '0' : 'a' - 10));
307d9cde10SStefan Roese 	zs = 1;
317d9cde10SStefan Roese }
327d9cde10SStefan Roese 
33a5ecdd08SStefan Roese static void div_out(unsigned int *num, unsigned int div)
347d9cde10SStefan Roese {
357d9cde10SStefan Roese 	unsigned char dgt = 0;
367d9cde10SStefan Roese 
37a5ecdd08SStefan Roese 	while (*num >= div) {
38a5ecdd08SStefan Roese 		*num -= div;
397d9cde10SStefan Roese 		dgt++;
407d9cde10SStefan Roese 	}
417d9cde10SStefan Roese 
427d9cde10SStefan Roese 	if (zs || dgt > 0)
437d9cde10SStefan Roese 		out_dgt(dgt);
447d9cde10SStefan Roese }
457d9cde10SStefan Roese 
465c411d88SSimon Glass int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
477d9cde10SStefan Roese {
487d9cde10SStefan Roese 	char ch;
497d9cde10SStefan Roese 	char *p;
50a5ecdd08SStefan Roese 	unsigned int num;
51a5ecdd08SStefan Roese 	char buf[12];
52a5ecdd08SStefan Roese 	unsigned int div;
537d9cde10SStefan Roese 
547d9cde10SStefan Roese 	while ((ch = *(fmt++))) {
557d9cde10SStefan Roese 		if (ch != '%') {
567d9cde10SStefan Roese 			putc(ch);
577d9cde10SStefan Roese 		} else {
581fb67608SSimon Glass 			bool lz = false;
591fb67608SSimon Glass 			int width = 0;
607d9cde10SStefan Roese 
617d9cde10SStefan Roese 			ch = *(fmt++);
627d9cde10SStefan Roese 			if (ch == '0') {
637d9cde10SStefan Roese 				ch = *(fmt++);
647d9cde10SStefan Roese 				lz = 1;
657d9cde10SStefan Roese 			}
667d9cde10SStefan Roese 
677d9cde10SStefan Roese 			if (ch >= '0' && ch <= '9') {
681fb67608SSimon Glass 				width = 0;
697d9cde10SStefan Roese 				while (ch >= '0' && ch <= '9') {
701fb67608SSimon Glass 					width = (width * 10) + ch - '0';
717d9cde10SStefan Roese 					ch = *fmt++;
727d9cde10SStefan Roese 				}
737d9cde10SStefan Roese 			}
747d9cde10SStefan Roese 			bf = buf;
757d9cde10SStefan Roese 			p = bf;
767d9cde10SStefan Roese 			zs = 0;
777d9cde10SStefan Roese 
787d9cde10SStefan Roese 			switch (ch) {
791fb67608SSimon Glass 			case '\0':
807d9cde10SStefan Roese 				goto abort;
817d9cde10SStefan Roese 			case 'u':
827d9cde10SStefan Roese 			case 'd':
837d9cde10SStefan Roese 				num = va_arg(va, unsigned int);
847d9cde10SStefan Roese 				if (ch == 'd' && (int)num < 0) {
857d9cde10SStefan Roese 					num = -(int)num;
867d9cde10SStefan Roese 					out('-');
877d9cde10SStefan Roese 				}
8874b1320aSSimon Glass 				if (!num) {
8974b1320aSSimon Glass 					out_dgt(0);
9074b1320aSSimon Glass 				} else {
91a5ecdd08SStefan Roese 					for (div = 1000000000; div; div /= 10)
92a5ecdd08SStefan Roese 						div_out(&num, div);
9374b1320aSSimon Glass 				}
947d9cde10SStefan Roese 				break;
957d9cde10SStefan Roese 			case 'x':
967d9cde10SStefan Roese 				num = va_arg(va, unsigned int);
9774b1320aSSimon Glass 				if (!num) {
9874b1320aSSimon Glass 					out_dgt(0);
9974b1320aSSimon Glass 				} else {
100a5ecdd08SStefan Roese 					for (div = 0x10000000; div; div /= 0x10)
101a5ecdd08SStefan Roese 						div_out(&num, div);
10274b1320aSSimon Glass 				}
1037d9cde10SStefan Roese 				break;
1047d9cde10SStefan Roese 			case 'c':
1057d9cde10SStefan Roese 				out((char)(va_arg(va, int)));
1067d9cde10SStefan Roese 				break;
1077d9cde10SStefan Roese 			case 's':
1087d9cde10SStefan Roese 				p = va_arg(va, char*);
1097d9cde10SStefan Roese 				break;
1107d9cde10SStefan Roese 			case '%':
1117d9cde10SStefan Roese 				out('%');
1127d9cde10SStefan Roese 			default:
1137d9cde10SStefan Roese 				break;
1147d9cde10SStefan Roese 			}
1157d9cde10SStefan Roese 
1167d9cde10SStefan Roese 			*bf = 0;
1177d9cde10SStefan Roese 			bf = p;
1181fb67608SSimon Glass 			while (*bf++ && width > 0)
1191fb67608SSimon Glass 				width--;
1201fb67608SSimon Glass 			while (width-- > 0)
1217d9cde10SStefan Roese 				putc(lz ? '0' : ' ');
1228e31681cSSimon Glass 			if (p) {
1237d9cde10SStefan Roese 				while ((ch = *p++))
1247d9cde10SStefan Roese 					putc(ch);
1257d9cde10SStefan Roese 			}
1267d9cde10SStefan Roese 		}
1278e31681cSSimon Glass 	}
1287d9cde10SStefan Roese 
1297d9cde10SStefan Roese abort:
1307d9cde10SStefan Roese 	return 0;
1317d9cde10SStefan Roese }
132962a43ccSSjoerd Simons 
133*da70b4d1SHans de Goede int vprintf(const char *fmt, va_list va)
134*da70b4d1SHans de Goede {
135*da70b4d1SHans de Goede 	return _vprintf(fmt, va, putc);
136*da70b4d1SHans de Goede }
137*da70b4d1SHans de Goede 
138962a43ccSSjoerd Simons int printf(const char *fmt, ...)
139962a43ccSSjoerd Simons {
140962a43ccSSjoerd Simons 	va_list va;
141962a43ccSSjoerd Simons 	int ret;
142962a43ccSSjoerd Simons 
143962a43ccSSjoerd Simons 	va_start(va, fmt);
1445c411d88SSimon Glass 	ret = _vprintf(fmt, va, putc);
145962a43ccSSjoerd Simons 	va_end(va);
146962a43ccSSjoerd Simons 
147962a43ccSSjoerd Simons 	return ret;
148962a43ccSSjoerd Simons }
1495c411d88SSimon Glass 
1505c411d88SSimon Glass static void putc_outstr(char ch)
1515c411d88SSimon Glass {
1525c411d88SSimon Glass 	*outstr++ = ch;
1535c411d88SSimon Glass }
1545c411d88SSimon Glass 
155abeb272dSMarek Vasut int sprintf(char *buf, const char *fmt, ...)
1565c411d88SSimon Glass {
1575c411d88SSimon Glass 	va_list va;
1585c411d88SSimon Glass 	int ret;
1595c411d88SSimon Glass 
1605c411d88SSimon Glass 	va_start(va, fmt);
1615c411d88SSimon Glass 	outstr = buf;
1625c411d88SSimon Glass 	ret = _vprintf(fmt, va, putc_outstr);
1635c411d88SSimon Glass 	va_end(va);
1645c411d88SSimon Glass 	*outstr = '\0';
1655c411d88SSimon Glass 
1665c411d88SSimon Glass 	return ret;
1675c411d88SSimon Glass }
168abeb272dSMarek Vasut 
169abeb272dSMarek Vasut /* Note that size is ignored */
170abeb272dSMarek Vasut int snprintf(char *buf, size_t size, const char *fmt, ...)
171abeb272dSMarek Vasut {
172abeb272dSMarek Vasut 	va_list va;
173abeb272dSMarek Vasut 	int ret;
174abeb272dSMarek Vasut 
175abeb272dSMarek Vasut 	va_start(va, fmt);
1763191d840SSimon Glass 	outstr = buf;
1773191d840SSimon Glass 	ret = _vprintf(fmt, va, putc_outstr);
178abeb272dSMarek Vasut 	va_end(va);
1793191d840SSimon Glass 	*outstr = '\0';
180abeb272dSMarek Vasut 
181abeb272dSMarek Vasut 	return ret;
182abeb272dSMarek Vasut }
183