123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /* 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
|