rev |
line source |
nuclear@6
|
1 #include <stdio.h>
|
nuclear@6
|
2 #include <string.h>
|
nuclear@6
|
3 #include <stdlib.h>
|
nuclear@6
|
4 #include <ctype.h>
|
nuclear@6
|
5 #include <stdarg.h>
|
nuclear@6
|
6
|
nuclear@6
|
7 static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
|
nuclear@6
|
8 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
|
nuclear@6
|
9 static void itoa(int val, char *buf, int base);
|
nuclear@6
|
10 static void utoa(unsigned int val, char *buf, int base);
|
nuclear@6
|
11
|
nuclear@6
|
12
|
nuclear@6
|
13 int putchar(int c)
|
nuclear@6
|
14 {
|
nuclear@6
|
15 /* TODO */
|
nuclear@6
|
16 return c;
|
nuclear@6
|
17 }
|
nuclear@6
|
18
|
nuclear@6
|
19 int puts(const char *s)
|
nuclear@6
|
20 {
|
nuclear@6
|
21 while(*s) {
|
nuclear@6
|
22 putchar(*s++);
|
nuclear@6
|
23 }
|
nuclear@6
|
24 putchar('\n');
|
nuclear@6
|
25 return 0;
|
nuclear@6
|
26 }
|
nuclear@6
|
27
|
nuclear@6
|
28 /* -- printf and friends -- */
|
nuclear@6
|
29
|
nuclear@6
|
30 static char *convc = "dioxXucsfeEgGpn%";
|
nuclear@6
|
31
|
nuclear@6
|
32 #define IS_CONV(c) strchr(convc, c)
|
nuclear@6
|
33
|
nuclear@6
|
34 int printf(const char *fmt, ...)
|
nuclear@6
|
35 {
|
nuclear@6
|
36 int res;
|
nuclear@6
|
37 va_list ap;
|
nuclear@6
|
38
|
nuclear@6
|
39 va_start(ap, fmt);
|
nuclear@6
|
40 res = intern_printf(0, 0, fmt, ap);
|
nuclear@6
|
41 va_end(ap);
|
nuclear@6
|
42 return res;
|
nuclear@6
|
43 }
|
nuclear@6
|
44
|
nuclear@6
|
45 int vprintf(const char *fmt, va_list ap)
|
nuclear@6
|
46 {
|
nuclear@6
|
47 return intern_printf(0, 0, fmt, ap);
|
nuclear@6
|
48 }
|
nuclear@6
|
49
|
nuclear@6
|
50 int sprintf(char *buf, const char *fmt, ...)
|
nuclear@6
|
51 {
|
nuclear@6
|
52 int res;
|
nuclear@6
|
53 va_list ap;
|
nuclear@6
|
54
|
nuclear@6
|
55 va_start(ap, fmt);
|
nuclear@6
|
56 res = intern_printf(buf, 0, fmt, ap);
|
nuclear@6
|
57 va_end(ap);
|
nuclear@6
|
58 return res;
|
nuclear@6
|
59 }
|
nuclear@6
|
60
|
nuclear@6
|
61 int vsprintf(char *buf, const char *fmt, va_list ap)
|
nuclear@6
|
62 {
|
nuclear@6
|
63 return intern_printf(buf, 0, fmt, ap);
|
nuclear@6
|
64 }
|
nuclear@6
|
65
|
nuclear@6
|
66 int snprintf(char *buf, size_t sz, const char *fmt, ...)
|
nuclear@6
|
67 {
|
nuclear@6
|
68 int res;
|
nuclear@6
|
69 va_list ap;
|
nuclear@6
|
70
|
nuclear@6
|
71 va_start(ap, fmt);
|
nuclear@6
|
72 res = intern_printf(buf, sz, fmt, ap);
|
nuclear@6
|
73 va_end(ap);
|
nuclear@6
|
74 return res;
|
nuclear@6
|
75 }
|
nuclear@6
|
76
|
nuclear@6
|
77 int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
|
nuclear@6
|
78 {
|
nuclear@6
|
79 return intern_printf(buf, sz, fmt, ap);
|
nuclear@6
|
80 }
|
nuclear@6
|
81
|
nuclear@6
|
82
|
nuclear@6
|
83 /* intern_printf provides all the functionality needed by all the printf
|
nuclear@6
|
84 * variants.
|
nuclear@6
|
85 * - buf: optional buffer onto which the formatted results are written. If null
|
nuclear@6
|
86 * then the output goes to the terminal through putchar calls. This is used
|
nuclear@6
|
87 * by the (v)sprintf variants which write to an array of char.
|
nuclear@6
|
88 * - sz: optional maximum size of the output, 0 means unlimited. This is used
|
nuclear@6
|
89 * by the (v)snprintf variants to avoid buffer overflows.
|
nuclear@6
|
90 * The rest are obvious, format string and variable argument list.
|
nuclear@6
|
91 */
|
nuclear@6
|
92
|
nuclear@6
|
93 #define BUF(x) ((x) ? (x) + cnum : (x))
|
nuclear@6
|
94 #define SZ(x) ((x) ? (x) - cnum : (x))
|
nuclear@6
|
95
|
nuclear@6
|
96 static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
|
nuclear@6
|
97 {
|
nuclear@6
|
98 char conv_buf[32];
|
nuclear@6
|
99 char *str;
|
nuclear@6
|
100 int i, slen;
|
nuclear@6
|
101 const char *fstart = 0;
|
nuclear@6
|
102
|
nuclear@6
|
103 /* state */
|
nuclear@6
|
104 int cnum = 0;
|
nuclear@6
|
105 int base = 10;
|
nuclear@6
|
106 int alt = 0;
|
nuclear@6
|
107 int fwidth = 0;
|
nuclear@6
|
108 int padc = ' ';
|
nuclear@6
|
109 int sign = 0;
|
nuclear@6
|
110 int left_align = 0; /* not implemented yet */
|
nuclear@6
|
111 int hex_caps = 0;
|
nuclear@6
|
112 int unsig = 0;
|
nuclear@6
|
113
|
nuclear@6
|
114 while(*fmt) {
|
nuclear@6
|
115 if(*fmt == '%') {
|
nuclear@6
|
116 fstart = fmt++;
|
nuclear@6
|
117 continue;
|
nuclear@6
|
118 }
|
nuclear@6
|
119
|
nuclear@6
|
120 if(fstart) {
|
nuclear@6
|
121 if(IS_CONV(*fmt)) {
|
nuclear@6
|
122 switch(*fmt) {
|
nuclear@6
|
123 case 'X':
|
nuclear@6
|
124 hex_caps = 1;
|
nuclear@6
|
125
|
nuclear@6
|
126 case 'x':
|
nuclear@6
|
127 case 'p':
|
nuclear@6
|
128 base = 16;
|
nuclear@6
|
129
|
nuclear@6
|
130 if(alt) {
|
nuclear@6
|
131 bwrite(BUF(buf), SZ(sz), "0x", 2);
|
nuclear@6
|
132 }
|
nuclear@6
|
133
|
nuclear@6
|
134 case 'u':
|
nuclear@6
|
135 unsig = 1;
|
nuclear@6
|
136
|
nuclear@6
|
137 if(0) {
|
nuclear@6
|
138 case 'o':
|
nuclear@6
|
139 base = 8;
|
nuclear@6
|
140
|
nuclear@6
|
141 if(alt) {
|
nuclear@6
|
142 bwrite(BUF(buf), SZ(sz), "0", 1);
|
nuclear@6
|
143 }
|
nuclear@6
|
144 }
|
nuclear@6
|
145
|
nuclear@6
|
146 case 'd':
|
nuclear@6
|
147 case 'i':
|
nuclear@6
|
148 if(unsig) {
|
nuclear@6
|
149 utoa(va_arg(ap, unsigned int), conv_buf, base);
|
nuclear@6
|
150 } else {
|
nuclear@6
|
151 itoa(va_arg(ap, int), conv_buf, base);
|
nuclear@6
|
152 }
|
nuclear@6
|
153 if(hex_caps) {
|
nuclear@6
|
154 for(i=0; conv_buf[i]; i++) {
|
nuclear@6
|
155 conv_buf[i] = toupper(conv_buf[i]);
|
nuclear@6
|
156 }
|
nuclear@6
|
157 }
|
nuclear@6
|
158
|
nuclear@6
|
159 slen = strlen(conv_buf);
|
nuclear@6
|
160 for(i=slen; i<fwidth; i++) {
|
nuclear@6
|
161 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
|
nuclear@6
|
162 cnum++;
|
nuclear@6
|
163 }
|
nuclear@6
|
164
|
nuclear@6
|
165 bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
|
nuclear@6
|
166 cnum += slen;
|
nuclear@6
|
167 break;
|
nuclear@6
|
168
|
nuclear@6
|
169 case 'c':
|
nuclear@6
|
170 {
|
nuclear@6
|
171 char c = va_arg(ap, int);
|
nuclear@6
|
172 bwrite(BUF(buf), SZ(sz), &c, 1);
|
nuclear@6
|
173 cnum++;
|
nuclear@6
|
174 }
|
nuclear@6
|
175 break;
|
nuclear@6
|
176
|
nuclear@6
|
177 case 's':
|
nuclear@6
|
178 str = va_arg(ap, char*);
|
nuclear@6
|
179 slen = strlen(str);
|
nuclear@6
|
180
|
nuclear@6
|
181 for(i=slen; i<fwidth; i++) {
|
nuclear@6
|
182 bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
|
nuclear@6
|
183 cnum++;
|
nuclear@6
|
184 }
|
nuclear@6
|
185 bwrite(BUF(buf), SZ(sz), str, slen);
|
nuclear@6
|
186 cnum += slen;
|
nuclear@6
|
187 break;
|
nuclear@6
|
188
|
nuclear@6
|
189 case 'n':
|
nuclear@6
|
190 *va_arg(ap, int*) = cnum;
|
nuclear@6
|
191 break;
|
nuclear@6
|
192
|
nuclear@6
|
193 default:
|
nuclear@6
|
194 break;
|
nuclear@6
|
195 }
|
nuclear@6
|
196
|
nuclear@6
|
197 /* restore default conversion state */
|
nuclear@6
|
198 base = 10;
|
nuclear@6
|
199 alt = 0;
|
nuclear@6
|
200 fwidth = 0;
|
nuclear@6
|
201 padc = ' ';
|
nuclear@6
|
202 hex_caps = 0;
|
nuclear@6
|
203
|
nuclear@6
|
204 fstart = 0;
|
nuclear@6
|
205 fmt++;
|
nuclear@6
|
206 } else {
|
nuclear@6
|
207 switch(*fmt) {
|
nuclear@6
|
208 case '#':
|
nuclear@6
|
209 alt = 1;
|
nuclear@6
|
210 break;
|
nuclear@6
|
211
|
nuclear@6
|
212 case '+':
|
nuclear@6
|
213 sign = 1;
|
nuclear@6
|
214 break;
|
nuclear@6
|
215
|
nuclear@6
|
216 case '-':
|
nuclear@6
|
217 left_align = 1;
|
nuclear@6
|
218 break;
|
nuclear@6
|
219
|
nuclear@6
|
220 case 'l':
|
nuclear@6
|
221 case 'L':
|
nuclear@6
|
222 break;
|
nuclear@6
|
223
|
nuclear@6
|
224 case '0':
|
nuclear@6
|
225 padc = '0';
|
nuclear@6
|
226 break;
|
nuclear@6
|
227
|
nuclear@6
|
228 default:
|
nuclear@6
|
229 if(isdigit(*fmt)) {
|
nuclear@6
|
230 const char *fw = fmt;
|
nuclear@6
|
231 while(*fmt && isdigit(*fmt)) fmt++;
|
nuclear@6
|
232
|
nuclear@6
|
233 fwidth = atoi(fw);
|
nuclear@6
|
234 continue;
|
nuclear@6
|
235 }
|
nuclear@6
|
236 }
|
nuclear@6
|
237 fmt++;
|
nuclear@6
|
238 }
|
nuclear@6
|
239 } else {
|
nuclear@6
|
240 bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
|
nuclear@6
|
241 cnum++;
|
nuclear@6
|
242 }
|
nuclear@6
|
243 }
|
nuclear@6
|
244
|
nuclear@6
|
245 return 0;
|
nuclear@6
|
246 }
|
nuclear@6
|
247
|
nuclear@6
|
248
|
nuclear@6
|
249 /* bwrite is called by intern_printf to transparently handle writing into a
|
nuclear@6
|
250 * buffer (if buf is non-null) or to the terminal (if buf is null).
|
nuclear@6
|
251 */
|
nuclear@6
|
252 static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
|
nuclear@6
|
253 {
|
nuclear@6
|
254 if(buf) {
|
nuclear@6
|
255 if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
|
nuclear@6
|
256 memcpy(buf, str, sz);
|
nuclear@6
|
257
|
nuclear@6
|
258 buf[sz] = 0;
|
nuclear@6
|
259 } else {
|
nuclear@6
|
260 int i;
|
nuclear@6
|
261 for(i=0; i<sz; i++) {
|
nuclear@6
|
262 putchar(*str++);
|
nuclear@6
|
263 }
|
nuclear@6
|
264 }
|
nuclear@6
|
265 }
|
nuclear@6
|
266
|
nuclear@6
|
267
|
nuclear@6
|
268 static void itoa(int val, char *buf, int base)
|
nuclear@6
|
269 {
|
nuclear@6
|
270 static char rbuf[16];
|
nuclear@6
|
271 char *ptr = rbuf;
|
nuclear@6
|
272 int neg = 0;
|
nuclear@6
|
273
|
nuclear@6
|
274 if(val < 0) {
|
nuclear@6
|
275 neg = 1;
|
nuclear@6
|
276 val = -val;
|
nuclear@6
|
277 }
|
nuclear@6
|
278
|
nuclear@6
|
279 if(val == 0) {
|
nuclear@6
|
280 *ptr++ = '0';
|
nuclear@6
|
281 }
|
nuclear@6
|
282
|
nuclear@6
|
283 while(val) {
|
nuclear@6
|
284 int digit = val % base;
|
nuclear@6
|
285 *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
|
nuclear@6
|
286 val /= base;
|
nuclear@6
|
287 }
|
nuclear@6
|
288
|
nuclear@6
|
289 if(neg) {
|
nuclear@6
|
290 *ptr++ = '-';
|
nuclear@6
|
291 }
|
nuclear@6
|
292
|
nuclear@6
|
293 ptr--;
|
nuclear@6
|
294
|
nuclear@6
|
295 while(ptr >= rbuf) {
|
nuclear@6
|
296 *buf++ = *ptr--;
|
nuclear@6
|
297 }
|
nuclear@6
|
298 *buf = 0;
|
nuclear@6
|
299 }
|
nuclear@6
|
300
|
nuclear@6
|
301 static void utoa(unsigned int val, char *buf, int base)
|
nuclear@6
|
302 {
|
nuclear@6
|
303 static char rbuf[16];
|
nuclear@6
|
304 char *ptr = rbuf;
|
nuclear@6
|
305
|
nuclear@6
|
306 if(val == 0) {
|
nuclear@6
|
307 *ptr++ = '0';
|
nuclear@6
|
308 }
|
nuclear@6
|
309
|
nuclear@6
|
310 while(val) {
|
nuclear@6
|
311 unsigned int digit = val % base;
|
nuclear@6
|
312 *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
|
nuclear@6
|
313 val /= base;
|
nuclear@6
|
314 }
|
nuclear@6
|
315
|
nuclear@6
|
316 ptr--;
|
nuclear@6
|
317
|
nuclear@6
|
318 while(ptr >= rbuf) {
|
nuclear@6
|
319 *buf++ = *ptr--;
|
nuclear@6
|
320 }
|
nuclear@6
|
321 *buf = 0;
|
nuclear@6
|
322 }
|
nuclear@6
|
323
|