Correct yet another typo causing reds and greater shame on me.
[kugel-rb/myfork.git] / firmware / common / sprintf.c
blob0f012f7340d9e46dc28eaf9db59ae25c1b76af4f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Gary Czvitkovicz
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * Minimal printf and snprintf formatting functions
25 * These support %c %s %d and %x
26 * Field width and zero-padding flag only
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdbool.h>
32 #include <limits.h>
34 #include "file.h" /* for write(), used in fprintf() */
35 #include "sprintf.h" /* to allow the simulator magic */
37 static const char hexdigit[] = "0123456789ABCDEF";
39 static int format(
40 /* call 'push()' for each output letter */
41 int (*push)(void *userp, unsigned char data),
42 void *userp,
43 const char *fmt,
44 va_list ap)
46 char *str;
47 char tmpbuf[12], pad;
48 int ch, width, val, sign, precision;
49 long lval, lsign;
50 unsigned int uval;
51 unsigned long ulval;
52 bool ok = true;
54 tmpbuf[sizeof tmpbuf - 1] = '\0';
56 while ((ch = *fmt++) != '\0' && ok)
58 if (ch == '%')
60 ch = *fmt++;
61 pad = ' ';
62 if (ch == '0')
63 pad = '0';
65 width = 0;
66 while (ch >= '0' && ch <= '9')
68 width = 10*width + ch - '0';
69 ch = *fmt++;
72 precision = 0;
73 if(ch == '.')
75 ch = *fmt++;
76 while (ch >= '0' && ch <= '9')
78 precision = 10*precision + ch - '0';
79 ch = *fmt++;
81 } else {
82 precision = INT_MAX;
85 str = tmpbuf + sizeof tmpbuf - 1;
86 switch (ch)
88 case 'c':
89 *--str = va_arg (ap, int);
90 break;
92 case 's':
93 str = va_arg (ap, char*);
94 break;
96 case 'd':
97 val = sign = va_arg (ap, int);
98 if (val < 0)
99 val = -val;
102 *--str = (val % 10) + '0';
103 val /= 10;
105 while (val > 0);
106 if (sign < 0)
107 *--str = '-';
108 break;
110 case 'u':
111 uval = va_arg(ap, unsigned int);
114 *--str = (uval % 10) + '0';
115 uval /= 10;
117 while (uval > 0);
118 break;
120 case 'x':
121 case 'X':
122 pad='0';
123 uval = va_arg (ap, int);
126 *--str = hexdigit[uval & 0xf];
127 uval >>= 4;
129 while (uval);
130 break;
132 case 'l':
133 ch = *fmt++;
134 switch(ch) {
135 case 'x':
136 case 'X':
137 pad='0';
138 ulval = va_arg (ap, long);
141 *--str = hexdigit[ulval & 0xf];
142 ulval >>= 4;
144 while (ulval);
145 break;
146 case 'd':
147 lval = lsign = va_arg (ap, long);
148 if (lval < 0)
149 lval = -lval;
152 *--str = (lval % 10) + '0';
153 lval /= 10;
155 while (lval > 0);
156 if (lsign < 0)
157 *--str = '-';
158 break;
160 case 'u':
161 ulval = va_arg(ap, unsigned long);
164 *--str = (ulval % 10) + '0';
165 ulval /= 10;
167 while (ulval > 0);
168 break;
170 default:
171 *--str = 'l';
172 *--str = ch;
175 break;
177 default:
178 *--str = ch;
179 break;
182 if (width > 0)
184 width -= strlen (str);
185 while (width-- > 0 && ok)
186 ok=push(userp, pad);
188 while (*str != '\0' && ok && precision--)
189 ok=push(userp, *str++);
191 else
192 ok=push(userp, ch);
194 return ok; /* true means good */
197 #if !defined(SIMULATOR) || !defined(linux)
198 /* ALSA library requires a more advanced snprintf, so let's not
199 override it in simulator for Linux. Note that Cygwin requires
200 our snprintf or it produces garbled output after a while. */
202 struct for_snprintf {
203 unsigned char *ptr; /* where to store it */
204 int bytes; /* amount already stored */
205 int max; /* max amount to store */
208 static int sprfunc(void *ptr, unsigned char letter)
210 struct for_snprintf *pr = (struct for_snprintf *)ptr;
211 if(pr->bytes < pr->max) {
212 *pr->ptr = letter;
213 pr->ptr++;
214 pr->bytes++;
215 return true;
217 return false; /* filled buffer */
221 int snprintf(char *buf, size_t size, const char *fmt, ...)
223 bool ok;
224 va_list ap;
225 struct for_snprintf pr;
227 pr.ptr = (unsigned char *)buf;
228 pr.bytes = 0;
229 pr.max = size;
231 va_start(ap, fmt);
232 ok = format(sprfunc, &pr, fmt, ap);
233 va_end(ap);
235 /* make sure it ends with a trailing zero */
236 pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
238 return pr.bytes;
241 int vsnprintf(char *buf, int size, const char *fmt, va_list ap)
243 bool ok;
244 struct for_snprintf pr;
246 pr.ptr = (unsigned char *)buf;
247 pr.bytes = 0;
248 pr.max = size;
250 ok = format(sprfunc, &pr, fmt, ap);
252 /* make sure it ends with a trailing zero */
253 pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0';
255 return pr.bytes;
258 #endif /* Linux SIMULATOR */
260 struct for_fprintf {
261 int fd; /* where to store it */
262 int bytes; /* amount stored */
265 static int fprfunc(void *pr, unsigned char letter)
267 struct for_fprintf *fpr = (struct for_fprintf *)pr;
268 int rc = write(fpr->fd, &letter, 1);
270 if(rc > 0) {
271 fpr->bytes++; /* count them */
272 return true; /* we are ok */
275 return false; /* failure */
279 int fdprintf(int fd, const char *fmt, ...)
281 bool ok;
282 va_list ap;
283 struct for_fprintf fpr;
285 fpr.fd=fd;
286 fpr.bytes=0;
288 va_start(ap, fmt);
289 ok = format(fprfunc, &fpr, fmt, ap);
290 va_end(ap);
292 return fpr.bytes; /* return 0 on error */