megadrive_test1

annotate 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
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