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 16 static char *bf; 17 static char zs; 18 19 /* Current position in sprintf() output string */ 20 static char *outstr; 21 22 static void out(char c) 23 { 24 *bf++ = c; 25 } 26 27 static void out_dgt(char dgt) 28 { 29 out(dgt + (dgt < 10 ? '0' : 'a' - 10)); 30 zs = 1; 31 } 32 33 static void div_out(unsigned int *num, unsigned int div) 34 { 35 unsigned char dgt = 0; 36 37 while (*num >= div) { 38 *num -= div; 39 dgt++; 40 } 41 42 if (zs || dgt > 0) 43 out_dgt(dgt); 44 } 45 46 int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) 47 { 48 char ch; 49 char *p; 50 unsigned int num; 51 char buf[12]; 52 unsigned int div; 53 54 while ((ch = *(fmt++))) { 55 if (ch != '%') { 56 putc(ch); 57 } else { 58 bool lz = false; 59 int width = 0; 60 61 ch = *(fmt++); 62 if (ch == '0') { 63 ch = *(fmt++); 64 lz = 1; 65 } 66 67 if (ch >= '0' && ch <= '9') { 68 width = 0; 69 while (ch >= '0' && ch <= '9') { 70 width = (width * 10) + ch - '0'; 71 ch = *fmt++; 72 } 73 } 74 bf = buf; 75 p = bf; 76 zs = 0; 77 78 switch (ch) { 79 case '\0': 80 goto abort; 81 case 'u': 82 case 'd': 83 num = va_arg(va, unsigned int); 84 if (ch == 'd' && (int)num < 0) { 85 num = -(int)num; 86 out('-'); 87 } 88 if (!num) { 89 out_dgt(0); 90 } else { 91 for (div = 1000000000; div; div /= 10) 92 div_out(&num, div); 93 } 94 break; 95 case 'x': 96 num = va_arg(va, unsigned int); 97 if (!num) { 98 out_dgt(0); 99 } else { 100 for (div = 0x10000000; div; div /= 0x10) 101 div_out(&num, div); 102 } 103 break; 104 case 'c': 105 out((char)(va_arg(va, int))); 106 break; 107 case 's': 108 p = va_arg(va, char*); 109 break; 110 case '%': 111 out('%'); 112 default: 113 break; 114 } 115 116 *bf = 0; 117 bf = p; 118 while (*bf++ && width > 0) 119 width--; 120 while (width-- > 0) 121 putc(lz ? '0' : ' '); 122 if (p) { 123 while ((ch = *p++)) 124 putc(ch); 125 } 126 } 127 } 128 129 abort: 130 return 0; 131 } 132 133 int vprintf(const char *fmt, va_list va) 134 { 135 return _vprintf(fmt, va, putc); 136 } 137 138 int printf(const char *fmt, ...) 139 { 140 va_list va; 141 int ret; 142 143 va_start(va, fmt); 144 ret = _vprintf(fmt, va, putc); 145 va_end(va); 146 147 return ret; 148 } 149 150 static void putc_outstr(char ch) 151 { 152 *outstr++ = ch; 153 } 154 155 int sprintf(char *buf, const char *fmt, ...) 156 { 157 va_list va; 158 int ret; 159 160 va_start(va, fmt); 161 outstr = buf; 162 ret = _vprintf(fmt, va, putc_outstr); 163 va_end(va); 164 *outstr = '\0'; 165 166 return ret; 167 } 168 169 /* Note that size is ignored */ 170 int snprintf(char *buf, size_t size, const char *fmt, ...) 171 { 172 va_list va; 173 int ret; 174 175 va_start(va, fmt); 176 outstr = buf; 177 ret = _vprintf(fmt, va, putc_outstr); 178 va_end(va); 179 *outstr = '\0'; 180 181 return ret; 182 } 183