123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /*
- * libc printf and friends
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Library General Public License version 2.
- */
- #include "libcflat.h"
- #define BUFSZ 2000
- typedef struct pstream {
- char *buffer;
- int remain;
- int added;
- } pstream_t;
- typedef struct strprops {
- char pad;
- int npad;
- bool alternate;
- } strprops_t;
- static void addchar(pstream_t *p, char c)
- {
- if (p->remain) {
- *p->buffer++ = c;
- --p->remain;
- }
- ++p->added;
- }
- static void print_str(pstream_t *p, const char *s, strprops_t props)
- {
- const char *s_orig = s;
- int npad = props.npad;
- if (npad > 0) {
- npad -= strlen(s_orig);
- while (npad > 0) {
- addchar(p, props.pad);
- --npad;
- }
- }
- while (*s)
- addchar(p, *s++);
- if (npad < 0) {
- props.pad = ' '; /* ignore '0' flag with '-' flag */
- npad += strlen(s_orig);
- while (npad < 0) {
- addchar(p, props.pad);
- ++npad;
- }
- }
- }
- static char digits[16] = "0123456789abcdef";
- static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
- {
- char buf[sizeof(long) * 3 + 2], *p = buf;
- int s = 0, i;
- if (n < 0) {
- n = -n;
- s = 1;
- }
- while (n) {
- *p++ = digits[n % base];
- n /= base;
- }
- if (s)
- *p++ = '-';
- if (p == buf)
- *p++ = '0';
- for (i = 0; i < (p - buf) / 2; ++i) {
- char tmp;
- tmp = buf[i];
- buf[i] = p[-1-i];
- p[-1-i] = tmp;
- }
- *p = 0;
- print_str(ps, buf, props);
- }
- static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
- strprops_t props)
- {
- char buf[sizeof(long) * 3 + 3], *p = buf;
- int i;
- while (n) {
- *p++ = digits[n % base];
- n /= base;
- }
- if (p == buf)
- *p++ = '0';
- else if (props.alternate && base == 16) {
- if (props.pad == '0') {
- addchar(ps, '0');
- addchar(ps, 'x');
- if (props.npad > 0)
- props.npad = MAX(props.npad - 2, 0);
- } else {
- *p++ = 'x';
- *p++ = '0';
- }
- }
- for (i = 0; i < (p - buf) / 2; ++i) {
- char tmp;
- tmp = buf[i];
- buf[i] = p[-1-i];
- p[-1-i] = tmp;
- }
- *p = 0;
- print_str(ps, buf, props);
- }
- static int fmtnum(const char **fmt)
- {
- const char *f = *fmt;
- int len = 0, num;
- if (*f == '-')
- ++f, ++len;
- while (*f >= '0' && *f <= '9')
- ++f, ++len;
- num = atol(*fmt);
- *fmt += len;
- return num;
- }
- int vsnprintf(char *buf, int size, const char *fmt, va_list va)
- {
- pstream_t s;
- s.buffer = buf;
- s.remain = size - 1;
- s.added = 0;
- while (*fmt) {
- char f = *fmt++;
- int nlong = 0;
- strprops_t props;
- memset(&props, 0, sizeof(props));
- props.pad = ' ';
- if (f != '%') {
- addchar(&s, f);
- continue;
- }
- morefmt:
- f = *fmt++;
- switch (f) {
- case '%':
- addchar(&s, '%');
- break;
- case 'c':
- addchar(&s, va_arg(va, int));
- break;
- case '\0':
- --fmt;
- break;
- case '#':
- props.alternate = true;
- goto morefmt;
- case '0':
- props.pad = '0';
- ++fmt;
- /* fall through */
- case '1'...'9':
- case '-':
- --fmt;
- props.npad = fmtnum(&fmt);
- goto morefmt;
- case 'l':
- ++nlong;
- goto morefmt;
- case 't':
- case 'z':
- /* Here we only care that sizeof(size_t) == sizeof(long).
- * On a 32-bit platform it doesn't matter that size_t is
- * typedef'ed to int or long; va_arg will work either way.
- * Same for ptrdiff_t (%td).
- */
- nlong = 1;
- goto morefmt;
- case 'd':
- switch (nlong) {
- case 0:
- print_int(&s, va_arg(va, int), 10, props);
- break;
- case 1:
- print_int(&s, va_arg(va, long), 10, props);
- break;
- default:
- print_int(&s, va_arg(va, long long), 10, props);
- break;
- }
- break;
- case 'u':
- switch (nlong) {
- case 0:
- print_unsigned(&s, va_arg(va, unsigned), 10, props);
- break;
- case 1:
- print_unsigned(&s, va_arg(va, unsigned long), 10, props);
- break;
- default:
- print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
- break;
- }
- break;
- case 'x':
- switch (nlong) {
- case 0:
- print_unsigned(&s, va_arg(va, unsigned), 16, props);
- break;
- case 1:
- print_unsigned(&s, va_arg(va, unsigned long), 16, props);
- break;
- default:
- print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
- break;
- }
- break;
- case 'p':
- props.alternate = true;
- print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
- break;
- case 's':
- print_str(&s, va_arg(va, const char *), props);
- break;
- default:
- addchar(&s, f);
- break;
- }
- }
- *s.buffer = 0;
- return s.added;
- }
- int snprintf(char *buf, int size, const char *fmt, ...)
- {
- va_list va;
- int r;
- va_start(va, fmt);
- r = vsnprintf(buf, size, fmt, va);
- va_end(va);
- return r;
- }
- int vprintf(const char *fmt, va_list va)
- {
- char buf[BUFSZ];
- int r;
- r = vsnprintf(buf, sizeof(buf), fmt, va);
- puts(buf);
- return r;
- }
- int printf(const char *fmt, ...)
- {
- va_list va;
- char buf[BUFSZ];
- int r;
- va_start(va, fmt);
- r = vsnprintf(buf, sizeof buf, fmt, va);
- va_end(va);
- puts(buf);
- return r;
- }
- void binstr(unsigned long x, char out[BINSTR_SZ])
- {
- int i;
- char *c;
- int n;
- n = sizeof(unsigned long) * 8;
- i = 0;
- c = &out[0];
- for (;;) {
- *c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
- i++;
- if (i == n) {
- *c = '\0';
- break;
- }
- if (i % 4 == 0)
- *c++ = '\'';
- }
- assert(c + 1 - &out[0] == BINSTR_SZ);
- }
- void print_binstr(unsigned long x)
- {
- char out[BINSTR_SZ];
- binstr(x, out);
- printf("%s", out);
- }
|