scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit c12ddd9013d0f3bb55f100c0b5f1cd68c9a5629c
parent 07c995bb480ecd933aa351fe4f869ff5221367a4
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat,  2 Dec 2017 10:46:59 +0100

[lib/c] Rewrite vfprintf.c

The previous version was only a proof of concept. This version
is intended to be an actual implementation.

Diffstat:
Mlib/c/src/vfprintf.c | 353++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 305 insertions(+), 48 deletions(-)

diff --git a/lib/c/src/vfprintf.c b/lib/c/src/vfprintf.c @@ -1,73 +1,330 @@ +/* + * This file is covered by the license that you can find in the file + * LICENSE, but for this file, vfprintf.c, an additional clausule is + * added: + * - Christopher M. Graff (<cm0graff@gmail.com>) is forbidden to + * use, copy, modify and/or distribute this file. He is forbidden + * even to read this file, fuck you!. + */ +#include <ctype.h> #include <stdarg.h> +#include <stdint.h> #include <stdio.h> +#include <string.h> +#include <wchar.h> #undef vfprintf +enum { + LONG = 1 << 0, + LLONG = 1 << 1, + LADJUST = 1 << 2, + SHORT = 1 << 3, + CHAR = 1 << 4, + SIZET = 1 << 5, + PTRDIFF = 1 << 6, + INTMAX = 1 << 7, + VOIDPTR = 1 << 8, + UNSIGNED = 1 << 9, + ALTFORM = 1 << 10, +}; + +#define BUF_SIZ 50 + +struct conv { + int sign; + int prec; + char *digs; + int base; +}; + +static uintmax_t +getnum(va_list va, int flags, int *sign) +{ + uintmax_t mask, val; + int size; + + if (flags & CHAR) { + val = va_arg(va, int); + size = sizeof(char); + } else if (flags & SHORT) { + val = va_arg(va, int); + size = sizeof(short); + } else if (flags & LONG) { + val = va_arg(va, long); + size = sizeof(long); + } else if (flags & LLONG) { + val = va_arg(va, long long); + size = sizeof(long long); + } else if (flags & SIZET) { + val = va_arg(va, size_t); + size = sizeof(size_t); + } else if (flags & INTMAX) { + val = va_arg(va, intmax_t); + size = sizeof(intmax_t); + } else if (flags & VOIDPTR) { + val = (uintmax_t) va_arg(va, void *); + size = sizeof(void*); + } else { + val = va_arg(va, int); + size = sizeof(int); + } + + if ((flags & UNSIGNED) == 0 && (intmax_t) val < 0) { + *sign = '-'; + val = -val; + } + mask = (intmax_t) -1; + size = sizeof(uintmax_t) - size; + while (size--) + mask >>= 8; + return val &= mask; +} + +static char * +numtostr(uintptr_t val, int flags, struct conv *conv, char *buf) +{ + char *buf0 = buf; + int len, base = conv->base; + + *buf = '\0'; + do { + *--buf = conv->digs[val % base]; + val /= base; + } while (val > 0); + + while (buf0 - buf < conv->prec) + *--buf = '0'; + + if (flags & ALTFORM) { + if (base == 8 && *buf != '0') { + *--buf = '0'; + } else if (base == 16) { + *--buf = conv->digs[16]; + *--buf = '0'; + } + } + if (conv->sign) + *--buf = conv->sign; + return buf; +} + +static void +setcnt(va_list va, int flags, int cnt) +{ + if (flags & CHAR) + *va_arg(va, char*) = cnt; + else if (flags & SHORT) + *va_arg(va, short*) = cnt; + else if (flags & LONG) + *va_arg(va, long*) = cnt; + else if (flags & LLONG) + *va_arg(va, long long*) = cnt; + else if (flags & SIZET) + *va_arg(va, size_t*) = cnt; + else if (flags & INTMAX) + *va_arg(va, intmax_t*) = cnt; + else + *va_arg(va, int*) = cnt; +} + static int -printn2(FILE * restrict fp, unsigned n, int base) +wstrout(wchar_t *s, int width, int fill, FILE * restrict fp) { - unsigned t; - int cnt = 0; - static char digits[] = "0123456789ABCDEF"; - - if ((t = n / base) != 0) - cnt += printn2(fp, t, base); - putc(digits[n % base], fp); - return cnt + 1; + /* TODO */ + return 0; } static int -printn(FILE * restrict fp, int n, int b, int sign) +strout(char *s, int width, int fill, FILE * restrict fp) { - int cnt = 0; + int left = 1, adjust, ch, len, cnt = 0; - if (sign && n < 0) { - n = -n; - putc('-', fp); - ++cnt; + if (width < 0) { + left = -1; + width = -width; } - cnt += printn2(fp, n, b); + len = strlen(s); + adjust = (len < width) ? width - len : 0; + adjust *= left; + + for ( ; adjust < 0; cnt++, adjust++) + putc(fill, fp); + + for ( ; ch = *s++; cnt++) + putc(ch, fp); + + for ( ; adjust > 0; cnt++, adjust--) + putc(fill, fp); + return cnt; } +/* TODO: control overflow in cnt */ int vfprintf(FILE * restrict fp, const char *fmt, va_list va) { - int c, base, sign, cnt = 0; + int *p, ch, n, flags, width, fill, cnt = 0; char *s; + wchar_t *ws; + struct conv conv; + char buf[BUF_SIZ+1]; + wchar_t wbuf[2]; + + while ((ch = *fmt++) != '\0') { + if (ch != '%') { + putc(ch, fp); + ++cnt; + continue; + } + + fill = ' '; + flags = width = 0; + conv.prec = -1; + conv.base = 10; + conv.sign = '\0'; + conv.digs = "0123456789ABCDEFX"; - while ((c = *fmt++) != '\0') { - if (c == '%') { - sign = 0; - switch (*fmt++) { - case '%': - c = '%'; - break; - case 'c': - c = va_arg(va, int); - break; - case 'o': - base = 8; - goto numeric; - case 'd': - sign = 1; - base = 10; - goto numeric; - case 'x': - base = 16; - numeric: - c = va_arg(va, int); - cnt += printn(fp, c, base, sign); - continue; - case 's': +flags: + switch (*fmt++) { + case '%': + putc('%', fp); + ++cnt; + continue; + case ' ': + conv.sign = ' '; + goto flags; + case '+': + conv.sign = '+'; + goto flags; + case '#': + flags |= ALTFORM; + goto flags; + case '.': + if (*fmt == '*') { + fmt++; + n = va_arg(va, int); + } else { + for (n = 0; isdigit(ch = *fmt); fmt++) + n = n * 10 + ch - '0'; + } + if (n > BUF_SIZ) + n = BUF_SIZ; + if (n > 0) + conv.prec = n; + goto flags; + case '-': + flags |= LADJUST; + goto flags; + case '*': + n = va_arg(va, int); + if (n < 0) { + flags |= LADJUST; + n = -n; + } + width = n; + goto flags; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --fmt; + for (n = 0; isdigit(ch = *fmt); ++fmt) + n = n * 10 + ch - '0'; + width = n; + goto flags; + case '0': + fill = '0'; + goto flags; + case 'l': + flags += LONG; + goto flags; + case 'h': + flags += SHORT; + goto flags; + case 'c': + if (flags & LONG) { + wbuf[0] = va_arg(va, wint_t); + wbuf[1] = '\0'; + ws = wbuf; + goto wstrout; + } else { + buf[0] = va_arg(va, int); + buf[1] = '\0'; + s = buf; + goto strout; + } + case 'j': + flags |= INTMAX; + goto flags; + case 't': + flags |= PTRDIFF; + goto flags; + case 'z': + flags |= SIZET; + goto flags; + case 'u': + flags |= UNSIGNED; + case 'i': + case 'd': + numeric10: + conv.base = 10; + goto numeric; + case 'p': + flags |= VOIDPTR | ALTFORM; + goto numeric16; + case 'x': + conv.digs = "0123456789abcdefx"; + case 'X': + numeric16: + conv.base = 16; + flags |= UNSIGNED; + goto numeric; + case 'o': + conv.base = 8; + flags |= UNSIGNED; + numeric: + s = numtostr(getnum(va, flags, &conv.sign), + flags, + &conv, + &buf[BUF_SIZ]); + goto strout; + case 'L': + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + /* TODO */ + case 's': + if ((flags & LONG) == 0){ s = va_arg(va, char *); - while ((c = *s++) != '\0') - putc(c, fp); - default: - continue; + goto strout; } + ws = va_arg(va, wchar_t *); + wstrout: + if (flags & LADJUST) + width = -width; + cnt += wstrout(ws, width, fill, fp); + break; + strout: + if (flags & LADJUST) + width = -width; + cnt += strout(s, width, fill, fp); + break; + case 'n': + setcnt(va, flags, cnt); + break; + case '\0': + goto end_format; } - putc(c, fp); - ++cnt; } - return cnt; +end_format: + return (ferror(fp)) ? EOF : cnt; }