blob: 451f4f7a673d74e8ae93cee83f0c7c5a690a193e [file] [log] [blame]
Stefan Roese7d9cde12015-11-23 07:00:22 +01001/*
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
16static char *bf;
Stefan Roese7d9cde12015-11-23 07:00:22 +010017static char zs;
18
Simon Glass5c411d82016-05-14 14:02:53 -060019/* Current position in sprintf() output string */
20static char *outstr;
21
Stefan Roese7d9cde12015-11-23 07:00:22 +010022static void out(char c)
23{
24 *bf++ = c;
25}
26
27static void out_dgt(char dgt)
28{
Stefan Roesea5ecdd02015-11-16 15:26:34 +010029 out(dgt + (dgt < 10 ? '0' : 'a' - 10));
Stefan Roese7d9cde12015-11-23 07:00:22 +010030 zs = 1;
31}
32
Stefan Roesea5ecdd02015-11-16 15:26:34 +010033static void div_out(unsigned int *num, unsigned int div)
Stefan Roese7d9cde12015-11-23 07:00:22 +010034{
35 unsigned char dgt = 0;
36
Stefan Roesea5ecdd02015-11-16 15:26:34 +010037 while (*num >= div) {
38 *num -= div;
Stefan Roese7d9cde12015-11-23 07:00:22 +010039 dgt++;
40 }
41
42 if (zs || dgt > 0)
43 out_dgt(dgt);
44}
45
Simon Glass5c411d82016-05-14 14:02:53 -060046int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch))
Stefan Roese7d9cde12015-11-23 07:00:22 +010047{
Stefan Roese7d9cde12015-11-23 07:00:22 +010048 char ch;
49 char *p;
Stefan Roesea5ecdd02015-11-16 15:26:34 +010050 unsigned int num;
51 char buf[12];
52 unsigned int div;
Stefan Roese7d9cde12015-11-23 07:00:22 +010053
Stefan Roese7d9cde12015-11-23 07:00:22 +010054 while ((ch = *(fmt++))) {
55 if (ch != '%') {
56 putc(ch);
57 } else {
Simon Glass1fb67602016-05-14 14:02:52 -060058 bool lz = false;
59 int width = 0;
Stefan Roese7d9cde12015-11-23 07:00:22 +010060
61 ch = *(fmt++);
62 if (ch == '0') {
63 ch = *(fmt++);
64 lz = 1;
65 }
66
67 if (ch >= '0' && ch <= '9') {
Simon Glass1fb67602016-05-14 14:02:52 -060068 width = 0;
Stefan Roese7d9cde12015-11-23 07:00:22 +010069 while (ch >= '0' && ch <= '9') {
Simon Glass1fb67602016-05-14 14:02:52 -060070 width = (width * 10) + ch - '0';
Stefan Roese7d9cde12015-11-23 07:00:22 +010071 ch = *fmt++;
72 }
73 }
74 bf = buf;
75 p = bf;
76 zs = 0;
77
78 switch (ch) {
Simon Glass1fb67602016-05-14 14:02:52 -060079 case '\0':
Stefan Roese7d9cde12015-11-23 07:00:22 +010080 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 }
Simon Glass74b13202016-01-05 09:30:57 -070088 if (!num) {
89 out_dgt(0);
90 } else {
91 for (div = 1000000000; div; div /= 10)
92 div_out(&num, div);
93 }
Stefan Roese7d9cde12015-11-23 07:00:22 +010094 break;
95 case 'x':
Stefan Roese7d9cde12015-11-23 07:00:22 +010096 num = va_arg(va, unsigned int);
Simon Glass74b13202016-01-05 09:30:57 -070097 if (!num) {
98 out_dgt(0);
99 } else {
100 for (div = 0x10000000; div; div /= 0x10)
101 div_out(&num, div);
102 }
Stefan Roese7d9cde12015-11-23 07:00:22 +0100103 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;
Simon Glass1fb67602016-05-14 14:02:52 -0600118 while (*bf++ && width > 0)
119 width--;
120 while (width-- > 0)
Stefan Roese7d9cde12015-11-23 07:00:22 +0100121 putc(lz ? '0' : ' ');
Simon Glass8e316812015-12-29 05:22:46 -0700122 if (p) {
123 while ((ch = *p++))
124 putc(ch);
125 }
Stefan Roese7d9cde12015-11-23 07:00:22 +0100126 }
127 }
128
129abort:
Stefan Roese7d9cde12015-11-23 07:00:22 +0100130 return 0;
131}
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100132
Hans de Goededa70b4d2016-06-10 21:03:34 +0200133int vprintf(const char *fmt, va_list va)
134{
135 return _vprintf(fmt, va, putc);
136}
137
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100138int printf(const char *fmt, ...)
139{
140 va_list va;
141 int ret;
142
143 va_start(va, fmt);
Simon Glass5c411d82016-05-14 14:02:53 -0600144 ret = _vprintf(fmt, va, putc);
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100145 va_end(va);
146
147 return ret;
148}
Simon Glass5c411d82016-05-14 14:02:53 -0600149
150static void putc_outstr(char ch)
151{
152 *outstr++ = ch;
153}
154
Marek Vasutabeb2722016-05-31 23:12:46 +0200155int sprintf(char *buf, const char *fmt, ...)
Simon Glass5c411d82016-05-14 14:02:53 -0600156{
157 va_list va;
158 int ret;
159
160 va_start(va, fmt);
161 outstr = buf;
162 ret = _vprintf(fmt, va, putc_outstr);
163 va_end(va);
164 *outstr = '\0';
165
166 return ret;
167}
Marek Vasutabeb2722016-05-31 23:12:46 +0200168
169/* Note that size is ignored */
170int snprintf(char *buf, size_t size, const char *fmt, ...)
171{
172 va_list va;
173 int ret;
174
175 va_start(va, fmt);
Simon Glass3191d842016-06-08 20:55:15 -0600176 outstr = buf;
177 ret = _vprintf(fmt, va, putc_outstr);
Marek Vasutabeb2722016-05-31 23:12:46 +0200178 va_end(va);
Simon Glass3191d842016-06-08 20:55:15 -0600179 *outstr = '\0';
Marek Vasutabeb2722016-05-31 23:12:46 +0200180
181 return ret;
182}