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