Merge branch 'master' of git://git.denx.de/u-boot-usb
[platform/kernel/u-boot.git] / lib / tiny-printf.c
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 static void out(char c)
20 {
21         *bf++ = c;
22 }
23
24 static void out_dgt(char dgt)
25 {
26         out(dgt + (dgt < 10 ? '0' : 'a' - 10));
27         zs = 1;
28 }
29
30 static void div_out(unsigned int *num, unsigned int div)
31 {
32         unsigned char dgt = 0;
33
34         while (*num >= div) {
35                 *num -= div;
36                 dgt++;
37         }
38
39         if (zs || dgt > 0)
40                 out_dgt(dgt);
41 }
42
43 int vprintf(const char *fmt, va_list va)
44 {
45         char ch;
46         char *p;
47         unsigned int num;
48         char buf[12];
49         unsigned int div;
50
51         while ((ch = *(fmt++))) {
52                 if (ch != '%') {
53                         putc(ch);
54                 } else {
55                         char lz = 0;
56                         char w = 0;
57
58                         ch = *(fmt++);
59                         if (ch == '0') {
60                                 ch = *(fmt++);
61                                 lz = 1;
62                         }
63
64                         if (ch >= '0' && ch <= '9') {
65                                 w = 0;
66                                 while (ch >= '0' && ch <= '9') {
67                                         w = (w * 10) + ch - '0';
68                                         ch = *fmt++;
69                                 }
70                         }
71                         bf = buf;
72                         p = bf;
73                         zs = 0;
74
75                         switch (ch) {
76                         case 0:
77                                 goto abort;
78                         case 'u':
79                         case 'd':
80                                 num = va_arg(va, unsigned int);
81                                 if (ch == 'd' && (int)num < 0) {
82                                         num = -(int)num;
83                                         out('-');
84                                 }
85                                 for (div = 1000000000; div; div /= 10)
86                                         div_out(&num, div);
87                                 break;
88                         case 'x':
89                                 num = va_arg(va, unsigned int);
90                                 for (div = 0x10000000; div; div /= 0x10)
91                                         div_out(&num, div);
92                                 break;
93                         case 'c':
94                                 out((char)(va_arg(va, int)));
95                                 break;
96                         case 's':
97                                 p = va_arg(va, char*);
98                                 break;
99                         case '%':
100                                 out('%');
101                         default:
102                                 break;
103                         }
104
105                         *bf = 0;
106                         bf = p;
107                         while (*bf++ && w > 0)
108                                 w--;
109                         while (w-- > 0)
110                                 putc(lz ? '0' : ' ');
111                         while ((ch = *p++))
112                                 putc(ch);
113                 }
114         }
115
116 abort:
117         return 0;
118 }
119
120 int printf(const char *fmt, ...)
121 {
122         va_list va;
123         int ret;
124
125         va_start(va, fmt);
126         ret = vprintf(fmt, va);
127         va_end(va);
128
129         return ret;
130 }