blob: 2aec59aa6d6d4ccd5d2f52b2fe43d329731c857c [file] [log] [blame] [raw]
#include "libcflat.h"
#define BUFSZ 2000
typedef struct pstream {
char *buffer;
int remain;
int added;
} pstream_t;
typedef struct strprops {
char pad;
int npad;
} strprops_t;
static void addchar(pstream_t *p, char c)
{
if (p->remain) {
*p->buffer++ = c;
--p->remain;
}
++p->added;
}
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";
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);
}
void print_unsigned(pstream_t *ps, unsigned long long n, int base,
strprops_t props)
{
char buf[sizeof(long) * 3 + 1], *p = buf;
int i;
while (n) {
*p++ = digits[n % base];
n /= base;
}
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 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 '0':
props.pad = '0';
++fmt;
/* fall through */
case '1'...'9':
case '-':
--fmt;
props.npad = fmtnum(&fmt);
goto morefmt;
case 'l':
++nlong;
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':
print_str(&s, "0x", props);
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;
++s.added;
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;
}