1 /* Formatted output to strings, using POSIX/XSI format strings with positions.
2 Copyright (C) 2003, 2006-2007 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 __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. */
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 #include "wprintf-parse.h"
289 /* Define auxiliary functions declared in "wprintf-parse.h". */
290 #define CHAR_T wchar_t
291 #define DIRECTIVE wchar_t_directive
292 #define DIRECTIVES wchar_t_directives
293 #define PRINTF_PARSE wprintf_parse
294 #include "printf-parse.c"
295
296 /* Define functions declared in "vasnprintf.h". */
297 #define vasnwprintf libintl_vasnwprintf
298 #include "vasnprintf.c"
299 #if 0 /* not needed */
300 #define asnwprintf libintl_asnwprintf
301 #include "asnprintf.c"
302 #endif
303
304 # if HAVE_DECL__SNWPRINTF
305 /* Windows. */
306 # define system_vswprintf _vsnwprintf
307 # else
308 /* Unix. */
309 # define system_vswprintf vswprintf
310 # endif
311
312 DLL_EXPORTED
313 int
libintl_vfwprintf(FILE * stream,const wchar_t * format,va_list args)314 libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
315 {
316 if (wcschr (format, '$') == NULL)
317 return vfwprintf (stream, format, args);
318 else
319 {
320 size_t length;
321 wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
322 int retval = -1;
323 if (result != NULL)
324 {
325 size_t i;
326 for (i = 0; i < length; i++)
327 if (fputwc (result[i], stream) == WEOF)
328 break;
329 free (result);
330 if (i == length)
331 {
332 if (length > INT_MAX)
333 errno = EOVERFLOW;
334 else
335 retval = length;
336 }
337 }
338 return retval;
339 }
340 }
341
342 DLL_EXPORTED
343 int
libintl_fwprintf(FILE * stream,const wchar_t * format,...)344 libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
345 {
346 va_list args;
347 int retval;
348
349 va_start (args, format);
350 retval = libintl_vfwprintf (stream, format, args);
351 va_end (args);
352 return retval;
353 }
354
355 DLL_EXPORTED
356 int
libintl_vwprintf(const wchar_t * format,va_list args)357 libintl_vwprintf (const wchar_t *format, va_list args)
358 {
359 return libintl_vfwprintf (stdout, format, args);
360 }
361
362 DLL_EXPORTED
363 int
libintl_wprintf(const wchar_t * format,...)364 libintl_wprintf (const wchar_t *format, ...)
365 {
366 va_list args;
367 int retval;
368
369 va_start (args, format);
370 retval = libintl_vwprintf (format, args);
371 va_end (args);
372 return retval;
373 }
374
375 DLL_EXPORTED
376 int
libintl_vswprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,va_list args)377 libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
378 {
379 if (wcschr (format, '$') == NULL)
380 return system_vswprintf (resultbuf, length, format, args);
381 else
382 {
383 size_t maxlength = length;
384 wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
385 if (result != resultbuf)
386 {
387 if (maxlength > 0)
388 {
389 size_t pruned_length =
390 (length < maxlength ? length : maxlength - 1);
391 memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
392 resultbuf[pruned_length] = 0;
393 }
394 free (result);
395 /* Unlike vsnprintf, which has to return the number of character that
396 would have been produced if the resultbuf had been sufficiently
397 large, the vswprintf function has to return a negative value if
398 the resultbuf was not sufficiently large. */
399 if (length >= maxlength)
400 return -1;
401 }
402 if (length > INT_MAX)
403 {
404 errno = EOVERFLOW;
405 return -1;
406 }
407 else
408 return length;
409 }
410 }
411
412 DLL_EXPORTED
413 int
libintl_swprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,...)414 libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
415 {
416 va_list args;
417 int retval;
418
419 va_start (args, format);
420 retval = libintl_vswprintf (resultbuf, length, format, args);
421 va_end (args);
422 return retval;
423 }
424
425 #endif
426
427 #endif
428