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