Merge branch 'master' of git://git.denx.de/u-boot-video
[oweals/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 printf(const char *fmt, ...)
44 {
45         va_list va;
46         char ch;
47         char *p;
48         unsigned int num;
49         char buf[12];
50         unsigned int div;
51
52         va_start(va, fmt);
53
54         while ((ch = *(fmt++))) {
55                 if (ch != '%') {
56                         putc(ch);
57                 } else {
58                         char lz = 0;
59                         char w = 0;
60
61                         ch = *(fmt++);
62                         if (ch == '0') {
63                                 ch = *(fmt++);
64                                 lz = 1;
65                         }
66
67                         if (ch >= '0' && ch <= '9') {
68                                 w = 0;
69                                 while (ch >= '0' && ch <= '9') {
70                                         w = (w * 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                                 for (div = 1000000000; div; div /= 10)
89                                         div_out(&num, div);
90                                 break;
91                         case 'x':
92                                 num = va_arg(va, unsigned int);
93                                 for (div = 0x10000000; div; div /= 0x10)
94                                         div_out(&num, div);
95                                 break;
96                         case 'c':
97                                 out((char)(va_arg(va, int)));
98                                 break;
99                         case 's':
100                                 p = va_arg(va, char*);
101                                 break;
102                         case '%':
103                                 out('%');
104                         default:
105                                 break;
106                         }
107
108                         *bf = 0;
109                         bf = p;
110                         while (*bf++ && w > 0)
111                                 w--;
112                         while (w-- > 0)
113                                 putc(lz ? '0' : ' ');
114                         while ((ch = *p++))
115                                 putc(ch);
116                 }
117         }
118
119 abort:
120         va_end(va);
121         return 0;
122 }