• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Formatted output to strings, using POSIX/XSI format strings with positions.
2    Copyright (C) 2003, 2006-2007, 2009-2011, 2018, 2020 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 <https://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 /* You can enable this for debugging on Windows.  But not in a release!  */
72 #if 0
73 # define ENABLE_WCHAR_FALLBACK 1
74 #endif
75 
76 /* This needs to be consistent with libgnuintl.in.h.  */
77 #if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
78 /* Don't break __attribute__((format(printf,M,N))).
79    This redefinition is only possible because the libc in NetBSD, Cygwin,
80    mingw does not have a function __printf__.  */
81 # define libintl_printf __printf__
82 #endif
83 
84 /* Define auxiliary functions declared in "printf-args.h".  */
85 #include "printf-args.c"
86 
87 /* Define auxiliary functions declared in "printf-parse.h".  */
88 #include "printf-parse.c"
89 
90 /* Define functions declared in "vasnprintf.h".  */
91 #define vasnprintf libintl_vasnprintf
92 #include "vasnprintf.c"
93 #if 0 /* not needed */
94 #define asnprintf libintl_asnprintf
95 #include "asnprintf.c"
96 #endif
97 
98 /* Users don't expect libintl_fprintf to be less POSIX compliant
99    than the fprintf implementation provided by gnulib or - on mingw -
100    the one provided by mingw libs when __USE_MINGW_ANSI_STDIO is in
101    effect.  */
102 #define USE_REPLACEMENT_CODE_ALWAYS 1
103 
104 DLL_EXPORTED
105 int
libintl_vfprintf(FILE * stream,const char * format,va_list args)106 libintl_vfprintf (FILE *stream, const char *format, va_list args)
107 {
108 #if !USE_REPLACEMENT_CODE_ALWAYS
109   if (strchr (format, '$') == NULL)
110     return vfprintf (stream, format, args);
111   else
112 #endif
113     {
114       size_t length;
115       char *result = libintl_vasnprintf (NULL, &length, format, args);
116       int retval = -1;
117       if (result != NULL)
118         {
119           size_t written = fwrite (result, 1, length, stream);
120           free (result);
121           if (written == length)
122             {
123               if (length > INT_MAX)
124                 errno = EOVERFLOW;
125               else
126                 retval = length;
127             }
128         }
129       return retval;
130     }
131 }
132 
133 DLL_EXPORTED
134 int
libintl_fprintf(FILE * stream,const char * format,...)135 libintl_fprintf (FILE *stream, const char *format, ...)
136 {
137   va_list args;
138   int retval;
139 
140   va_start (args, format);
141   retval = libintl_vfprintf (stream, format, args);
142   va_end (args);
143   return retval;
144 }
145 
146 DLL_EXPORTED
147 int
libintl_vprintf(const char * format,va_list args)148 libintl_vprintf (const char *format, va_list args)
149 {
150   return libintl_vfprintf (stdout, format, args);
151 }
152 
153 DLL_EXPORTED
154 int
libintl_printf(const char * format,...)155 libintl_printf (const char *format, ...)
156 {
157   va_list args;
158   int retval;
159 
160   va_start (args, format);
161   retval = libintl_vprintf (format, args);
162   va_end (args);
163   return retval;
164 }
165 
166 DLL_EXPORTED
167 int
libintl_vsprintf(char * resultbuf,const char * format,va_list args)168 libintl_vsprintf (char *resultbuf, const char *format, va_list args)
169 {
170 #if !USE_REPLACEMENT_CODE_ALWAYS
171   if (strchr (format, '$') == NULL)
172     return vsprintf (resultbuf, format, args);
173   else
174 #endif
175     {
176       size_t length = (size_t) ~0 / (4 * sizeof (char));
177       char *result = libintl_vasnprintf (resultbuf, &length, format, args);
178       if (result != resultbuf)
179         {
180           free (result);
181           return -1;
182         }
183       if (length > INT_MAX)
184         {
185           errno = EOVERFLOW;
186           return -1;
187         }
188       else
189         return length;
190     }
191 }
192 
193 DLL_EXPORTED
194 int
libintl_sprintf(char * resultbuf,const char * format,...)195 libintl_sprintf (char *resultbuf, const char *format, ...)
196 {
197   va_list args;
198   int retval;
199 
200   va_start (args, format);
201   retval = libintl_vsprintf (resultbuf, format, args);
202   va_end (args);
203   return retval;
204 }
205 
206 #if HAVE_SNPRINTF
207 
208 # if HAVE_DECL__SNPRINTF
209    /* Windows.  The mingw function vsnprintf() has fewer bugs than the MSVCRT
210       function _vsnprintf(), so prefer that.  */
211 #  if defined __MINGW32__
212 #   define system_vsnprintf vsnprintf
213 #  else
214 #   define system_vsnprintf _vsnprintf
215 #  endif
216 # else
217    /* Unix.  */
218 #  define system_vsnprintf vsnprintf
219 # endif
220 
221 DLL_EXPORTED
222 int
libintl_vsnprintf(char * resultbuf,size_t length,const char * format,va_list args)223 libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
224 {
225 # if !USE_REPLACEMENT_CODE_ALWAYS
226   if (strchr (format, '$') == NULL)
227     return system_vsnprintf (resultbuf, length, format, args);
228   else
229 # endif
230     {
231       size_t maxlength = length;
232       char *result = libintl_vasnprintf (resultbuf, &length, format, args);
233       if (result == NULL)
234         return -1;
235       if (result != resultbuf)
236         {
237           if (maxlength > 0)
238             {
239               size_t pruned_length =
240                 (length < maxlength ? length : maxlength - 1);
241               memcpy (resultbuf, result, pruned_length);
242               resultbuf[pruned_length] = '\0';
243             }
244           free (result);
245         }
246       if (length > INT_MAX)
247         {
248           errno = EOVERFLOW;
249           return -1;
250         }
251       else
252         return length;
253     }
254 }
255 
256 DLL_EXPORTED
257 int
libintl_snprintf(char * resultbuf,size_t length,const char * format,...)258 libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
259 {
260   va_list args;
261   int retval;
262 
263   va_start (args, format);
264   retval = libintl_vsnprintf (resultbuf, length, format, args);
265   va_end (args);
266   return retval;
267 }
268 
269 #endif
270 
271 #if HAVE_ASPRINTF
272 
273 DLL_EXPORTED
274 int
libintl_vasprintf(char ** resultp,const char * format,va_list args)275 libintl_vasprintf (char **resultp, const char *format, va_list args)
276 {
277   size_t length;
278   char *result = libintl_vasnprintf (NULL, &length, format, args);
279   if (result == NULL)
280     return -1;
281   if (length > INT_MAX)
282     {
283       free (result);
284       errno = EOVERFLOW;
285       return -1;
286     }
287   *resultp = result;
288   return length;
289 }
290 
291 DLL_EXPORTED
292 int
libintl_asprintf(char ** resultp,const char * format,...)293 libintl_asprintf (char **resultp, const char *format, ...)
294 {
295   va_list args;
296   int retval;
297 
298   va_start (args, format);
299   retval = libintl_vasprintf (resultp, format, args);
300   va_end (args);
301   return retval;
302 }
303 
304 #endif
305 
306 #if HAVE_FWPRINTF
307 
308 #include <wchar.h>
309 
310 #define WIDE_CHAR_VERSION 1
311 
312 #include "wprintf-parse.h"
313 /* Define auxiliary functions declared in "wprintf-parse.h".  */
314 #define CHAR_T wchar_t
315 #define DIRECTIVE wchar_t_directive
316 #define DIRECTIVES wchar_t_directives
317 #define PRINTF_PARSE wprintf_parse
318 #include "printf-parse.c"
319 
320 /* Define functions declared in "vasnprintf.h".  */
321 #define vasnwprintf libintl_vasnwprintf
322 #include "vasnprintf.c"
323 #if 0 /* not needed */
324 #define asnwprintf libintl_asnwprintf
325 #include "asnprintf.c"
326 #endif
327 
328 # if HAVE_DECL__SNWPRINTF
329    /* Windows.  The function vswprintf() has a different signature than
330       on Unix; we use the function _vsnwprintf() instead.  */
331 #  define system_vswprintf _vsnwprintf
332 # else
333    /* Unix.  */
334 #  define system_vswprintf vswprintf
335 # endif
336 
337 DLL_EXPORTED
338 int
libintl_vfwprintf(FILE * stream,const wchar_t * format,va_list args)339 libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
340 {
341 # if !USE_REPLACEMENT_CODE_ALWAYS
342   if (wcschr (format, '$') == NULL)
343     return vfwprintf (stream, format, args);
344   else
345 # endif
346     {
347       size_t length;
348       wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
349       int retval = -1;
350       if (result != NULL)
351         {
352           size_t i;
353           for (i = 0; i < length; i++)
354             if (fputwc (result[i], stream) == WEOF)
355               break;
356           free (result);
357           if (i == length)
358             {
359               if (length > INT_MAX)
360                 errno = EOVERFLOW;
361               else
362                 retval = length;
363             }
364         }
365       return retval;
366     }
367 }
368 
369 DLL_EXPORTED
370 int
libintl_fwprintf(FILE * stream,const wchar_t * format,...)371 libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
372 {
373   va_list args;
374   int retval;
375 
376   va_start (args, format);
377   retval = libintl_vfwprintf (stream, format, args);
378   va_end (args);
379   return retval;
380 }
381 
382 DLL_EXPORTED
383 int
libintl_vwprintf(const wchar_t * format,va_list args)384 libintl_vwprintf (const wchar_t *format, va_list args)
385 {
386   return libintl_vfwprintf (stdout, format, args);
387 }
388 
389 DLL_EXPORTED
390 int
libintl_wprintf(const wchar_t * format,...)391 libintl_wprintf (const wchar_t *format, ...)
392 {
393   va_list args;
394   int retval;
395 
396   va_start (args, format);
397   retval = libintl_vwprintf (format, args);
398   va_end (args);
399   return retval;
400 }
401 
402 DLL_EXPORTED
403 int
libintl_vswprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,va_list args)404 libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
405 {
406 # if !USE_REPLACEMENT_CODE_ALWAYS
407   if (wcschr (format, '$') == NULL)
408     return system_vswprintf (resultbuf, length, format, args);
409   else
410 # endif
411     {
412       size_t maxlength = length;
413       wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
414       if (result == NULL)
415         return -1;
416       if (result != resultbuf)
417         {
418           if (maxlength > 0)
419             {
420               size_t pruned_length =
421                 (length < maxlength ? length : maxlength - 1);
422               memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
423               resultbuf[pruned_length] = 0;
424             }
425           free (result);
426           /* Unlike vsnprintf, which has to return the number of character that
427              would have been produced if the resultbuf had been sufficiently
428              large, the vswprintf function has to return a negative value if
429              the resultbuf was not sufficiently large.  */
430           if (length >= maxlength)
431             return -1;
432         }
433       if (length > INT_MAX)
434         {
435           errno = EOVERFLOW;
436           return -1;
437         }
438       else
439         return length;
440     }
441 }
442 
443 DLL_EXPORTED
444 int
libintl_swprintf(wchar_t * resultbuf,size_t length,const wchar_t * format,...)445 libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
446 {
447   va_list args;
448   int retval;
449 
450   va_start (args, format);
451   retval = libintl_vswprintf (resultbuf, length, format, args);
452   va_end (args);
453   return retval;
454 }
455 
456 #endif
457 
458 #endif
459