1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 ******************************************************************************/
22
23
24 #include <string.h>
25 #include "lib/tinyput.h"
26
27
28 /*
29 * Simple formatted output routine.
30 * Designed primarily for small size (and secondarily for efficiency).
31 * Only a common subset of printf formats and options are handled:
32 *
33 * %[-+ ][0][width]i decimal signed integer
34 * %[-+ ][0][width]d decimal signed integer
35 * %[-][0][width]u decimal unsigned integer
36 * %[-][0][width]x hex unsigned integer
37 * %[-][0][width]p hex unsigned integer with 0x prefix ("pointer")
38 * %[-][width]c single character
39 * %[-][width]s string
40 *
41 * These modifiers are ignored (legally on 32-bit Xtensa):
42 * # (alternate format)
43 * h (short) expands to int on 32-bit Xtensa
44 * l (long) same as int on 32-bit Xtensa
45 * j (intmax_t or uintmax_t) same as int on 32-bit Xtensa
46 * z (size_t or ssize_t) same as int on 32-bit Xtensa
47 * t (ptrdiff_t) same as int on 32-bit Xtensa
48 *
49 * Does NOT support:
50 * width.prec (precision modifier)
51 * %X (capitalized hex; handles this as lowercase hex)
52 * %o (octal)
53 * %[L][feEgG] (floating point formats)
54 * %a %A (hex floating point formats, C99)
55 * %C (multibyte character)
56 * %S (multibyte character string)
57 * %n (returning count of character written)
58 * ll (long long)
59 * q j z t (other size modifiers, eg. see glibc)
60 */
tiny_vsprintf(char * out,const char * fmt,va_list ap)61 int tiny_vsprintf(char *out, const char *fmt, va_list ap)
62 {
63 int total = 0;
64 char c, space = ' ', buf[11]; /* largest 32-bit integer output (octal) */
65
66 while ((c = *(char*)fmt++) != 0) {
67 if (c != '%') {
68 *out++ = c;
69 total++;
70 } else {
71 int width = 0, len = 1, rightjust = 1;
72 unsigned n;
73 char *s = buf, *t, pad = ' ', sign = 0;
74 while (1) {
75 c = *(char*)fmt++;
76 switch (c) {
77 case 'c': buf[0] = va_arg(ap, int); goto donefmt;
78 case 's': s = va_arg(ap, char*);
79 if (s == 0)
80 len = 0;
81 else {
82 for (t = s; *t; t++) ;
83 len = t - s;
84 }
85 goto donefmt;
86
87 case '#': /* ignore (not supported) */
88 case 'h': /* ignore (short; passed as int) */
89 case 'l': /* ignore (long; same as int) */
90 case 'j': /* ignore (intmax_t or uintmax_t; same as int) */
91 case 'z': /* ignore (size_t or ssize_t; same as int) */
92 case 't': /* ignore (ptrdiff_t; same as int) */
93 break;
94
95 case ' ': sign = ' '; break;
96 case '+': sign = '+'; break;
97 case '-': rightjust = 0; break;
98
99 case 'i': /*FALLTHROUGH*/
100 case 'd': n = va_arg(ap, int);
101 if ((int)n < 0) {
102 sign = '-';
103 n = -(int)n;
104 }
105 if (sign) {
106 if (rightjust && pad == ' ')
107 *s++ = sign;
108 else {
109 *out++ = sign;
110 width--;
111 total++;
112 }
113 }
114 goto do_decimal;
115 case 'u': n = va_arg(ap, int);
116 do_decimal:
117 {
118 /* (avoids division or multiplication) */
119 int digit, i, seen = 0;
120 for (digit = 0; n >= 1000000000; digit++)
121 n -= 1000000000;
122 for (i = 9;;) {
123 if (!seen && digit != 0)
124 seen = i;
125 if (seen)
126 *s++ = '0' + digit;
127 for (digit = 0; n >= 100000000; digit++)
128 n -= 100000000;
129 if (--i == 0) {
130 *s++ = '0' + digit;
131 len = s - buf;
132 s = buf;
133 goto donefmt;
134 }
135 n = ((n << 1) + (n << 3));
136 }
137 }
138 /*NOTREACHED*/
139
140 #if 0
141 case 'o': n = va_arg(ap, unsigned);
142 s = buf + 11;
143 do {
144 *--s = '0' + (n & 7);
145 n = (unsigned)n >> 3;
146 } while (n);
147 len = buf + 11 - s;
148 goto donefmt;
149 #endif
150
151 case 'p': *out++ = '0', *out++ = 'x';
152 total += 2;
153 /*FALLTHROUGH*/
154 case 'X': /*FALLTHROUGH*/
155 case 'x': n = va_arg(ap, unsigned);
156 s = buf + 8;
157 do {
158 *--s = "0123456789abcdef"[n & 0xF];
159 n = (unsigned)n >> 4;
160 } while (n);
161 len = buf + 8 - s;
162 goto donefmt;
163
164 case 0: goto done;
165 case '0': if (width == 0) pad = '0'; /*FALLTHROUGH*/
166 default: if (c >= '0' && c <= '9')
167 width = ((width<<1) + (width<<3)) + (c - '0');
168 else {
169 buf[0] = c; /* handles case of '%' */
170 goto donefmt;
171 }
172 }
173 }
174 /*NOTREACHED*/
175 donefmt:
176 if (len < width) {
177 total += width;
178 if (rightjust)
179 do { *out++ = pad; } while (len < --width);
180 } else
181 total += len;
182 for(n = len; n > 0; n--) *out++ = *s++;
183 for (; len < width; len++) *out++ = space;
184 }
185 }
186 done:
187 return total;
188 }
189
tiny_sprintf(char * out,const char * fmt,...)190 int tiny_sprintf(char *out, const char *fmt, ...)
191 {
192 int n = 0;
193 va_list ap;
194 va_start(ap, fmt);
195 n = tiny_vsprintf(out, fmt, ap);
196 va_end(ap);
197 return n;
198 }
199