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