megadrive_test1
diff src/libc/printf.c @ 6:862f8a034cae
expanding the megadrive code
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 11 Feb 2017 08:56:42 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/libc/printf.c Sat Feb 11 08:56:42 2017 +0200 1.3 @@ -0,0 +1,323 @@ 1.4 +#include <stdio.h> 1.5 +#include <string.h> 1.6 +#include <stdlib.h> 1.7 +#include <ctype.h> 1.8 +#include <stdarg.h> 1.9 + 1.10 +static void bwrite(char *buf, size_t buf_sz, char *str, int sz); 1.11 +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap); 1.12 +static void itoa(int val, char *buf, int base); 1.13 +static void utoa(unsigned int val, char *buf, int base); 1.14 + 1.15 + 1.16 +int putchar(int c) 1.17 +{ 1.18 + /* TODO */ 1.19 + return c; 1.20 +} 1.21 + 1.22 +int puts(const char *s) 1.23 +{ 1.24 + while(*s) { 1.25 + putchar(*s++); 1.26 + } 1.27 + putchar('\n'); 1.28 + return 0; 1.29 +} 1.30 + 1.31 +/* -- printf and friends -- */ 1.32 + 1.33 +static char *convc = "dioxXucsfeEgGpn%"; 1.34 + 1.35 +#define IS_CONV(c) strchr(convc, c) 1.36 + 1.37 +int printf(const char *fmt, ...) 1.38 +{ 1.39 + int res; 1.40 + va_list ap; 1.41 + 1.42 + va_start(ap, fmt); 1.43 + res = intern_printf(0, 0, fmt, ap); 1.44 + va_end(ap); 1.45 + return res; 1.46 +} 1.47 + 1.48 +int vprintf(const char *fmt, va_list ap) 1.49 +{ 1.50 + return intern_printf(0, 0, fmt, ap); 1.51 +} 1.52 + 1.53 +int sprintf(char *buf, const char *fmt, ...) 1.54 +{ 1.55 + int res; 1.56 + va_list ap; 1.57 + 1.58 + va_start(ap, fmt); 1.59 + res = intern_printf(buf, 0, fmt, ap); 1.60 + va_end(ap); 1.61 + return res; 1.62 +} 1.63 + 1.64 +int vsprintf(char *buf, const char *fmt, va_list ap) 1.65 +{ 1.66 + return intern_printf(buf, 0, fmt, ap); 1.67 +} 1.68 + 1.69 +int snprintf(char *buf, size_t sz, const char *fmt, ...) 1.70 +{ 1.71 + int res; 1.72 + va_list ap; 1.73 + 1.74 + va_start(ap, fmt); 1.75 + res = intern_printf(buf, sz, fmt, ap); 1.76 + va_end(ap); 1.77 + return res; 1.78 +} 1.79 + 1.80 +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap) 1.81 +{ 1.82 + return intern_printf(buf, sz, fmt, ap); 1.83 +} 1.84 + 1.85 + 1.86 +/* intern_printf provides all the functionality needed by all the printf 1.87 + * variants. 1.88 + * - buf: optional buffer onto which the formatted results are written. If null 1.89 + * then the output goes to the terminal through putchar calls. This is used 1.90 + * by the (v)sprintf variants which write to an array of char. 1.91 + * - sz: optional maximum size of the output, 0 means unlimited. This is used 1.92 + * by the (v)snprintf variants to avoid buffer overflows. 1.93 + * The rest are obvious, format string and variable argument list. 1.94 + */ 1.95 + 1.96 +#define BUF(x) ((x) ? (x) + cnum : (x)) 1.97 +#define SZ(x) ((x) ? (x) - cnum : (x)) 1.98 + 1.99 +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap) 1.100 +{ 1.101 + char conv_buf[32]; 1.102 + char *str; 1.103 + int i, slen; 1.104 + const char *fstart = 0; 1.105 + 1.106 + /* state */ 1.107 + int cnum = 0; 1.108 + int base = 10; 1.109 + int alt = 0; 1.110 + int fwidth = 0; 1.111 + int padc = ' '; 1.112 + int sign = 0; 1.113 + int left_align = 0; /* not implemented yet */ 1.114 + int hex_caps = 0; 1.115 + int unsig = 0; 1.116 + 1.117 + while(*fmt) { 1.118 + if(*fmt == '%') { 1.119 + fstart = fmt++; 1.120 + continue; 1.121 + } 1.122 + 1.123 + if(fstart) { 1.124 + if(IS_CONV(*fmt)) { 1.125 + switch(*fmt) { 1.126 + case 'X': 1.127 + hex_caps = 1; 1.128 + 1.129 + case 'x': 1.130 + case 'p': 1.131 + base = 16; 1.132 + 1.133 + if(alt) { 1.134 + bwrite(BUF(buf), SZ(sz), "0x", 2); 1.135 + } 1.136 + 1.137 + case 'u': 1.138 + unsig = 1; 1.139 + 1.140 + if(0) { 1.141 + case 'o': 1.142 + base = 8; 1.143 + 1.144 + if(alt) { 1.145 + bwrite(BUF(buf), SZ(sz), "0", 1); 1.146 + } 1.147 + } 1.148 + 1.149 + case 'd': 1.150 + case 'i': 1.151 + if(unsig) { 1.152 + utoa(va_arg(ap, unsigned int), conv_buf, base); 1.153 + } else { 1.154 + itoa(va_arg(ap, int), conv_buf, base); 1.155 + } 1.156 + if(hex_caps) { 1.157 + for(i=0; conv_buf[i]; i++) { 1.158 + conv_buf[i] = toupper(conv_buf[i]); 1.159 + } 1.160 + } 1.161 + 1.162 + slen = strlen(conv_buf); 1.163 + for(i=slen; i<fwidth; i++) { 1.164 + bwrite(BUF(buf), SZ(sz), (char*)&padc, 1); 1.165 + cnum++; 1.166 + } 1.167 + 1.168 + bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf)); 1.169 + cnum += slen; 1.170 + break; 1.171 + 1.172 + case 'c': 1.173 + { 1.174 + char c = va_arg(ap, int); 1.175 + bwrite(BUF(buf), SZ(sz), &c, 1); 1.176 + cnum++; 1.177 + } 1.178 + break; 1.179 + 1.180 + case 's': 1.181 + str = va_arg(ap, char*); 1.182 + slen = strlen(str); 1.183 + 1.184 + for(i=slen; i<fwidth; i++) { 1.185 + bwrite(BUF(buf), SZ(sz), (char*)&padc, 1); 1.186 + cnum++; 1.187 + } 1.188 + bwrite(BUF(buf), SZ(sz), str, slen); 1.189 + cnum += slen; 1.190 + break; 1.191 + 1.192 + case 'n': 1.193 + *va_arg(ap, int*) = cnum; 1.194 + break; 1.195 + 1.196 + default: 1.197 + break; 1.198 + } 1.199 + 1.200 + /* restore default conversion state */ 1.201 + base = 10; 1.202 + alt = 0; 1.203 + fwidth = 0; 1.204 + padc = ' '; 1.205 + hex_caps = 0; 1.206 + 1.207 + fstart = 0; 1.208 + fmt++; 1.209 + } else { 1.210 + switch(*fmt) { 1.211 + case '#': 1.212 + alt = 1; 1.213 + break; 1.214 + 1.215 + case '+': 1.216 + sign = 1; 1.217 + break; 1.218 + 1.219 + case '-': 1.220 + left_align = 1; 1.221 + break; 1.222 + 1.223 + case 'l': 1.224 + case 'L': 1.225 + break; 1.226 + 1.227 + case '0': 1.228 + padc = '0'; 1.229 + break; 1.230 + 1.231 + default: 1.232 + if(isdigit(*fmt)) { 1.233 + const char *fw = fmt; 1.234 + while(*fmt && isdigit(*fmt)) fmt++; 1.235 + 1.236 + fwidth = atoi(fw); 1.237 + continue; 1.238 + } 1.239 + } 1.240 + fmt++; 1.241 + } 1.242 + } else { 1.243 + bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1); 1.244 + cnum++; 1.245 + } 1.246 + } 1.247 + 1.248 + return 0; 1.249 +} 1.250 + 1.251 + 1.252 +/* bwrite is called by intern_printf to transparently handle writing into a 1.253 + * buffer (if buf is non-null) or to the terminal (if buf is null). 1.254 + */ 1.255 +static void bwrite(char *buf, size_t buf_sz, char *str, int sz) 1.256 +{ 1.257 + if(buf) { 1.258 + if(buf_sz && buf_sz <= sz) sz = buf_sz - 1; 1.259 + memcpy(buf, str, sz); 1.260 + 1.261 + buf[sz] = 0; 1.262 + } else { 1.263 + int i; 1.264 + for(i=0; i<sz; i++) { 1.265 + putchar(*str++); 1.266 + } 1.267 + } 1.268 +} 1.269 + 1.270 + 1.271 +static void itoa(int val, char *buf, int base) 1.272 +{ 1.273 + static char rbuf[16]; 1.274 + char *ptr = rbuf; 1.275 + int neg = 0; 1.276 + 1.277 + if(val < 0) { 1.278 + neg = 1; 1.279 + val = -val; 1.280 + } 1.281 + 1.282 + if(val == 0) { 1.283 + *ptr++ = '0'; 1.284 + } 1.285 + 1.286 + while(val) { 1.287 + int digit = val % base; 1.288 + *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a'); 1.289 + val /= base; 1.290 + } 1.291 + 1.292 + if(neg) { 1.293 + *ptr++ = '-'; 1.294 + } 1.295 + 1.296 + ptr--; 1.297 + 1.298 + while(ptr >= rbuf) { 1.299 + *buf++ = *ptr--; 1.300 + } 1.301 + *buf = 0; 1.302 +} 1.303 + 1.304 +static void utoa(unsigned int val, char *buf, int base) 1.305 +{ 1.306 + static char rbuf[16]; 1.307 + char *ptr = rbuf; 1.308 + 1.309 + if(val == 0) { 1.310 + *ptr++ = '0'; 1.311 + } 1.312 + 1.313 + while(val) { 1.314 + unsigned int digit = val % base; 1.315 + *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a'); 1.316 + val /= base; 1.317 + } 1.318 + 1.319 + ptr--; 1.320 + 1.321 + while(ptr >= rbuf) { 1.322 + *buf++ = *ptr--; 1.323 + } 1.324 + *buf = 0; 1.325 +} 1.326 +