1 /*
2  * vasprintf(3)
3  * 20020809 entropy@tappedin.com
4  * public domain.  no warranty.  use at your own risk.  have a nice day.
5  */
6 
7 #include <config.h>
8 
9 #include <stdarg.h>
10 #include <stdio.h>
11 
12 #if HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif /* HAVE_STDLIB_H */
15 
16 #if HAVE_ERRNO_H
17 #include <errno.h>
18 #endif /* HAVE_ERRNO_H */
19 
20 #if HAVE_STRING_H
21 #include <string.h>
22 #endif /* HAVE_STRING_H */
23 
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif /* HAVE_UNISTD_H */
27 
28 #if HAVE_PATHS_H
29 #include <paths.h>
30 #endif /* HAVE_PATHS_H */
31 
32 #include <freetds/sysdep_private.h>
33 #include "replacements.h"
34 
35 TDS_RCSID(var, "$Id: vasprintf.c 487464 2015-12-17 19:10:00Z ucko $");
36 
37 #if defined(HAVE__VSNPRINTF) && !defined(HAVE_VSNPRINTF)
38 #undef HAVE_VSNPRINTF
39 #undef vsnprintf
40 #define HAVE_VSNPRINTF 1
41 #define vsnprintf _vsnprintf
42 #endif
43 
44 #ifndef _PATH_DEVNULL
45 #define _PATH_DEVNULL "/dev/null"
46 #endif
47 
48 #define CHUNKSIZE 512
49 int
vasprintf(char ** ret,const char * fmt,va_list ap)50 vasprintf(char **ret, const char *fmt, va_list ap)
51 {
52 #if HAVE__VSCPRINTF
53 	int len = _vscprintf(fmt, ap);
54 
55 	if (len >= 0) {
56 		*ret = malloc(len + 1);
57 		if (*ret) {
58 			vsprintf(*ret, fmt, ap);
59 			return len;
60 		}
61 		errno = ENOMEM;
62 	}
63 	*ret = NULL;
64 	return -1;
65 #elif HAVE_VSNPRINTF
66 	size_t chunks;
67 	size_t buflen;
68 	char *buf;
69 	int len;
70 
71 	chunks = ((strlen(fmt) + 1) / CHUNKSIZE) + 1;
72 	buflen = chunks * CHUNKSIZE;
73 	for (;;) {
74 		if ((buf = malloc(buflen)) == NULL) {
75 			errno = ENOMEM;
76 			*ret = NULL;
77 			return -1;
78 		}
79 		len = vsnprintf(buf, buflen, fmt, ap);
80 		if (0 <= len && (size_t) len < buflen - 1) {
81 			break;
82 		}
83 		free(buf);
84 		buflen = (++chunks) * CHUNKSIZE;
85 		/*
86 		 * len >= 0 is required for vsnprintf implementations that
87 		 * return -1 for insufficient buffer
88 		 */
89 		if (len >= 0 && buflen <= (size_t) len) {
90 			buflen = len + 1;
91 		}
92 	}
93 	*ret = buf;
94 	return len;
95 #else /* HAVE_VSNPRINTF */
96 #ifdef _REENTRANT
97 	FILE *fp;
98 #else /* !_REENTRANT */
99 	static FILE *fp = NULL;
100 #endif /* !_REENTRANT */
101 	int len;
102 	char *buf;
103 
104 	*ret = NULL;
105 
106 #ifdef _REENTRANT
107 
108 # ifdef _WIN32
109 #  error Win32 do not have /dev/null, should use vsnprintf version
110 # endif
111 
112 	if ((fp = fopen(_PATH_DEVNULL, "w")) == NULL)
113 		return -1;
114 #else /* !_REENTRANT */
115 	if ((fp == NULL) && ((fp = fopen(_PATH_DEVNULL, "w")) == NULL))
116 		return -1;
117 #endif /* !_REENTRANT */
118 
119 	len = vfprintf(fp, fmt, ap);
120 
121 #ifdef _REENTRANT
122 	if (fclose(fp) != 0)
123 		return -1;
124 #endif /* _REENTRANT */
125 
126 	if (len < 0)
127 		return len;
128 	if ((buf = malloc(len + 1)) == NULL) {
129 		errno = ENOMEM;
130 		return -1;
131 	}
132 	if (vsprintf(buf, fmt, ap) != len)
133 		return -1;
134 	*ret = buf;
135 	return len;
136 #endif /* HAVE_VSNPRINTF */
137 }
138