blob: 31adc52b69c522413aefbfb562a72af477e54248 [file] [log] [blame]
/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
*
* GNU Library General Public License (LGPL) version 2 or later.
*
* Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
*/
#include "_stdio.h"
#include <stdarg.h>
#ifdef __UCLIBC_MJN3_ONLY__
#warning WISHLIST: Implement vsnprintf for non-buffered and no custom stream case.
#endif /* __UCLIBC_MJN3_ONLY__ */
#ifdef __STDIO_BUFFERS
/* NB: we can still have __USE_OLD_VFPRINTF__ defined in this case! */
int vsnprintf(char *__restrict buf, size_t size,
const char * __restrict format, va_list arg)
{
FILE f;
int rv;
/* __STDIO_STREAM_RESET_GCS(&f); */
#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
f.__cookie = &(f.__filedes);
f.__gcs.read = NULL;
f.__gcs.write = NULL;
f.__gcs.seek = NULL;
f.__gcs.close = NULL;
#endif
f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES;
f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
#ifdef __UCLIBC_HAS_WCHAR__
f.__ungot_width[0] = 0;
#endif /* __UCLIBC_HAS_WCHAR__ */
#ifdef __STDIO_MBSTATE
__INIT_MBSTATE(&(f.__state));
#endif /* __STDIO_MBSTATE */
#if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__)
f.__user_locking = 1; /* Set user locking. */
STDIO_INIT_MUTEX(f.__lock);
#endif
f.__nextopen = NULL;
if (size > SIZE_MAX - (size_t) buf) {
size = SIZE_MAX - (size_t) buf;
}
/* TODO: this comment seems to be wrong */
/* Set these last since __bufputc initialization depends on
* __user_locking and only gets set if user locking is on. */
f.__bufstart = (unsigned char *) buf;
f.__bufend = (unsigned char *) buf + size;
__STDIO_STREAM_INIT_BUFREAD_BUFPOS(&f);
__STDIO_STREAM_DISABLE_GETC(&f);
__STDIO_STREAM_ENABLE_PUTC(&f);
#ifdef __USE_OLD_VFPRINTF__
rv = vfprintf(&f, format, arg);
#else
rv = _vfprintf_internal(&f, format, arg);
#endif
if (size) {
if (f.__bufpos == f.__bufend) {
--f.__bufpos;
}
*f.__bufpos = 0;
}
return rv;
}
libc_hidden_def(vsnprintf)
#elif defined(__USE_OLD_VFPRINTF__)
typedef struct {
FILE f;
unsigned char *bufend; /* pointer to 1 past end of buffer */
unsigned char *bufpos;
} __FILE_vsnprintf;
int vsnprintf(char *__restrict buf, size_t size,
const char * __restrict format, va_list arg)
{
__FILE_vsnprintf f;
int rv;
f.bufpos = buf;
if (size > SIZE_MAX - (size_t) buf) {
size = SIZE_MAX - (size_t) buf;
}
f.bufend = buf + size;
/* __STDIO_STREAM_RESET_GCS(&f.f); */
#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
f.f.__cookie = &(f.f.__filedes);
f.f.__gcs.read = NULL;
f.f.__gcs.write = NULL;
f.f.__gcs.seek = NULL;
f.f.__gcs.close = NULL;
#endif
f.f.__filedes = __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB;
f.f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
#ifdef __UCLIBC_HAS_WCHAR__
f.f.__ungot_width[0] = 0;
#endif /* __UCLIBC_HAS_WCHAR__ */
#ifdef __STDIO_MBSTATE
__INIT_MBSTATE(&(f.f.__state));
#endif /* __STDIO_MBSTATE */
#ifdef __UCLIBC_HAS_THREADS__
f.f.__user_locking = 1; /* Set user locking. */
STDIO_INIT_MUTEX(f.f.__lock);
#endif
f.f.__nextopen = NULL;
rv = vfprintf((FILE *) &f, format, arg);
if (size) {
if (f.bufpos == f.bufend) {
--f.bufpos;
}
*f.bufpos = 0;
}
return rv;
}
libc_hidden_def(vsnprintf)
#elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
typedef struct {
size_t pos;
size_t len;
unsigned char *buf;
FILE *fp;
} __snpf_cookie;
#define COOKIE ((__snpf_cookie *) cookie)
static ssize_t snpf_write(register void *cookie, const char *buf,
size_t bufsize)
{
size_t count;
register char *p;
/* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
if (COOKIE->len > COOKIE->pos) {
count = COOKIE->len - COOKIE->pos - 1; /* Leave space for nul. */
if (count > bufsize) {
count = bufsize;
}
p = COOKIE->buf + COOKIE->pos;
while (count) {
*p++ = *buf++;
--count;
}
*p = 0;
}
COOKIE->pos += bufsize;
return bufsize;
}
#undef COOKIE
int vsnprintf(char *__restrict buf, size_t size,
const char * __restrict format, va_list arg)
{
FILE f;
__snpf_cookie cookie;
int rv;
cookie.buf = buf;
cookie.len = size;
cookie.pos = 0;
cookie.fp = &f;
f.__cookie = &cookie;
f.__gcs.write = snpf_write;
f.__gcs.read = NULL;
f.__gcs.seek = NULL;
f.__gcs.close = NULL;
f.__filedes = -1; /* For debugging. */
f.__modeflags = (__FLAG_NARROW|__FLAG_WRITEONLY|__FLAG_WRITING);
#ifdef __UCLIBC_HAS_WCHAR__
f.__ungot_width[0] = 0;
#endif /* __UCLIBC_HAS_WCHAR__ */
#ifdef __STDIO_MBSTATE
__INIT_MBSTATE(&(f.__state));
#endif /* __STDIO_MBSTATE */
f.__nextopen = NULL;
rv = _vfprintf_internal(&f, format, arg);
return rv;
}
libc_hidden_def(vsnprintf)
#else
#warning Skipping vsnprintf since no buffering, no custom streams, and not old vfprintf!
#ifdef __STDIO_HAS_VSNPRINTF
#error WHOA! __STDIO_HAS_VSNPRINTF is defined!
#endif
#endif