Spaces:
Runtime error
Runtime error
| /* | |
| * 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. | |
| */ | |
| 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); | |
| } | |