5ea2555280b1561da6e072d6d8092b9e2b2325f3
[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 /* 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 printf(const char *fmt, ...)
134 {
135         va_list va;
136         int ret;
137
138         va_start(va, fmt);
139         ret = _vprintf(fmt, va, putc);
140         va_end(va);
141
142         return ret;
143 }
144
145 static void putc_outstr(char ch)
146 {
147         *outstr++ = ch;
148 }
149
150 int sprintf(char *buf, const char *fmt, ...)
151 {
152         va_list va;
153         int ret;
154
155         va_start(va, fmt);
156         outstr = buf;
157         ret = _vprintf(fmt, va, putc_outstr);
158         va_end(va);
159         *outstr = '\0';
160
161         return ret;
162 }
163
164 /* Note that size is ignored */
165 int snprintf(char *buf, size_t size, const char *fmt, ...)
166 {
167         va_list va;
168         int ret;
169
170         va_start(va, fmt);
171         ret = sprintf(buf, fmt, va);
172         va_end(va);
173
174         return ret;
175 }