1 /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
2  *
3  * GNU Library General Public License (LGPL) version 2 or later.
4  *
5  * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
6  */
7 
8 #include <features.h>
9 
10 #ifdef __USE_GNU
11 #include "_stdio.h"
12 #include <stdarg.h>
13 #include <bits/uClibc_va_copy.h>
14 
15 #ifndef __STDIO_HAS_VSNPRINTF
16 #warning Skipping vasprintf since no vsnprintf!
17 #else
18 
vasprintf(char ** __restrict buf,const char * __restrict format,va_list arg)19 int vasprintf(char **__restrict buf, const char * __restrict format,
20 			 va_list arg)
21 {
22 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
23 
24 	FILE *f;
25 	size_t size;
26 	int rv = -1;
27 
28 	*buf = NULL;
29 
30 	if ((f = open_memstream(buf, &size)) != NULL) {
31 		rv = vfprintf(f, format, arg);
32 		fclose(f);
33 		if (rv < 0) {
34 			free(*buf);
35 			*buf = NULL;
36 		} else {
37 			*buf = realloc(*buf, rv + 1);
38 		}
39 	}
40 
41 	assert(rv >= -1);
42 
43 	return rv;
44 
45 #else  /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */
46 
47 	/* This implementation actually calls the printf machinery twice, but
48 	 * only does one malloc.  This can be a problem though when custom printf
49 	 * specs or the %m specifier are involved because the results of the
50 	 * second call might be different from the first. */
51 	va_list arg2;
52 	int rv;
53 
54 	va_copy(arg2, arg);
55  	rv = vsnprintf(NULL, 0, format, arg2);
56 	va_end(arg2);
57 
58 	*buf = NULL;
59 
60 	if (rv >= 0) {
61 		if ((*buf = malloc(++rv)) != NULL) {
62 			if ((rv = vsnprintf(*buf, rv, format, arg)) < 0) {
63 				free(*buf);
64 				*buf = NULL;
65 			}
66 		}
67 	}
68 
69 	assert(rv >= -1);
70 
71 	return rv;
72 
73 #endif /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */
74 }
75 libc_hidden_def(vasprintf)
76 
77 #endif
78 #endif
79