1 /* Formatted output to strings, using POSIX/XSI format strings with positions.
2 Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU Library General Public License as published
7 by the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #ifdef __GNUC__
25 # define alloca __builtin_alloca
26 # define HAVE_ALLOCA 1
27 #else
28 # ifdef _MSC_VER
29 # include <malloc.h>
30 # define alloca _alloca
31 # else
32 # if defined HAVE_ALLOCA_H || defined _LIBC
33 # include <alloca.h>
34 # else
35 # ifdef _AIX
36 #pragma alloca
37 # else
38 # ifndef alloca
39 char *alloca ();
40 # endif
41 # endif
42 # endif
43 # endif
44 #endif
45
46 #include <stdio.h>
47
48 #if !HAVE_POSIX_PRINTF
49
50 #include <errno.h>
51 #include <limits.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
56 #ifndef EOVERFLOW
57 # define EOVERFLOW E2BIG
58 #endif
59
60 /* When building a DLL, we must export some functions. Note that because
61 the functions are only defined for binary backward compatibility, we
62 don't need to use __declspec(dllimport) in any case. */
63 #if defined _MSC_VER && BUILDING_DLL
64 # define DLL_EXPORTED __declspec(dllexport)
65 #else
66 # define DLL_EXPORTED
67 #endif
68
69 #define STATIC static
70
71 /* This needs to be consistent with libgnuintl.h.in. */
72 #if defined __NetBSD__ || defined __CYGWIN__ || defined __MINGW32__
73 /* Don't break __attribute__((format(printf,M,N))).
74 This redefinition is only possible because the libc in NetBSD, Cygwin,
75 mingw does not have a function __printf__. */
76 # define libintl_printf __printf__
77 #endif
78
79 /* Define auxiliary functions declared in "printf-args.h". */
80 #include "printf-args.c"
81
82 /* Define auxiliary functions declared in "printf-parse.h". */
83 #include "printf-parse.c"
84
85 /* Define functions declared in "vasnprintf.h". */
86 #define vasnprintf libintl_vasnprintf
87 #include "vasnprintf.c"
88 #if 0 /* not needed */
89 #define asnprintf libintl_asnprintf
90 #include "asnprintf.c"
91 #endif
92
93 DLL_EXPORTED
94 int
libintl_vfprintf(FILE * stream,const char * format,va_list args)95 libintl_vfprintf (FILE *stream, const char *format, va_list args)
96 {
97 if (strchr (format, '$') == NULL)
98 return vfprintf (stream, format, args);
99 else
100 {
101 size_t length;
102 char *result = libintl_vasnprintf (NULL, &length, format, args);
103 int retval = -1;
104 if (result != NULL)
105 {
106 size_t written = fwrite (result, 1, length, stream);
107 free (result);
108 if (written == length)
109 {
110 if (length > INT_MAX)
111 errno = EOVERFLOW;
112 else
113 retval = length;
114 }
115 }
116 return retval;
117 }
118 }
119
120 DLL_EXPORTED
121 int
libintl_fprintf(FILE * stream,const char * format,...)122 libintl_fprintf (FILE *stream, const char *format, ...)
123 {
124 va_list args;
125 int retval;
126
127 va_start (args, format);
128 retval = libintl_vfprintf (stream, format, args);
129 va_end (args);
130 return retval;
131 }
132
133 DLL_EXPORTED
134 int
libintl_vprintf(const char * format,va_list args)135 libintl_vprintf (const char *format, va_list args)
136 {
137 return libintl_vfprintf (stdout, format, args);
138 }
139
140 DLL_EXPORTED
141 int
libintl_printf(const char * format,...)142 libintl_printf (const char *format, ...)
143 {
144 va_list args;
145 int retval;
146
147 va_start (args, format);
148 retval = libintl_vprintf (format, args);
149 va_end (args);
150 return retval;
151 }
152
153 DLL_EXPORTED
154 int
libintl_vsprintf(char * resultbuf,const char * format,va_list args)155 libintl_vsprintf (char *resultbuf, const char *format, va_list args)
156 {
157 if (strchr (format, '$') == NULL)
158 return vsprintf (resultbuf, format, args);
159 else
160 {
161 size_t length = (size_t) ~0 / (4 * sizeof (char));
162 char *result = libintl_vasnprintf (resultbuf, &length, format, args);
163 if (result != resultbuf)
164 {
165 free (result);
166 return -1;
167 }
168 if (length > INT_MAX)
169 {
170 errno = EOVERFLOW;
171 return -1;
172 }
173 else
174 return length;
175 }
176 }
177
178 DLL_EXPORTED
179 int
libintl_sprintf(char * resultbuf,const char * format,...)180 libintl_sprintf (char *resultbuf, const char *format, ...)
181 {
182 va_list args;
183 int retval;
184
185 va_start (args, format);
186 retval = libintl_vsprintf (resultbuf, format, args);
187 va_end (args);
188 return retval;
189 }
190
191 #if HAVE_SNPRINTF
192
193 # if HAVE_DECL__SNPRINTF
194 /* Windows. */
195 # define system_vsnprintf _vsnprintf
196 # else
197 /* Unix. */
198 # define system_vsnprintf vsnprintf
199 # endif
200
201 DLL_EXPORTED
202 int
libintl_vsnprintf(char * resultbuf,size_t length,const char * format,va_list args)203 libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
204 {
205 if (strchr (format, '$') == NULL)
206 return system_vsnprintf (resultbuf, length, format, args);
207 else
208 {
209 size_t maxlength = length;
210 char *result = libintl_vasnprintf (resultbuf, &length, format, args);
211 if (result != resultbuf)
212 {
213 if (maxlength > 0)
214 {
215 size_t pruned_length =
216 (length < maxlength ? length : maxlength - 1);
217 memcpy (resultbuf, result, pruned_length);
218 resultbuf[pruned_length] = '\0';
219 }
220 free (result);
221 }
222 if (length > INT_MAX)
223 {
224 errno = EOVERFLOW;
225 return -1;
226 }
227 else
228 return length;
229 }
230 }
231
232 DLL_EXPORTED
233 int
libintl_snprintf(char * resultbuf,size_t length,const char * format,...)234 libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
235 {
236 va_list args;
237 int retval;
238
239 va_start (args, format);
240 retval = libintl_vsnprintf (resultbuf, length, format, args);
241 va_end (args);
242 return retval;
243 }
244
245 #endif
246
247 #if HAVE_ASPRINTF
248
249 DLL_EXPORTED
250 int
libintl_vasprintf(char ** resultp,const char * format,va_list args)251 libintl_vasprintf (char **resultp, const char *format, va_list args)
252 {
253 size_t length;
254 char *result = libintl_vasnprintf (NULL, &length, format, args);
255 if (result == NULL)
256 return -1;
257 if (length > INT_MAX)
258 {
259 free (result);
260 errno = EOVERFLOW;
261 return -1;
262 }
263 *resultp = result;
264 return length;
265 }
266
267 DLL_EXPORTED
268 int
libintl_asprintf(char ** resultp,const char * format,...)269 libintl_asprintf (char **resultp, const char *format, ...)
270 {
271 va_list args;
272 int retval;
273
274 va_start (args, format);
275 retval = libintl_vasprintf (resultp, format, args);
276 va_end (args);
277 return retval;
278 }
279
280 #endif
281
282 #if HAVE_FWPRINTF
283
284 #include <wchar.h>
285
286 #define WIDE_CHAR_VERSION 1
287
288 /* Define auxiliary functions declared in "wprintf-parse.h". */
289 #include "printf-parse.c"
290
291 /* Define functions declared in "vasnprintf.h". */
292 #define vasnwprintf libintl_vasnwprintf
293 #include "vasnprintf.c"
294 #if 0 /* not needed */
295 #define asnwprintf libintl_asnwprintf
296 #include "asnprintf.c"
297 #endif
298
299 # if HAVE_DECL__SNWPRINTF
300 /* Windows. */
301 # define system_vswprintf _vsnwprintf
302 # else
303 /* Unix. */
304 # define system_vswprintf vswprintf
305 # endif
306
307 DLL_EXPORTED
308 int
libintl_vfwprintf(FILE * stream,const wchar_t * format,va_list args)309 libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
310 {
311 if (wcschr (format, '$') == NULL)
312 return vfwprintf (stream, format, args);
313 else
314 {
315 size_t length;
316 wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
317 int retval = -1;
318 if (result != NULL)
319 {
320 size_t i;
321 for (i = 0; i < length; i++)
322 if (fputwc (result[i], stream) == WEOF)
323 break;
324 free (result);
325 if (i == length)
326 {
327 if (length > INT_MAX)
328 errno = EOVERFLOW;
329 else
330 retval = length;
331 }
332 }
333 return retval;
334 }
335 }
336
337 DLL_EXPORTED
338 int
libintl_fwprintf(FILE * stream,const wchar_t * format,...)339 libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
340 {
341 va_list args;
342 int retval;
343
344 va_start (args, format);
345 retval = libintl_vfwprintf (stream, format, args);
346 va_end (args);
347 return retval;
348 }
349
350 DLL_EXPORTED
351 int
libintl_vwprintf(const wchar_t * format,va_list args)352 libintl_vwprintf (const wchar_t *format, va_list args)
353 {
354 return libintl_vfwprintf (stdout, format, args);
355 }
356
357 DLL_EXPORTED
358 int
libintl_wprintf(const wchar_t * format,...)359 libintl_wprintf (const wchar_t *format, ...)
360 {
361 va_list args;
362 int retval;
363
364 va_start (args, format);
365 retval = libintl_vwprintf (format, args);
366 va_end (args);
367 return retval;
368 }
369
370 DLL_EXPORTED
371 int
libintl_vswprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,va_list args)372 libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
373 {
374 if (wcschr (format, '$') == NULL)
375 return system_vswprintf (resultbuf, length, format, args);
376 else
377 {
378 size_t maxlength = length;
379 wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
380 if (result != resultbuf)
381 {
382 if (maxlength > 0)
383 {
384 size_t pruned_length =
385 (length < maxlength ? length : maxlength - 1);
386 memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
387 resultbuf[pruned_length] = 0;
388 }
389 free (result);
390 /* Unlike vsnprintf, which has to return the number of character that
391 would have been produced if the resultbuf had been sufficiently
392 large, the vswprintf function has to return a negative value if
393 the resultbuf was not sufficiently large. */
394 if (length >= maxlength)
395 return -1;
396 }
397 if (length > INT_MAX)
398 {
399 errno = EOVERFLOW;
400 return -1;
401 }
402 else
403 return length;
404 }
405 }
406
407 DLL_EXPORTED
408 int
libintl_swprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,...)409 libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
410 {
411 va_list args;
412 int retval;
413
414 va_start (args, format);
415 retval = libintl_vswprintf (resultbuf, length, format, args);
416 va_end (args);
417 return retval;
418 }
419
420 #endif
421
422 #endif
423