• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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