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