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 39char *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 93DLL_EXPORTED 94int 95libintl_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 120DLL_EXPORTED 121int 122libintl_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 133DLL_EXPORTED 134int 135libintl_vprintf (const char *format, va_list args) 136{ 137 return libintl_vfprintf (stdout, format, args); 138} 139 140DLL_EXPORTED 141int 142libintl_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 153DLL_EXPORTED 154int 155libintl_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 178DLL_EXPORTED 179int 180libintl_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 201DLL_EXPORTED 202int 203libintl_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 232DLL_EXPORTED 233int 234libintl_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 249DLL_EXPORTED 250int 251libintl_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 267DLL_EXPORTED 268int 269libintl_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 312DLL_EXPORTED 313int 314libintl_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 342DLL_EXPORTED 343int 344libintl_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 355DLL_EXPORTED 356int 357libintl_vwprintf (const wchar_t *format, va_list args) 358{ 359 return libintl_vfwprintf (stdout, format, args); 360} 361 362DLL_EXPORTED 363int 364libintl_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 375DLL_EXPORTED 376int 377libintl_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 412DLL_EXPORTED 413int 414libintl_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