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