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