1 /* Formatted output to strings, using POSIX/XSI format strings with positions.
2 Copyright (C) 2003, 2006-2007, 2009-2011 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
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #ifdef __GNUC__
23 # define alloca __builtin_alloca
24 # define HAVE_ALLOCA 1
25 #else
26 # ifdef _MSC_VER
27 # include <malloc.h>
28 # define alloca _alloca
29 # else
30 # if defined HAVE_ALLOCA_H || defined _LIBC
31 # include <alloca.h>
32 # else
33 # ifdef _AIX
34 #pragma alloca
35 # else
36 # ifndef alloca
37 char *alloca ();
38 # endif
39 # endif
40 # endif
41 # endif
42 #endif
43
44 #include <stdio.h>
45
46 #if !HAVE_POSIX_PRINTF
47
48 #include <errno.h>
49 #include <limits.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
54 #ifndef EOVERFLOW
55 # define EOVERFLOW E2BIG
56 #endif
57
58 /* When building a DLL, we must export some functions. Note that because
59 the functions are only defined for binary backward compatibility, we
60 don't need to use __declspec(dllimport) in any case. */
61 #if HAVE_VISIBILITY && BUILDING_DLL
62 # define DLL_EXPORTED __attribute__((__visibility__("default")))
63 #elif 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.in.h. */
72 #if defined __NetBSD__ || defined __BEOS__ || 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. The mingw function vsnprintf() has fewer bugs than the MSVCRT
195 function _vsnprintf(), so prefer that. */
196 # if defined __MINGW32__
197 # define system_vsnprintf vsnprintf
198 # else
199 # define system_vsnprintf _vsnprintf
200 # endif
201 # else
202 /* Unix. */
203 # define system_vsnprintf vsnprintf
204 # endif
205
206 DLL_EXPORTED
207 int
libintl_vsnprintf(char * resultbuf,size_t length,const char * format,va_list args)208 libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
209 {
210 if (strchr (format, '$') == NULL)
211 return system_vsnprintf (resultbuf, length, format, args);
212 else
213 {
214 size_t maxlength = length;
215 char *result = libintl_vasnprintf (resultbuf, &length, format, args);
216 if (result == NULL)
217 return -1;
218 if (result != resultbuf)
219 {
220 if (maxlength > 0)
221 {
222 size_t pruned_length =
223 (length < maxlength ? length : maxlength - 1);
224 memcpy (resultbuf, result, pruned_length);
225 resultbuf[pruned_length] = '\0';
226 }
227 free (result);
228 }
229 if (length > INT_MAX)
230 {
231 errno = EOVERFLOW;
232 return -1;
233 }
234 else
235 return length;
236 }
237 }
238
239 DLL_EXPORTED
240 int
libintl_snprintf(char * resultbuf,size_t length,const char * format,...)241 libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
242 {
243 va_list args;
244 int retval;
245
246 va_start (args, format);
247 retval = libintl_vsnprintf (resultbuf, length, format, args);
248 va_end (args);
249 return retval;
250 }
251
252 #endif
253
254 #if HAVE_ASPRINTF
255
256 DLL_EXPORTED
257 int
libintl_vasprintf(char ** resultp,const char * format,va_list args)258 libintl_vasprintf (char **resultp, const char *format, va_list args)
259 {
260 size_t length;
261 char *result = libintl_vasnprintf (NULL, &length, format, args);
262 if (result == NULL)
263 return -1;
264 if (length > INT_MAX)
265 {
266 free (result);
267 errno = EOVERFLOW;
268 return -1;
269 }
270 *resultp = result;
271 return length;
272 }
273
274 DLL_EXPORTED
275 int
libintl_asprintf(char ** resultp,const char * format,...)276 libintl_asprintf (char **resultp, const char *format, ...)
277 {
278 va_list args;
279 int retval;
280
281 va_start (args, format);
282 retval = libintl_vasprintf (resultp, format, args);
283 va_end (args);
284 return retval;
285 }
286
287 #endif
288
289 #if HAVE_FWPRINTF
290
291 #include <wchar.h>
292
293 #define WIDE_CHAR_VERSION 1
294
295 #include "wprintf-parse.h"
296 /* Define auxiliary functions declared in "wprintf-parse.h". */
297 #define CHAR_T wchar_t
298 #define DIRECTIVE wchar_t_directive
299 #define DIRECTIVES wchar_t_directives
300 #define PRINTF_PARSE wprintf_parse
301 #include "printf-parse.c"
302
303 /* Define functions declared in "vasnprintf.h". */
304 #define vasnwprintf libintl_vasnwprintf
305 #include "vasnprintf.c"
306 #if 0 /* not needed */
307 #define asnwprintf libintl_asnwprintf
308 #include "asnprintf.c"
309 #endif
310
311 # if HAVE_DECL__SNWPRINTF
312 /* Windows. The function vswprintf() has a different signature than
313 on Unix; we use the function _vsnwprintf() instead. */
314 # define system_vswprintf _vsnwprintf
315 # else
316 /* Unix. */
317 # define system_vswprintf vswprintf
318 # endif
319
320 DLL_EXPORTED
321 int
libintl_vfwprintf(FILE * stream,const wchar_t * format,va_list args)322 libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
323 {
324 if (wcschr (format, '$') == NULL)
325 return vfwprintf (stream, format, args);
326 else
327 {
328 size_t length;
329 wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
330 int retval = -1;
331 if (result != NULL)
332 {
333 size_t i;
334 for (i = 0; i < length; i++)
335 if (fputwc (result[i], stream) == WEOF)
336 break;
337 free (result);
338 if (i == length)
339 {
340 if (length > INT_MAX)
341 errno = EOVERFLOW;
342 else
343 retval = length;
344 }
345 }
346 return retval;
347 }
348 }
349
350 DLL_EXPORTED
351 int
libintl_fwprintf(FILE * stream,const wchar_t * format,...)352 libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
353 {
354 va_list args;
355 int retval;
356
357 va_start (args, format);
358 retval = libintl_vfwprintf (stream, format, args);
359 va_end (args);
360 return retval;
361 }
362
363 DLL_EXPORTED
364 int
libintl_vwprintf(const wchar_t * format,va_list args)365 libintl_vwprintf (const wchar_t *format, va_list args)
366 {
367 return libintl_vfwprintf (stdout, format, args);
368 }
369
370 DLL_EXPORTED
371 int
libintl_wprintf(const wchar_t * format,...)372 libintl_wprintf (const wchar_t *format, ...)
373 {
374 va_list args;
375 int retval;
376
377 va_start (args, format);
378 retval = libintl_vwprintf (format, args);
379 va_end (args);
380 return retval;
381 }
382
383 DLL_EXPORTED
384 int
libintl_vswprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,va_list args)385 libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
386 {
387 if (wcschr (format, '$') == NULL)
388 return system_vswprintf (resultbuf, length, format, args);
389 else
390 {
391 size_t maxlength = length;
392 wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
393 if (result == NULL)
394 return -1;
395 if (result != resultbuf)
396 {
397 if (maxlength > 0)
398 {
399 size_t pruned_length =
400 (length < maxlength ? length : maxlength - 1);
401 memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
402 resultbuf[pruned_length] = 0;
403 }
404 free (result);
405 /* Unlike vsnprintf, which has to return the number of character that
406 would have been produced if the resultbuf had been sufficiently
407 large, the vswprintf function has to return a negative value if
408 the resultbuf was not sufficiently large. */
409 if (length >= maxlength)
410 return -1;
411 }
412 if (length > INT_MAX)
413 {
414 errno = EOVERFLOW;
415 return -1;
416 }
417 else
418 return length;
419 }
420 }
421
422 DLL_EXPORTED
423 int
libintl_swprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,...)424 libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
425 {
426 va_list args;
427 int retval;
428
429 va_start (args, format);
430 retval = libintl_vswprintf (resultbuf, length, format, args);
431 va_end (args);
432 return retval;
433 }
434
435 #endif
436
437 #endif
438