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