uboot/lib/tiny-printf.c
<<
>>
Prefs
   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 */
  21static char *bf __attribute__ ((section(".data")));
  22static char zs __attribute__ ((section(".data")));
  23
  24/* Current position in sprintf() output string */
  25static char *outstr __attribute__ ((section(".data")));
  26
  27static void out(char c)
  28{
  29        *bf++ = c;
  30}
  31
  32static void out_dgt(char dgt)
  33{
  34        out(dgt + (dgt < 10 ? '0' : 'a' - 10));
  35        zs = 1;
  36}
  37
  38static 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
  51int _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
 134abort:
 135        return 0;
 136}
 137
 138int vprintf(const char *fmt, va_list va)
 139{
 140        return _vprintf(fmt, va, putc);
 141}
 142
 143int 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
 155static void putc_outstr(char ch)
 156{
 157        *outstr++ = ch;
 158}
 159
 160int 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 */
 175int 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