#include "namespace.h"
#include <err.h>
#include <sys/types.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <locale.h>
#include <stdint.h>
#include <assert.h>
#include <stdarg.h>
#include <namespace.h>
#include <string.h>
#include <wchar.h>
#include <errno.h>
#include "un-namespace.h"
#ifdef MACHTIME
#include <mach/mach_time.h>
#endif // MACHTIME
#ifdef XPRINTF_PERF
#include <libkern/OSAtomic.h>
#endif
#include "local.h"
#include "xprintf_private.h"
#include "xprintf_domain.h"
#include "fvwrite.h"
#ifdef XPRINTF_DEBUG
#include <unistd.h>
int __use_xprintf = 0;
#endif
union arg {
int intarg;
long longarg;
intmax_t intmaxarg;
#ifndef NO_FLOATING_POINT
double doublearg;
long double longdoublearg;
#endif
wint_t wintarg;
char *pchararg;
wchar_t *pwchararg;
void *pvoidarg;
#ifdef VECTORS
VECTORTYPE vectorarg;
unsigned char vuchararg[16];
signed char vchararg[16];
unsigned short vushortarg[8];
signed short vshortarg[8];
unsigned int vuintarg[4];
signed int vintarg[4];
float vfloatarg[4];
#ifdef V64TYPE
double vdoublearg[2];
unsigned long long vulonglongarg[2];
long long vlonglongarg[2];
#endif
#endif
};
#define to_digit(c) ((c) - '0')
#define is_digit(c) (((unsigned)to_digit(c)) <= 9)
__private_extern__ const char __lowercase_hex[17] = "0123456789abcdef?";
__private_extern__ const char __uppercase_hex[17] = "0123456789ABCDEF?";
#define PADSIZE 16
static char blanks[PADSIZE] =
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
static char zeroes[PADSIZE] =
{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
#define NIOV 8
struct __printf_io {
FILE *fp;
struct __suio uio;
struct __siov iov[NIOV];
struct __siov *iovp;
};
static void
__printf_init(struct __printf_io *io)
{
io->uio.uio_iov = io->iovp = &io->iov[0];
io->uio.uio_resid = 0;
io->uio.uio_iovcnt = 0;
}
__private_extern__ void
__printf_flush(struct __printf_io *io)
{
__sfvwrite(io->fp, &io->uio);
__printf_init(io);
}
__private_extern__ int
__printf_puts(struct __printf_io *io, const void *ptr, int len)
{
#if 0
if (io->fp->_flags & __SERR)
return (0);
#endif
if (len == 0)
return (0);
io->iovp->iov_base = __DECONST(void *, ptr);
io->iovp->iov_len = len;
io->uio.uio_resid += len;
io->iovp++;
io->uio.uio_iovcnt++;
if (io->uio.uio_iovcnt >= NIOV)
__printf_flush(io);
return (len);
}
__private_extern__ int
__printf_pad(struct __printf_io *io, int howmany, int zero)
{
int n;
const char *with;
int ret = 0;
if (zero)
with = zeroes;
else
with = blanks;
if ((n = (howmany)) > 0) {
while (n > PADSIZE) {
ret += __printf_puts(io, with, PADSIZE);
n -= PADSIZE;
}
ret += __printf_puts(io, with, n);
}
return (ret);
}
__private_extern__ int
__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
{
int ret = 0;
if ((!pi->left) && pi->width > len)
ret += __printf_pad(io, pi->width - len, pi->pad == '0');
ret += __printf_puts(io, ptr, len);
if (pi->left && pi->width > len)
ret += __printf_pad(io, pi->width - len, pi->pad == '0');
return (ret);
}
__private_extern__ int
__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
{
return (0);
}
__private_extern__ int
__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
{
return (__printf_puts(io, "%", 1));
}
__private_extern__ int
__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
{
assert(n >= 1);
argt[0] = PA_POINTER;
return (1);
}
__private_extern__ int
__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
{
if (pi->is_char)
**((signed char **)arg[0]) = (signed char)pi->sofar;
else if (pi->is_short)
**((short **)arg[0]) = (short)pi->sofar;
else if (pi->is_long)
**((long **)arg[0]) = pi->sofar;
else if (pi->is_long_double)
**((long long **)arg[0]) = pi->sofar;
else if (pi->is_intmax)
**((intmax_t **)arg[0]) = pi->sofar;
else if (pi->is_ptrdiff)
**((ptrdiff_t **)arg[0]) = pi->sofar;
else if (pi->is_quad)
**((quad_t **)arg[0]) = pi->sofar;
else if (pi->is_size)
**((size_t **)arg[0]) = pi->sofar;
else
**((int **)arg[0]) = pi->sofar;
return (0);
}
#define ARRAYDELTA 8
struct array {
#ifdef XPRINTF_PERF
struct array *next;
#endif
void *data;
int itemsize;
int max;
};
#ifdef XPRINTF_PERF
__private_extern__
#else
static
#endif
void
arrayfree(struct array *a)
{
if(a) free(a->data);
}
static void *
arrayget(struct array *a, int i)
{
if (i >= a->max) {
int oldsize = a->max * a->itemsize;
int newmax = i + ARRAYDELTA;
int newsize = newmax * a->itemsize;
void *newdata = realloc(a->data, newsize);
if(!newdata) return NULL;
bzero(newdata + oldsize, newsize - oldsize);
a->data = newdata;
a->max = newmax;
}
return a->data + i * a->itemsize;
}
static struct array *
arrayinit(struct array *a, int itemsize)
{
a->data = CALLOC(ARRAYDELTA, itemsize);
if(!a->data) return NULL;
a->itemsize = itemsize;
a->max = ARRAYDELTA;
return a;
}
#ifdef XPRINTF_PERF
static OSQueueHead arg_type_queue = OS_ATOMIC_QUEUE_INIT;
static OSQueueHead printf_info_queue = OS_ATOMIC_QUEUE_INIT;
static OSQueueHead union_arg_queue = OS_ATOMIC_QUEUE_INIT;
#define DEFINE_DEQUEUE(which, type) \
static struct array * \
which ## _dequeue(void) \
{ \
struct array *a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next)); \
\
if (a) { \
bzero(a->data, a->max * a->itemsize); \
return a; \
} \
a = (struct array *)MALLOC(sizeof(*a)); \
if (!a) return NULL; \
if (!arrayinit(a, sizeof(type))) { \
free(a); \
return NULL; \
} \
return a; \
}
#define DEFINE_ENQUEUE(which) \
__private_extern__ void \
which ## _enqueue(struct array *a) \
{ \
if (!a) return; \
OSAtomicEnqueue(&which ## _queue, a, offsetof(struct array, next)); \
}
#define DEFINE_FLUSH(which) \
static void \
which ## _flush(void) \
{ \
struct array *a; \
while((a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next))) != NULL) { \
arrayfree(a); \
free(a); \
} \
}
DEFINE_DEQUEUE(arg_type, int)
DEFINE_ENQUEUE(arg_type)
DEFINE_FLUSH(arg_type)
DEFINE_DEQUEUE(printf_info, struct printf_info)
DEFINE_ENQUEUE(printf_info)
DEFINE_FLUSH(printf_info)
DEFINE_DEQUEUE(union_arg, union arg)
DEFINE_ENQUEUE(union_arg)
DEFINE_FLUSH(union_arg)
static void
flush_queues(void)
{
arg_type_flush();
printf_info_flush();
union_arg_flush();
}
__private_extern__ void *
xprintf_calloc(size_t count, size_t size)
{
void *x = calloc(count, size);
if(!x) {
flush_queues();
x = calloc(count, size);
}
return x;
}
__private_extern__ void *
xprintf_malloc(size_t size)
{
void *x = malloc(size);
if(!x) {
flush_queues();
x = malloc(size);
}
return x;
}
#if 0
void
show_queues(void)
{
struct array *a;
printf("arg_type:");
while((a = (struct array *)OSAtomicDequeue(&arg_type_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
printf("\nprintf_info:");
while((a = (struct array *)OSAtomicDequeue(&printf_info_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
printf("\nunion_arg:");
while((a = (struct array *)OSAtomicDequeue(&union_arg_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a);
printf("\n");
}
#endif
#endif
__private_extern__ int
__printf_comp(printf_comp_t restrict pc, printf_domain_t restrict domain)
{
struct printf_info *pi, *pil;
const char *fmt;
int ch, pii;
int *argt;
int nextarg;
int maxarg;
int ret = 0;
int n;
#ifndef XPRINTF_PERF
struct array piarr, argtarr;
#endif
struct array *pa, *aa;
fmt = pc->fmt;
maxarg = 0;
nextarg = 1;
#ifdef XPRINTF_PERF
pa = printf_info_dequeue();
#else
pa = arrayinit(&piarr, sizeof(*pi));
#endif
if (!pa) {
#ifdef XPRINTF_PERF
flush_queues();
#endif
return EOF;
}
#ifdef XPRINTF_PERF
pc->pa = pa;
aa = arg_type_dequeue();
#else
aa = arrayinit(&argtarr, sizeof(*argt));
#endif
if (!aa) {
arrayfree(pa);
#ifdef XPRINTF_PERF
free(pa);
flush_queues();
#endif
return EOF;
}
#ifdef XPRINTF_PERF
pc->aa = aa;
#endif
for (pii = 0; ; pii++) {
pi = arrayget(pa, pii);
if (!pi) {
ret = EOF;
goto error;
}
pil = pi;
if (*fmt == '\0')
break;
pil = pi + 1;
pi->prec = -1;
pi->pad = ' ';
#ifdef VECTORS
pi->vsep = 'X';
#endif
pi->begin = pi->end = fmt;
while (*fmt != '\0' && *fmt != '%')
pi->end = ++fmt;
if (*fmt == '\0')
break;
fmt++;
for (;;) {
pi->spec = *fmt;
switch (pi->spec) {
case ' ':
if (pi->showsign == 0) {
pi->space = 1;
pi->signchar = ' ';
}
fmt++;
continue;
case '#':
pi->alt = 1;
fmt++;
continue;
#ifdef VECTORS
case ',': case ';': case ':': case '_':
pi->vsep = pi->spec;
fmt++;
continue;
#endif
case '.':
pi->prec = 0;
fmt++;
if (*fmt == '*') {
fmt++;
n = 0;
while (*fmt != '\0' && is_digit(*fmt)) {
n *= 10;
n += to_digit(*fmt);
fmt++;
}
if (*fmt == '$') {
if ((n + 1) > maxarg)
maxarg = (n + 1);
fmt++;
} else n = nextarg++;
pi->get_prec = n;
argt = (int *)arrayget(aa, n);
if (!argt) {
ret = EOF;
goto error;
}
*argt = PA_INT;
continue;
}
while (*fmt != '\0' && is_digit(*fmt)) {
pi->prec *= 10;
pi->prec += to_digit(*fmt);
fmt++;
}
continue;
case '-':
pi->left = 1;
fmt++;
continue;
case '+':
pi->showsign = 1;
pi->signchar = '+';
fmt++;
continue;
case '*':
fmt++;
n = 0;
while (*fmt != '\0' && is_digit(*fmt)) {
n *= 10;
n += to_digit(*fmt);
fmt++;
}
if (*fmt == '$') {
if ((n + 1) > maxarg)
maxarg = (n + 1);
fmt++;
} else n = nextarg++;
pi->get_width = n;
argt = (int *)arrayget(aa, n);
if (!argt) {
ret = EOF;
goto error;
}
*argt = PA_INT;
continue;
case '%':
fmt++;
break;
case '\'':
pi->group = 1;
fmt++;
continue;
case '0':
pi->pad = '0';
fmt++;
continue;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
n = 0;
while (*fmt != '\0' && is_digit(*fmt)) {
n *= 10;
n += to_digit(*fmt);
fmt++;
}
if (*fmt == '$') {
if (nextarg > maxarg)
maxarg = nextarg;
nextarg = n;
fmt++;
} else
pi->width = n;
continue;
#if 0
case 'D':
case 'O':
case 'U':
pi->spec += ('a' - 'A');
pi->is_intmax = 0;
if (pi->is_long_double || pi->is_quad) {
pi->is_long = 0;
pi->is_long_double = 1;
} else {
pi->is_long = 1;
pi->is_long_double = 0;
}
fmt++;
break;
#endif
case 'j':
pi->is_intmax = 1;
fmt++;
continue;
case 'q':
pi->is_long = 0;
pi->is_quad = 1;
fmt++;
continue;
case 'L':
pi->is_long_double = 1;
fmt++;
continue;
case 'h':
fmt++;
if (*fmt == 'h') {
fmt++;
pi->is_char = 1;
} else {
pi->is_short = 1;
}
continue;
case 'l':
fmt++;
if (*fmt == 'l') {
fmt++;
pi->is_long_double = 1;
pi->is_quad = 0;
} else {
pi->is_quad = 0;
pi->is_long = 1;
}
continue;
case 't':
pi->is_ptrdiff = 1;
fmt++;
continue;
case 'v':
#ifdef VECTORS
pi->is_vec = 1;
#endif
fmt++;
continue;
case 'z':
pi->is_size = 1;
fmt++;
continue;
default:
fmt++;
break;
}
if (printf_tbl_in_range(pi->spec)) {
switch(domain->type[printf_tbl_index(pi->spec)]) {
case PRINTF_DOMAIN_FLAG:
errx(1, "Unexpected flag: %c", pi->spec);
case PRINTF_DOMAIN_GLIBC_API:
case PRINTF_DOMAIN_FBSD_API:
if (!arrayget(aa, nextarg + __PRINTFMAXARG - 1)) {
ret = EOF;
goto error;
}
pi->context = domain->tbl[printf_tbl_index(pi->spec)].context;
pi->loc = pc->loc;
ch = domain->tbl[printf_tbl_index(pi->spec)].arginfo(
pi, __PRINTFMAXARG, arrayget(aa, nextarg));
if (ch > 0)
pi->arg[0] = (void *)(long)nextarg;
if (ch > 1)
pi->arg[1] = (void *)(long)(nextarg + 1);
nextarg += ch;
break;
}
}
break;
}
}
if (nextarg > maxarg)
maxarg = nextarg;
pc->argt = aa->data;
pc->pi = pa->data;
pc->pil = pil;
pc->maxarg = ch = maxarg;
if (ch < 1) ch = 1;
#ifdef XPRINTF_PERF
pc->ua = union_arg_dequeue();
if (!pc->ua) {
ret = EOF;
goto error;
}
if (!arrayget(pc->ua, ch)) {
union_arg_enqueue(pc->ua);
ret = EOF;
goto error;
}
pc->args = pc->ua->data;
#else
pc->args = (union arg *)malloc(ch * sizeof(*pc->args));
if (!pc->args) {
ret = EOF;
goto error;
}
#endif
for (pi = pc->pi; pi < pil; pi++) {
if (pi->arg[0]) pi->arg[0] = &pc->args[(long)pi->arg[0]];
if (pi->arg[1]) pi->arg[1] = &pc->args[(long)pi->arg[1]];
}
#if 0
fprintf(stderr, "fmt0 <%s>\n", fmt0);
fprintf(stderr, "pil %p\n", pil);
#endif
pc->domain = domain;
return (ret);
error:
arrayfree(pa);
arrayfree(aa);
#ifdef XPRINTF_PERF
free(pa);
free(aa);
flush_queues();
#endif
return (ret);
}
__private_extern__ int
__printf_exec(printf_comp_t restrict pc, FILE * restrict fp, va_list ap)
{
struct printf_info *pi;
int ch;
int ret = 0;
int n;
struct __printf_io io;
__printf_init(&io);
io.fp = fp;
for (ch = 1; ch < pc->maxarg; ch++) {
#if 0
fprintf(stderr, "arg %d %x\n", ch, pc->argt[ch]);
#endif
switch(pc->argt[ch]) {
case PA_CHAR:
pc->args[ch].intarg = (char)va_arg (ap, int);
break;
case PA_INT:
pc->args[ch].intarg = va_arg (ap, int);
break;
case PA_INT | PA_FLAG_SHORT:
pc->args[ch].intarg = (short)va_arg (ap, int);
break;
case PA_INT | PA_FLAG_LONG:
pc->args[ch].longarg = va_arg (ap, long);
break;
case PA_INT | PA_FLAG_INTMAX:
pc->args[ch].intmaxarg = va_arg (ap, intmax_t);
break;
case PA_INT | PA_FLAG_QUAD:
pc->args[ch].intmaxarg = va_arg (ap, quad_t);
break;
case PA_INT | PA_FLAG_LONG_LONG:
pc->args[ch].intmaxarg = va_arg (ap, long long);
break;
case PA_INT | PA_FLAG_SIZE:
pc->args[ch].intmaxarg = va_arg (ap, size_t);
break;
case PA_INT | PA_FLAG_PTRDIFF:
pc->args[ch].intmaxarg = (unsigned long)va_arg (ap, ptrdiff_t);
break;
case PA_WCHAR:
pc->args[ch].wintarg = va_arg (ap, wint_t);
break;
case PA_POINTER:
pc->args[ch].pvoidarg = va_arg (ap, void *);
break;
case PA_STRING:
pc->args[ch].pchararg = va_arg (ap, char *);
break;
case PA_WSTRING:
pc->args[ch].pwchararg = va_arg (ap, wchar_t *);
break;
case PA_DOUBLE:
#ifndef NO_FLOATING_POINT
pc->args[ch].doublearg = va_arg (ap, double);
#endif
break;
case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
#ifndef NO_FLOATING_POINT
pc->args[ch].longdoublearg = va_arg (ap, long double);
#endif
break;
#ifdef VECTORS
case PA_VECTOR:
pc->args[ch].vectorarg = va_arg (ap, VECTORTYPE);
break;
#endif
default:
errx(1, "argtype = %x (fmt = \"%s\")\n",
pc->argt[ch], pc->fmt);
}
}
for (pi = pc->pi; pi < pc->pil; pi++) {
#if 0
fprintf(stderr, "pi %p", pi);
fprintf(stderr, " spec '%c'", pi->spec);
fprintf(stderr, " args %d",
((uintptr_t)pi->arg[0] - (uintptr_t)pc->args) / sizeof pc->args[0]);
if (pi->width) fprintf(stderr, " width %d", pi->width);
if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
if (pi->left) fprintf(stderr, " left");
if (pi->showsign) fprintf(stderr, " showsign");
if (pi->signchar) fprintf(stderr, " signchar 0x%x", pi->signchar);
if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
if (pi->is_char) fprintf(stderr, " char");
if (pi->is_short) fprintf(stderr, " short");
if (pi->is_long) fprintf(stderr, " long");
if (pi->is_long_double) fprintf(stderr, " long_double");
fprintf(stderr, "\n");
fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
#endif
if (pi->get_width) {
pi->width = pc->args[pi->get_width].intarg;
if (pi->width < 0) {
pi->left = 1;
pi->width = -pi->width;
}
}
if (pi->get_prec)
pi->prec = pc->args[pi->get_prec].intarg;
ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
if (pi->spec) {
if (!printf_tbl_in_range(pi->spec)) goto unused;
switch(pc->domain->type[printf_tbl_index(pi->spec)]) {
case PRINTF_DOMAIN_UNUSED:
unused:
{
char unknown = pi->spec;
ret += __printf_out(&io, pi, &unknown, 1);
break;
}
case PRINTF_DOMAIN_GLIBC_API:
__printf_flush(&io);
pi->sofar = ret;
ret += ((printf_function *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)(
fp, pi, (const void *)pi->arg);
break;
case PRINTF_DOMAIN_FBSD_API:
pi->sofar = ret;
n = ((printf_render *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)(
&io, pi, (const void *)pi->arg);
if (n < 0)
io.fp->_flags |= __SERR;
else
ret += n;
break;
}
}
}
__printf_flush(&io);
return (ret);
}
__private_extern__ int
__v2printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap)
{
struct _printf_compiled spc;
int ret, saverrno;
if (prepwrite(fp) != 0) {
errno = EBADF;
return (EOF);
}
ORIENT(fp, -1);
if (pc == XPRINTF_PLAIN) {
NORMALIZE_LOCALE(loc);
#ifdef XPRINTF_DEBUG
if (!__use_xprintf)
#endif
return __vfprintf(fp, loc, fmt, ap);
#ifdef XPRINTF_DEBUG
xprintf_domain_init();
domain = xprintf_domain_global;
#endif
} else if (pc) {
pthread_mutex_lock(&pc->mutex);
pthread_rwlock_rdlock(&pc->domain->rwlock);
ret = __printf_exec(pc, fp, ap);
saverrno = errno;
pthread_rwlock_unlock(&pc->domain->rwlock);
pthread_mutex_unlock(&pc->mutex);
errno = saverrno;
return ret;
}
if (!domain) {
errno = EINVAL;
return EOF;
}
xprintf_domain_init();
bzero(&spc, sizeof(spc));
spc.fmt = fmt;
DEFAULT_CURRENT_LOCALE(loc);
XL_RETAIN(loc);
spc.loc = loc;
pthread_rwlock_rdlock(&domain->rwlock);
if (__printf_comp(&spc, domain) < 0) {
saverrno = errno;
pthread_rwlock_unlock(&domain->rwlock);
XL_RELEASE(loc);
errno = saverrno;
return EOF;
}
ret = __printf_exec(&spc, fp, ap);
saverrno = errno;
pthread_rwlock_unlock(&domain->rwlock);
XL_RELEASE(loc);
#ifdef XPRINTF_PERF
printf_info_enqueue(spc.pa);
arg_type_enqueue(spc.aa);
union_arg_enqueue(spc.ua);
#else
free(spc.pi);
free(spc.argt);
free(spc.args);
#endif
errno = saverrno;
return ret;
}
extern int __fflush(FILE *fp);
static int
__v3printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap)
{
int ret;
FILE fake;
struct __sFILEX extra;
unsigned char buf[BUFSIZ];
fake._extra = &extra;
INITEXTRA(&fake);
fake._flags = fp->_flags & ~__SNBF;
fake._file = fp->_file;
fake._cookie = fp->_cookie;
fake._write = fp->_write;
fake._orientation = fp->_orientation;
fake._mbstate = fp->_mbstate;
fake._bf._base = fake._p = buf;
fake._bf._size = fake._w = sizeof(buf);
fake._lbfsize = 0;
ret = __v2printf(pc, domain, &fake, loc, fmt, ap);
if (ret >= 0 && __fflush(&fake))
ret = EOF;
if (fake._flags & __SERR)
fp->_flags |= __SERR;
return (ret);
}
__private_extern__ int
__xvprintf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt0, va_list ap)
{
int ret;
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
ret = __v3printf(pc, domain, fp, loc, fmt0, ap);
else
ret = __v2printf(pc, domain, fp, loc, fmt0, ap);
return ret;
}
#if 0
int
register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
{
return register_printf_domain_function(NULL, spec, render, arginfo);
}
__private_extern__ int
register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
{
return register_printf_domain_render(NULL, spec, render, arginfo);
}
int
register_printf_render_std(const char *specs)
{
return register_printf_domain_render_std(NULL, specs);
}
#endif
#ifdef VECTORS
#define PRINTVECTOR(_io, _pi, _arg, _cnt, _type, _elem, _render, _ret) { \
int i; \
_type a, *ap; \
a = (_type)(_arg)->_elem[0]; \
ap = &a; \
(_ret) += _render((_io), (_pi), (const void *)&ap); \
for(i = 1; i < (_cnt); i++) { \
(_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \
a = (_type)(_arg)->_elem[i]; \
(_ret) += _render((_io), (_pi), (const void *)&ap); \
} \
}
#define PRINTVECTOR_P(_io, _pi, _arg, _cnt, _elem, _render, _ret) { \
int i; \
void * a, *ap; \
a = (void *)(uintptr_t)(_arg)->_elem[0]; \
ap = &a; \
(_ret) += _render((_io), (_pi), (const void *)&ap); \
for(i = 1; i < (_cnt); i++) { \
(_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \
a = (void *)(uintptr_t)(_arg)->_elem[i]; \
(_ret) += _render((_io), (_pi), (const void *)&ap); \
} \
}
__private_extern__ int
__xprintf_vector(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
{
char vsep;
const union arg *argp;
int ret = 0;
struct printf_info info = *pi;
argp = arg[0];
vsep = pi->vsep;
if (vsep == 'X') {
if (pi->spec == 'c')
vsep = '\0';
else
vsep = ' ';
}
info.begin = info.end = &vsep;
if (vsep) info.end++;
info.is_vec = 0;
if (pi->is_short) {
if (pi->spec == 'p') {
PRINTVECTOR_P(io, &info, argp, 8, vushortarg, __printf_render_ptr, ret);
} else {
PRINTVECTOR(io, &info, argp, 8, unsigned int, vushortarg, __printf_render_int, ret);
}
} else if (pi->is_long) {
info.is_long = 0;
if (pi->spec == 'p') {
PRINTVECTOR_P(io, &info, argp, 4, vuintarg, __printf_render_ptr, ret);
} else {
PRINTVECTOR(io, &info, argp, 4, unsigned int, vuintarg, __printf_render_int, ret);
}
#ifdef V64TYPE
} else if (pi->is_long_double) {
switch (pi->spec) {
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
info.is_long_double = 0;
PRINTVECTOR(io, &info, argp, 2, double, vdoublearg, __printf_render_float, ret);
break;
case 'p':
info.is_long_double = 0;
PRINTVECTOR_P(io, &info, argp, 2, vulonglongarg, __printf_render_ptr, ret);
break;
case 'd':
case 'i':
case 'u':
case 'o':
case 'x':
case 'X':
PRINTVECTOR(io, &info, argp, 2, unsigned long long, vulonglongarg, __printf_render_int, ret);
break;
default:
case 'c':
info.is_long_double = 0;
PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret);
}
#endif
} else {
switch (pi->spec) {
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
PRINTVECTOR(io, &info, argp, 4, double, vfloatarg, __printf_render_float, ret);
break;
default:
case 'p':
PRINTVECTOR_P(io, &info, argp, 16, vuchararg, __printf_render_ptr, ret);
break;
case 'd':
case 'i':
case 'u':
case 'o':
case 'x':
case 'X':
info.is_char = 1;
PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_int, ret);
break;
case 'c':
PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret);
}
}
return ret;
}
#endif