1 /* Formatted output to strings, using POSIX/XSI format strings with positions. 2 Copyright (C) 2003, 2006 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 __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 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 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 135 libintl_vprintf (const char *format, va_list args) 136 { 137 return libintl_vfprintf (stdout, format, args); 138 } 139 140 DLL_EXPORTED 141 int 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 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 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 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 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 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 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 /* Define auxiliary functions declared in "wprintf-parse.h". */ 289 #include "printf-parse.c" 290 291 /* Define functions declared in "vasnprintf.h". */ 292 #define vasnwprintf libintl_vasnwprintf 293 #include "vasnprintf.c" 294 #if 0 /* not needed */ 295 #define asnwprintf libintl_asnwprintf 296 #include "asnprintf.c" 297 #endif 298 299 # if HAVE_DECL__SNWPRINTF 300 /* Windows. */ 301 # define system_vswprintf _vsnwprintf 302 # else 303 /* Unix. */ 304 # define system_vswprintf vswprintf 305 # endif 306 307 DLL_EXPORTED 308 int 309 libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args) 310 { 311 if (wcschr (format, '$') == NULL) 312 return vfwprintf (stream, format, args); 313 else 314 { 315 size_t length; 316 wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args); 317 int retval = -1; 318 if (result != NULL) 319 { 320 size_t i; 321 for (i = 0; i < length; i++) 322 if (fputwc (result[i], stream) == WEOF) 323 break; 324 free (result); 325 if (i == length) 326 { 327 if (length > INT_MAX) 328 errno = EOVERFLOW; 329 else 330 retval = length; 331 } 332 } 333 return retval; 334 } 335 } 336 337 DLL_EXPORTED 338 int 339 libintl_fwprintf (FILE *stream, const wchar_t *format, ...) 340 { 341 va_list args; 342 int retval; 343 344 va_start (args, format); 345 retval = libintl_vfwprintf (stream, format, args); 346 va_end (args); 347 return retval; 348 } 349 350 DLL_EXPORTED 351 int 352 libintl_vwprintf (const wchar_t *format, va_list args) 353 { 354 return libintl_vfwprintf (stdout, format, args); 355 } 356 357 DLL_EXPORTED 358 int 359 libintl_wprintf (const wchar_t *format, ...) 360 { 361 va_list args; 362 int retval; 363 364 va_start (args, format); 365 retval = libintl_vwprintf (format, args); 366 va_end (args); 367 return retval; 368 } 369 370 DLL_EXPORTED 371 int 372 libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args) 373 { 374 if (wcschr (format, '$') == NULL) 375 return system_vswprintf (resultbuf, length, format, args); 376 else 377 { 378 size_t maxlength = length; 379 wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args); 380 if (result != resultbuf) 381 { 382 if (maxlength > 0) 383 { 384 size_t pruned_length = 385 (length < maxlength ? length : maxlength - 1); 386 memcpy (resultbuf, result, pruned_length * sizeof (wchar_t)); 387 resultbuf[pruned_length] = 0; 388 } 389 free (result); 390 /* Unlike vsnprintf, which has to return the number of character that 391 would have been produced if the resultbuf had been sufficiently 392 large, the vswprintf function has to return a negative value if 393 the resultbuf was not sufficiently large. */ 394 if (length >= maxlength) 395 return -1; 396 } 397 if (length > INT_MAX) 398 { 399 errno = EOVERFLOW; 400 return -1; 401 } 402 else 403 return length; 404 } 405 } 406 407 DLL_EXPORTED 408 int 409 libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...) 410 { 411 va_list args; 412 int retval; 413 414 va_start (args, format); 415 retval = libintl_vswprintf (resultbuf, length, format, args); 416 va_end (args); 417 return retval; 418 } 419 420 #endif 421 422 #endif 423