| /* | 
 |  * Tiny printf version for SPL | 
 |  * | 
 |  * Copied from: | 
 |  * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php | 
 |  * | 
 |  * Copyright (C) 2004,2008  Kustaa Nyholm | 
 |  * | 
 |  * SPDX-License-Identifier:	LGPL-2.1+ | 
 |  */ | 
 |  | 
 | #include <common.h> | 
 | #include <stdarg.h> | 
 | #include <serial.h> | 
 |  | 
 | static char *bf; | 
 | static char zs; | 
 |  | 
 | static void out(char c) | 
 | { | 
 | 	*bf++ = c; | 
 | } | 
 |  | 
 | static void out_dgt(char dgt) | 
 | { | 
 | 	out(dgt + (dgt < 10 ? '0' : 'a' - 10)); | 
 | 	zs = 1; | 
 | } | 
 |  | 
 | static void div_out(unsigned int *num, unsigned int div) | 
 | { | 
 | 	unsigned char dgt = 0; | 
 |  | 
 | 	while (*num >= div) { | 
 | 		*num -= div; | 
 | 		dgt++; | 
 | 	} | 
 |  | 
 | 	if (zs || dgt > 0) | 
 | 		out_dgt(dgt); | 
 | } | 
 |  | 
 | int vprintf(const char *fmt, va_list va) | 
 | { | 
 | 	char ch; | 
 | 	char *p; | 
 | 	unsigned int num; | 
 | 	char buf[12]; | 
 | 	unsigned int div; | 
 |  | 
 | 	while ((ch = *(fmt++))) { | 
 | 		if (ch != '%') { | 
 | 			putc(ch); | 
 | 		} else { | 
 | 			char lz = 0; | 
 | 			char w = 0; | 
 |  | 
 | 			ch = *(fmt++); | 
 | 			if (ch == '0') { | 
 | 				ch = *(fmt++); | 
 | 				lz = 1; | 
 | 			} | 
 |  | 
 | 			if (ch >= '0' && ch <= '9') { | 
 | 				w = 0; | 
 | 				while (ch >= '0' && ch <= '9') { | 
 | 					w = (w * 10) + ch - '0'; | 
 | 					ch = *fmt++; | 
 | 				} | 
 | 			} | 
 | 			bf = buf; | 
 | 			p = bf; | 
 | 			zs = 0; | 
 |  | 
 | 			switch (ch) { | 
 | 			case 0: | 
 | 				goto abort; | 
 | 			case 'u': | 
 | 			case 'd': | 
 | 				num = va_arg(va, unsigned int); | 
 | 				if (ch == 'd' && (int)num < 0) { | 
 | 					num = -(int)num; | 
 | 					out('-'); | 
 | 				} | 
 | 				for (div = 1000000000; div; div /= 10) | 
 | 					div_out(&num, div); | 
 | 				break; | 
 | 			case 'x': | 
 | 				num = va_arg(va, unsigned int); | 
 | 				for (div = 0x10000000; div; div /= 0x10) | 
 | 					div_out(&num, div); | 
 | 				break; | 
 | 			case 'c': | 
 | 				out((char)(va_arg(va, int))); | 
 | 				break; | 
 | 			case 's': | 
 | 				p = va_arg(va, char*); | 
 | 				break; | 
 | 			case '%': | 
 | 				out('%'); | 
 | 			default: | 
 | 				break; | 
 | 			} | 
 |  | 
 | 			*bf = 0; | 
 | 			bf = p; | 
 | 			while (*bf++ && w > 0) | 
 | 				w--; | 
 | 			while (w-- > 0) | 
 | 				putc(lz ? '0' : ' '); | 
 | 			while ((ch = *p++)) | 
 | 				putc(ch); | 
 | 		} | 
 | 	} | 
 |  | 
 | abort: | 
 | 	return 0; | 
 | } | 
 |  | 
 | int printf(const char *fmt, ...) | 
 | { | 
 | 	va_list va; | 
 | 	int ret; | 
 |  | 
 | 	va_start(va, fmt); | 
 | 	ret = vprintf(fmt, va); | 
 | 	va_end(va); | 
 |  | 
 | 	return ret; | 
 | } |