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 #if defined(HAVE__VSNPRINTF) && !defined(HAVE_VSNPRINTF)
36 #undef HAVE_VSNPRINTF
37 #undef vsnprintf
38 #define HAVE_VSNPRINTF 1
39 #define vsnprintf _vsnprintf
40 #endif
41 
42 #ifndef _PATH_DEVNULL
43 #define _PATH_DEVNULL "/dev/null"
44 #endif
45 
46 #define CHUNKSIZE 512
47 int
tds_vasprintf(char ** ret,const char * fmt,va_list ap)48 tds_vasprintf(char **ret, const char *fmt, va_list ap)
49 {
50 #if HAVE__VSCPRINTF
51 	int len = _vscprintf(fmt, ap);
52 
53 	if (len >= 0) {
54 		*ret = malloc(len + 1);
55 		if (*ret) {
56 			vsprintf(*ret, fmt, ap);
57 			return len;
58 		}
59 		errno = ENOMEM;
60 	}
61 	*ret = NULL;
62 	return -1;
63 #elif HAVE_VSNPRINTF
64 	size_t chunks;
65 	size_t buflen;
66 	char *buf;
67 	int len;
68 
69 	chunks = ((strlen(fmt) + 1) / CHUNKSIZE) + 1;
70 	buflen = chunks * CHUNKSIZE;
71 	for (;;) {
72 		if ((buf = malloc(buflen)) == NULL) {
73 			errno = ENOMEM;
74 			*ret = NULL;
75 			return -1;
76 		}
77 		len = vsnprintf(buf, buflen, fmt, ap);
78 		if (0 <= len && (size_t) len < buflen - 1) {
79 			break;
80 		}
81 		free(buf);
82 		buflen = (++chunks) * CHUNKSIZE;
83 		/*
84 		 * len >= 0 is required for vsnprintf implementations that
85 		 * return -1 for insufficient buffer
86 		 */
87 		if (len >= 0 && buflen <= (size_t) len) {
88 			buflen = len + 1;
89 		}
90 	}
91 	*ret = buf;
92 	return len;
93 #else /* HAVE_VSNPRINTF */
94 #ifdef _REENTRANT
95 	FILE *fp;
96 #else /* !_REENTRANT */
97 	static FILE *fp = NULL;
98 #endif /* !_REENTRANT */
99 	int len;
100 	char *buf;
101 
102 	*ret = NULL;
103 
104 #ifdef _REENTRANT
105 
106 # ifdef _WIN32
107 #  error Win32 do not have /dev/null, should use vsnprintf version
108 # endif
109 
110 	if ((fp = fopen(_PATH_DEVNULL, "w")) == NULL)
111 		return -1;
112 #else /* !_REENTRANT */
113 	if ((fp == NULL) && ((fp = fopen(_PATH_DEVNULL, "w")) == NULL))
114 		return -1;
115 #endif /* !_REENTRANT */
116 
117 	len = vfprintf(fp, fmt, ap);
118 
119 #ifdef _REENTRANT
120 	if (fclose(fp) != 0)
121 		return -1;
122 #endif /* _REENTRANT */
123 
124 	if (len < 0)
125 		return len;
126 	if ((buf = malloc(len + 1)) == NULL) {
127 		errno = ENOMEM;
128 		return -1;
129 	}
130 	if (vsprintf(buf, fmt, ap) != len)
131 		return -1;
132 	*ret = buf;
133 	return len;
134 #endif /* HAVE_VSNPRINTF */
135 }
136