blob: 30ac7596d343716f0041619e73e46e0359328126 [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
Simon Glass45313e82016-08-04 21:58:14 -060016struct printf_info {
17 char *bf; /* Digit buffer */
18 char zs; /* non-zero if a digit has been written */
19 char *outstr; /* Next output position for sprintf() */
Stefan Roese7d9cde12015-11-23 07:00:22 +010020
Simon Glass45313e82016-08-04 21:58:14 -060021 /* Output a character */
22 void (*putc)(struct printf_info *info, char ch);
23};
Simon Glass5c411d82016-05-14 14:02:53 -060024
Simon Glass45313e82016-08-04 21:58:14 -060025void putc_normal(struct printf_info *info, char ch)
Stefan Roese7d9cde12015-11-23 07:00:22 +010026{
Simon Glass45313e82016-08-04 21:58:14 -060027 putc(ch);
Stefan Roese7d9cde12015-11-23 07:00:22 +010028}
29
Simon Glass45313e82016-08-04 21:58:14 -060030static void out(struct printf_info *info, char c)
Stefan Roese7d9cde12015-11-23 07:00:22 +010031{
Simon Glass45313e82016-08-04 21:58:14 -060032 *info->bf++ = c;
Stefan Roese7d9cde12015-11-23 07:00:22 +010033}
34
Simon Glass45313e82016-08-04 21:58:14 -060035static void out_dgt(struct printf_info *info, char dgt)
36{
37 out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
38 info->zs = 1;
39}
40
41static void div_out(struct printf_info *info, unsigned int *num,
42 unsigned int div)
Stefan Roese7d9cde12015-11-23 07:00:22 +010043{
44 unsigned char dgt = 0;
45
Stefan Roesea5ecdd02015-11-16 15:26:34 +010046 while (*num >= div) {
47 *num -= div;
Stefan Roese7d9cde12015-11-23 07:00:22 +010048 dgt++;
49 }
50
Simon Glass45313e82016-08-04 21:58:14 -060051 if (info->zs || dgt > 0)
52 out_dgt(info, dgt);
Stefan Roese7d9cde12015-11-23 07:00:22 +010053}
54
Simon Glass45313e82016-08-04 21:58:14 -060055int _vprintf(struct printf_info *info, const char *fmt, va_list va)
Stefan Roese7d9cde12015-11-23 07:00:22 +010056{
Stefan Roese7d9cde12015-11-23 07:00:22 +010057 char ch;
58 char *p;
Stefan Roesea5ecdd02015-11-16 15:26:34 +010059 unsigned int num;
60 char buf[12];
61 unsigned int div;
Stefan Roese7d9cde12015-11-23 07:00:22 +010062
Stefan Roese7d9cde12015-11-23 07:00:22 +010063 while ((ch = *(fmt++))) {
64 if (ch != '%') {
Simon Glass45313e82016-08-04 21:58:14 -060065 info->putc(info, ch);
Stefan Roese7d9cde12015-11-23 07:00:22 +010066 } else {
Simon Glass1fb67602016-05-14 14:02:52 -060067 bool lz = false;
68 int width = 0;
Stefan Roese7d9cde12015-11-23 07:00:22 +010069
70 ch = *(fmt++);
71 if (ch == '0') {
72 ch = *(fmt++);
73 lz = 1;
74 }
75
76 if (ch >= '0' && ch <= '9') {
Simon Glass1fb67602016-05-14 14:02:52 -060077 width = 0;
Stefan Roese7d9cde12015-11-23 07:00:22 +010078 while (ch >= '0' && ch <= '9') {
Simon Glass1fb67602016-05-14 14:02:52 -060079 width = (width * 10) + ch - '0';
Stefan Roese7d9cde12015-11-23 07:00:22 +010080 ch = *fmt++;
81 }
82 }
Simon Glass45313e82016-08-04 21:58:14 -060083 info->bf = buf;
84 p = info->bf;
85 info->zs = 0;
Stefan Roese7d9cde12015-11-23 07:00:22 +010086
87 switch (ch) {
Simon Glass1fb67602016-05-14 14:02:52 -060088 case '\0':
Stefan Roese7d9cde12015-11-23 07:00:22 +010089 goto abort;
90 case 'u':
91 case 'd':
92 num = va_arg(va, unsigned int);
93 if (ch == 'd' && (int)num < 0) {
94 num = -(int)num;
Simon Glass45313e82016-08-04 21:58:14 -060095 out(info, '-');
Stefan Roese7d9cde12015-11-23 07:00:22 +010096 }
Simon Glass74b13202016-01-05 09:30:57 -070097 if (!num) {
Simon Glass45313e82016-08-04 21:58:14 -060098 out_dgt(info, 0);
Simon Glass74b13202016-01-05 09:30:57 -070099 } else {
100 for (div = 1000000000; div; div /= 10)
Simon Glass45313e82016-08-04 21:58:14 -0600101 div_out(info, &num, div);
Simon Glass74b13202016-01-05 09:30:57 -0700102 }
Stefan Roese7d9cde12015-11-23 07:00:22 +0100103 break;
104 case 'x':
Stefan Roese7d9cde12015-11-23 07:00:22 +0100105 num = va_arg(va, unsigned int);
Simon Glass74b13202016-01-05 09:30:57 -0700106 if (!num) {
Simon Glass45313e82016-08-04 21:58:14 -0600107 out_dgt(info, 0);
Simon Glass74b13202016-01-05 09:30:57 -0700108 } else {
109 for (div = 0x10000000; div; div /= 0x10)
Simon Glass45313e82016-08-04 21:58:14 -0600110 div_out(info, &num, div);
Simon Glass74b13202016-01-05 09:30:57 -0700111 }
Stefan Roese7d9cde12015-11-23 07:00:22 +0100112 break;
113 case 'c':
Simon Glass45313e82016-08-04 21:58:14 -0600114 out(info, (char)(va_arg(va, int)));
Stefan Roese7d9cde12015-11-23 07:00:22 +0100115 break;
116 case 's':
117 p = va_arg(va, char*);
118 break;
119 case '%':
Simon Glass45313e82016-08-04 21:58:14 -0600120 out(info, '%');
Stefan Roese7d9cde12015-11-23 07:00:22 +0100121 default:
122 break;
123 }
124
Simon Glass45313e82016-08-04 21:58:14 -0600125 *info->bf = 0;
126 info->bf = p;
127 while (*info->bf++ && width > 0)
Simon Glass1fb67602016-05-14 14:02:52 -0600128 width--;
129 while (width-- > 0)
Simon Glass45313e82016-08-04 21:58:14 -0600130 info->putc(info, lz ? '0' : ' ');
Simon Glass8e316812015-12-29 05:22:46 -0700131 if (p) {
132 while ((ch = *p++))
Simon Glass45313e82016-08-04 21:58:14 -0600133 info->putc(info, ch);
Simon Glass8e316812015-12-29 05:22:46 -0700134 }
Stefan Roese7d9cde12015-11-23 07:00:22 +0100135 }
136 }
137
138abort:
Stefan Roese7d9cde12015-11-23 07:00:22 +0100139 return 0;
140}
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100141
Hans de Goededa70b4d2016-06-10 21:03:34 +0200142int vprintf(const char *fmt, va_list va)
143{
Simon Glass45313e82016-08-04 21:58:14 -0600144 struct printf_info info;
145
146 info.putc = putc_normal;
147 return _vprintf(&info, fmt, va);
Hans de Goededa70b4d2016-06-10 21:03:34 +0200148}
149
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100150int printf(const char *fmt, ...)
151{
Simon Glass45313e82016-08-04 21:58:14 -0600152 struct printf_info info;
153
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100154 va_list va;
155 int ret;
156
Simon Glass45313e82016-08-04 21:58:14 -0600157 info.putc = putc_normal;
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100158 va_start(va, fmt);
Simon Glass45313e82016-08-04 21:58:14 -0600159 ret = _vprintf(&info, fmt, va);
Sjoerd Simons962a43c2015-12-04 23:27:37 +0100160 va_end(va);
161
162 return ret;
163}
Simon Glass5c411d82016-05-14 14:02:53 -0600164
Simon Glass45313e82016-08-04 21:58:14 -0600165static void putc_outstr(struct printf_info *info, char ch)
Simon Glass5c411d82016-05-14 14:02:53 -0600166{
Simon Glass45313e82016-08-04 21:58:14 -0600167 *info->outstr++ = ch;
Simon Glass5c411d82016-05-14 14:02:53 -0600168}
169
Marek Vasutabeb2722016-05-31 23:12:46 +0200170int sprintf(char *buf, const char *fmt, ...)
Simon Glass5c411d82016-05-14 14:02:53 -0600171{
Simon Glass45313e82016-08-04 21:58:14 -0600172 struct printf_info info;
Simon Glass5c411d82016-05-14 14:02:53 -0600173 va_list va;
174 int ret;
175
176 va_start(va, fmt);
Simon Glass45313e82016-08-04 21:58:14 -0600177 info.outstr = buf;
178 info.putc = putc_outstr;
179 ret = _vprintf(&info, fmt, va);
Simon Glass5c411d82016-05-14 14:02:53 -0600180 va_end(va);
Simon Glass45313e82016-08-04 21:58:14 -0600181 *info.outstr = '\0';
Simon Glass5c411d82016-05-14 14:02:53 -0600182
183 return ret;
184}
Marek Vasutabeb2722016-05-31 23:12:46 +0200185
186/* Note that size is ignored */
187int snprintf(char *buf, size_t size, const char *fmt, ...)
188{
Simon Glass45313e82016-08-04 21:58:14 -0600189 struct printf_info info;
Marek Vasutabeb2722016-05-31 23:12:46 +0200190 va_list va;
191 int ret;
192
193 va_start(va, fmt);
Simon Glass45313e82016-08-04 21:58:14 -0600194 info.outstr = buf;
195 info.putc = putc_outstr;
196 ret = _vprintf(&info, fmt, va);
Marek Vasutabeb2722016-05-31 23:12:46 +0200197 va_end(va);
Simon Glass45313e82016-08-04 21:58:14 -0600198 *info.outstr = '\0';
Marek Vasutabeb2722016-05-31 23:12:46 +0200199
200 return ret;
201}
Simon Glasse2409132016-07-04 11:58:13 -0600202
203void __assert_fail(const char *assertion, const char *file, unsigned line,
204 const char *function)
205{
206 /* This will not return */
207 printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
208 assertion);
209 hang();
210}