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