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