#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#define MYBUFSIZE 32
typedef struct {
char buf[MYBUFSIZE];
char *ptr;
char *end;
int fd;
} BUF;
static inline void
flush(BUF *b)
{
char *buf = b->buf;
int n = b->ptr - buf;
int w;
while(n > 0) {
w = write(b->fd, buf, n);
if(w < 0) {
if(errno == EINTR || errno == EAGAIN)
continue;
break;
}
n -= w;
buf += n;
}
b->ptr = b->buf;
}
static inline void
put_c(BUF *b, int c)
{
if(b->ptr >= b->end)
flush(b);
*b->ptr++ = c;
}
static inline void
put_s(BUF *b, const char *str)
{
while(*str)
put_c(b, *str++);
}
static inline void
put_n(BUF *b, const char *str, int n)
{
while(n-- > 0)
put_c(b, *str++);
}
static void
dec(BUF *b, long long in, int width, int zero)
{
char buf[32];
char *cp = buf + sizeof(buf);
int pad;
int neg = 0;
unsigned long long n = (unsigned long long)in;
if(in < 0) {
neg++;
width--;
n = ~n + 1;
}
*--cp = 0;
if(n) {
while(n) {
*--cp = (n % 10) + '0';
n /= 10;
}
} else
*--cp = '0';
if(neg && zero) {
put_c(b, '-');
neg = 0;
}
pad = width - strlen(cp);
zero = zero ? '0' : ' ';
while(pad-- > 0)
put_c(b, zero);
if(neg)
put_c(b, '-');
put_s(b, cp);
}
static char _h[] = "0123456789abcdef";
static char _H[] = "0123456789ABCDEF";
static char _0x[] = "0x";
static void
hex(BUF *b, unsigned long long n, int width, int zero, int upper, int p)
{
char buf[32];
char *cp = buf + sizeof(buf);
char *h = upper ? _H : _h;
*--cp = 0;
if(n) {
while(n) {
*--cp = h[n & 0xf];
n >>= 4;
}
} else
*--cp = '0';
if(p) {
width -= 2;
if(zero) {
put_s(b, _0x);
p = 0;
}
}
width -= strlen(cp);
zero = zero ? '0' : ' ';
while(width-- > 0)
put_c(b, zero);
if(p)
put_s(b, _0x);
put_s(b, cp);
}
static void
udec(BUF *b, unsigned long long n, int width, int zero)
{
char buf[32];
char *cp = buf + sizeof(buf);
int pad;
*--cp = 0;
if(n) {
while(n) {
*--cp = (n % 10) + '0';
n /= 10;
}
} else
*--cp = '0';
pad = width - strlen(cp);
zero = zero ? '0' : ' ';
while(pad-- > 0)
put_c(b, zero);
put_s(b, cp);
}
void
_simple_vdprintf(int fd, const char *fmt, va_list ap)
{
BUF b;
b.fd = fd;
b.ptr = b.buf;
b.end = b.buf + MYBUFSIZE;
while(*fmt) {
int lflag, zero, width;
char *cp;
if(!(cp = strchr(fmt, '%'))) {
put_s(&b, fmt);
break;
}
put_n(&b, fmt, cp - fmt);
fmt = cp + 1;
if(*fmt == '%') {
put_c(&b, '%');
fmt++;
continue;
}
lflag = zero = width = 0;
for(;;) {
switch(*fmt) {
case '0':
zero++;
fmt++;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
while(*fmt >= '0' && *fmt <= '9')
width = 10 * width + (*fmt++ - '0');
continue;
case 'c':
zero = zero ? '0' : ' ';
width--;
while(width-- > 0)
put_c(&b, zero);
put_c(&b, va_arg(ap, int));
break;
case 'd': case 'i':
switch(lflag) {
case 0:
dec(&b, va_arg(ap, int), width, zero);
break;
case 1:
dec(&b, va_arg(ap, long), width, zero);
break;
default:
dec(&b, va_arg(ap, long long), width, zero);
break;
}
break;
case 'l':
lflag++;
fmt++;
continue;
case 'p':
hex(&b, (unsigned long)va_arg(ap, void *), width, zero, 0, 1);
break;
case 's':
cp = va_arg(ap, char *);
width -= strlen(cp);
zero = zero ? '0' : ' ';
while(width-- > 0)
put_c(&b, zero);
put_s(&b, cp);
break;
case 'u':
switch(lflag) {
case 0:
udec(&b, va_arg(ap, unsigned int), width, zero);
break;
case 1:
udec(&b, va_arg(ap, unsigned long), width, zero);
break;
default:
udec(&b, va_arg(ap, unsigned long long), width, zero);
break;
}
break;
case 'X': case 'x':
switch(lflag) {
case 0:
hex(&b, va_arg(ap, unsigned int), width, zero,
*fmt == 'X', 0);
break;
case 1:
hex(&b, va_arg(ap, unsigned long), width, zero,
*fmt == 'X', 0);
break;
default:
hex(&b, va_arg(ap, unsigned long long), width, zero,
*fmt == 'X', 0);
break;
}
break;
default:
put_c(&b, *fmt);
break;
}
break;
}
fmt++;
}
flush(&b);
}
void
_simple_dprintf(int fd, const char *format, ...)
{
va_list ap;
va_start(ap, format);
_simple_vdprintf(fd, format, ap);
va_end(ap);
}