Sokoban: enable the plugin for the c200. Invent a new, a bit more rockboxish colour...
[kugel-rb.git] / firmware / common / sprintf.c
blob0b3a4f3344f78928d3e5175c1cbc01bfb0a0b7c5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Gary Czvitkovicz
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 * Minimal printf and snprintf formatting functions
23 * These support %c %s %d and %x
24 * Field width and zero-padding flag only
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdbool.h>
30 #include <limits.h>
32 #include "file.h" /* for write(), used in fprintf() */
33 #include "sprintf.h" /* to allow the simulator magic */
35 static const char hexdigit[] = "0123456789ABCDEF";
37 static int format(
38 /* call 'push()' for each output letter */
39 int (*push)(void *userp, unsigned char data),
40 void *userp,
41 const char *fmt,
42 va_list ap)
44 char *str;
45 char tmpbuf[12], pad;
46 int ch, width, val, sign, precision;
47 long lval, lsign;
48 unsigned int uval;
49 unsigned long ulval;
50 bool ok = true;
52 tmpbuf[sizeof tmpbuf - 1] = '\0';
54 while ((ch = *fmt++) != '\0' && ok)
56 if (ch == '%')
58 ch = *fmt++;
59 pad = ' ';
60 if (ch == '0')
61 pad = '0';
63 width = 0;
64 while (ch >= '0' && ch <= '9')
66 width = 10*width + ch - '0';
67 ch = *fmt++;
70 precision = 0;
71 if(ch == '.')
73 ch = *fmt++;
74 while (ch >= '0' && ch <= '9')
76 precision = 10*precision + ch - '0';
77 ch = *fmt++;
79 } else {
80 precision = INT_MAX;
83 str = tmpbuf + sizeof tmpbuf - 1;
84 switch (ch)
86 case 'c':
87 *--str = va_arg (ap, int);
88 break;
90 case 's':
91 str = va_arg (ap, char*);
92 break;
94 case 'd':
95 val = sign = va_arg (ap, int);
96 if (val < 0)
97 val = -val;
100 *--str = (val % 10) + '0';
101 val /= 10;
103 while (val > 0);
104 if (sign < 0)
105 *--str = '-';
106 break;
108 case 'u':
109 uval = va_arg(ap, unsigned int);
112 *--str = (uval % 10) + '0';
113 uval /= 10;
115 while (uval > 0);
116 break;
118 case 'x':
119 case 'X':
120 uval = va_arg (ap, int);
123 *--str = hexdigit[uval & 0xf];
124 uval >>= 4;
126 while (uval);
127 break;
129 case 'l':
130 ch = *fmt++;
131 switch(ch) {
132 case 'x':
133 case 'X':
134 ulval = va_arg (ap, long);
137 *--str = hexdigit[ulval & 0xf];
138 ulval >>= 4;
140 while (ulval);
141 break;
142 case 'd':
143 lval = lsign = va_arg (ap, long);
144 if (lval < 0)
145 lval = -lval;
148 *--str = (lval % 10) + '0';
149 lval /= 10;
151 while (lval > 0);
152 if (lsign < 0)
153 *--str = '-';
154 break;
156 case 'u':
157 ulval = va_arg(ap, unsigned long);
160 *--str = (ulval % 10) + '0';
161 ulval /= 10;
163 while (ulval > 0);
164 break;
166 default:
167 *--str = 'l';
168 *--str = ch;
171 break;
173 default:
174 *--str = ch;
175 break;
178 if (width > 0)
180 width -= strlen (str);
181 while (width-- > 0 && ok)
182 ok=push(userp, pad);
184 while (*str != '\0' && ok && precision--)
185 ok=push(userp, *str++);
187 else
188 ok=push(userp, ch);
190 return ok; /* true means good */
193 #if !defined(SIMULATOR) || !defined(linux)
194 /* ALSA library requires a more advanced snprintf, so let's not
195 override it in simulator for Linux. Note that Cygwin requires
196 our snprintf or it produces garbled output after a while. */
198 struct for_snprintf {
199 unsigned char *ptr; /* where to store it */
200 int bytes; /* amount already stored */
201 int max; /* max amount to store */
204 static int sprfunc(void *ptr, unsigned char letter)
206 struct for_snprintf *pr = (struct for_snprintf *)ptr;
207 if(pr->bytes < pr->max) {
208 *pr->ptr = letter;
209 pr->ptr++;
210 pr->bytes++;
211 return true;
213 return false; /* filled buffer */
217 int snprintf(char *buf, size_t size, const char *fmt, ...)
219 bool ok;
220 va_list ap;
221 struct for_snprintf pr;
223 pr.ptr = (unsigned char *)buf;
224 pr.bytes = 0;
225 pr.max = size;
227 va_start(ap, fmt);
228 ok = format(sprfunc, &pr, fmt, ap);
229 va_end(ap);
231 /* make sure it ends with a trailing zero */
232 pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
234 return pr.bytes;
237 int vsnprintf(char *buf, int size, const char *fmt, va_list ap)
239 bool ok;
240 struct for_snprintf pr;
242 pr.ptr = (unsigned char *)buf;
243 pr.bytes = 0;
244 pr.max = size;
246 ok = format(sprfunc, &pr, fmt, ap);
248 /* make sure it ends with a trailing zero */
249 pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
251 return pr.bytes;
254 #endif /* Linux SIMULATOR */
256 struct for_fprintf {
257 int fd; /* where to store it */
258 int bytes; /* amount stored */
261 static int fprfunc(void *pr, unsigned char letter)
263 struct for_fprintf *fpr = (struct for_fprintf *)pr;
264 int rc = write(fpr->fd, &letter, 1);
266 if(rc > 0) {
267 fpr->bytes++; /* count them */
268 return true; /* we are ok */
271 return false; /* failure */
275 int fdprintf(int fd, const char *fmt, ...)
277 bool ok;
278 va_list ap;
279 struct for_fprintf fpr;
281 fpr.fd=fd;
282 fpr.bytes=0;
284 va_start(ap, fmt);
285 ok = format(fprfunc, &fpr, fmt, ap);
286 va_end(ap);
288 return fpr.bytes; /* return 0 on error */