2004-07-27 17:12:00 +02:00
|
|
|
/* Formatted output to strings, using POSIX/XSI format strings with positions.
|
2015-02-26 19:01:30 +01:00
|
|
|
Copyright (C) 2003, 2006-2007, 2009-2011 Free Software Foundation, Inc.
|
2004-07-27 17:12:00 +02:00
|
|
|
Written by Bruno Haible <bruno@clisp.org>, 2003.
|
|
|
|
|
2015-02-26 19:01:30 +01:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
2004-07-27 17:12:00 +02:00
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2015-02-26 19:01:30 +01:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License for more details.
|
2004-07-27 17:12:00 +02:00
|
|
|
|
2015-02-26 19:01:30 +01:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
2004-07-27 17:12:00 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
# define alloca __builtin_alloca
|
|
|
|
# define HAVE_ALLOCA 1
|
|
|
|
#else
|
|
|
|
# ifdef _MSC_VER
|
|
|
|
# include <malloc.h>
|
|
|
|
# define alloca _alloca
|
|
|
|
# else
|
|
|
|
# if defined HAVE_ALLOCA_H || defined _LIBC
|
|
|
|
# include <alloca.h>
|
|
|
|
# else
|
|
|
|
# ifdef _AIX
|
|
|
|
#pragma alloca
|
|
|
|
# else
|
|
|
|
# ifndef alloca
|
|
|
|
char *alloca ();
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#if !HAVE_POSIX_PRINTF
|
|
|
|
|
2007-10-23 12:48:09 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2004-07-27 17:12:00 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2007-10-23 12:48:09 +02:00
|
|
|
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
|
|
|
#ifndef EOVERFLOW
|
|
|
|
# define EOVERFLOW E2BIG
|
|
|
|
#endif
|
|
|
|
|
2004-07-27 17:12:00 +02:00
|
|
|
/* When building a DLL, we must export some functions. Note that because
|
|
|
|
the functions are only defined for binary backward compatibility, we
|
|
|
|
don't need to use __declspec(dllimport) in any case. */
|
2012-12-14 16:08:23 +01:00
|
|
|
#if HAVE_VISIBILITY && BUILDING_DLL
|
|
|
|
# define DLL_EXPORTED __attribute__((__visibility__("default")))
|
|
|
|
#elif defined _MSC_VER && BUILDING_DLL
|
2004-07-27 17:12:00 +02:00
|
|
|
# define DLL_EXPORTED __declspec(dllexport)
|
|
|
|
#else
|
|
|
|
# define DLL_EXPORTED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define STATIC static
|
|
|
|
|
2015-02-26 19:01:30 +01:00
|
|
|
/* This needs to be consistent with libgnuintl.in.h. */
|
2012-12-14 16:08:23 +01:00
|
|
|
#if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
|
2007-10-23 12:48:09 +02:00
|
|
|
/* Don't break __attribute__((format(printf,M,N))).
|
|
|
|
This redefinition is only possible because the libc in NetBSD, Cygwin,
|
|
|
|
mingw does not have a function __printf__. */
|
|
|
|
# define libintl_printf __printf__
|
|
|
|
#endif
|
|
|
|
|
2004-07-27 17:12:00 +02:00
|
|
|
/* Define auxiliary functions declared in "printf-args.h". */
|
|
|
|
#include "printf-args.c"
|
|
|
|
|
|
|
|
/* Define auxiliary functions declared in "printf-parse.h". */
|
|
|
|
#include "printf-parse.c"
|
|
|
|
|
|
|
|
/* Define functions declared in "vasnprintf.h". */
|
|
|
|
#define vasnprintf libintl_vasnprintf
|
|
|
|
#include "vasnprintf.c"
|
|
|
|
#if 0 /* not needed */
|
|
|
|
#define asnprintf libintl_asnprintf
|
|
|
|
#include "asnprintf.c"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vfprintf (FILE *stream, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
if (strchr (format, '$') == NULL)
|
|
|
|
return vfprintf (stream, format, args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t length;
|
|
|
|
char *result = libintl_vasnprintf (NULL, &length, format, args);
|
|
|
|
int retval = -1;
|
|
|
|
if (result != NULL)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
size_t written = fwrite (result, 1, length, stream);
|
|
|
|
free (result);
|
|
|
|
if (written == length)
|
|
|
|
{
|
|
|
|
if (length > INT_MAX)
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
else
|
|
|
|
retval = length;
|
|
|
|
}
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_fprintf (FILE *stream, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vfprintf (stream, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vprintf (const char *format, va_list args)
|
|
|
|
{
|
|
|
|
return libintl_vfprintf (stdout, format, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_printf (const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vprintf (format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vsprintf (char *resultbuf, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
if (strchr (format, '$') == NULL)
|
|
|
|
return vsprintf (resultbuf, format, args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t length = (size_t) ~0 / (4 * sizeof (char));
|
|
|
|
char *result = libintl_vasnprintf (resultbuf, &length, format, args);
|
|
|
|
if (result != resultbuf)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
free (result);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-23 12:48:09 +02:00
|
|
|
if (length > INT_MAX)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
else
|
2012-12-14 16:08:23 +01:00
|
|
|
return length;
|
2004-07-27 17:12:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_sprintf (char *resultbuf, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vsprintf (resultbuf, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_SNPRINTF
|
|
|
|
|
|
|
|
# if HAVE_DECL__SNPRINTF
|
2015-02-26 19:01:30 +01:00
|
|
|
/* Windows. The mingw function vsnprintf() has fewer bugs than the MSVCRT
|
|
|
|
function _vsnprintf(), so prefer that. */
|
|
|
|
# if defined __MINGW32__
|
|
|
|
# define system_vsnprintf vsnprintf
|
|
|
|
# else
|
|
|
|
# define system_vsnprintf _vsnprintf
|
|
|
|
# endif
|
2004-07-27 17:12:00 +02:00
|
|
|
# else
|
|
|
|
/* Unix. */
|
|
|
|
# define system_vsnprintf vsnprintf
|
|
|
|
# endif
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
if (strchr (format, '$') == NULL)
|
|
|
|
return system_vsnprintf (resultbuf, length, format, args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t maxlength = length;
|
|
|
|
char *result = libintl_vasnprintf (resultbuf, &length, format, args);
|
2015-02-26 19:01:30 +01:00
|
|
|
if (result == NULL)
|
|
|
|
return -1;
|
2004-07-27 17:12:00 +02:00
|
|
|
if (result != resultbuf)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
if (maxlength > 0)
|
|
|
|
{
|
|
|
|
size_t pruned_length =
|
|
|
|
(length < maxlength ? length : maxlength - 1);
|
|
|
|
memcpy (resultbuf, result, pruned_length);
|
|
|
|
resultbuf[pruned_length] = '\0';
|
|
|
|
}
|
|
|
|
free (result);
|
|
|
|
}
|
2007-10-23 12:48:09 +02:00
|
|
|
if (length > INT_MAX)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
else
|
2012-12-14 16:08:23 +01:00
|
|
|
return length;
|
2004-07-27 17:12:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vsnprintf (resultbuf, length, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAVE_ASPRINTF
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vasprintf (char **resultp, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
size_t length;
|
|
|
|
char *result = libintl_vasnprintf (NULL, &length, format, args);
|
|
|
|
if (result == NULL)
|
|
|
|
return -1;
|
2007-10-23 12:48:09 +02:00
|
|
|
if (length > INT_MAX)
|
|
|
|
{
|
|
|
|
free (result);
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
*resultp = result;
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_asprintf (char **resultp, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vasprintf (resultp, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAVE_FWPRINTF
|
|
|
|
|
|
|
|
#include <wchar.h>
|
|
|
|
|
|
|
|
#define WIDE_CHAR_VERSION 1
|
|
|
|
|
2012-12-14 16:08:23 +01:00
|
|
|
#include "wprintf-parse.h"
|
2004-07-27 17:12:00 +02:00
|
|
|
/* Define auxiliary functions declared in "wprintf-parse.h". */
|
2012-12-14 16:08:23 +01:00
|
|
|
#define CHAR_T wchar_t
|
|
|
|
#define DIRECTIVE wchar_t_directive
|
|
|
|
#define DIRECTIVES wchar_t_directives
|
|
|
|
#define PRINTF_PARSE wprintf_parse
|
2004-07-27 17:12:00 +02:00
|
|
|
#include "printf-parse.c"
|
|
|
|
|
|
|
|
/* Define functions declared in "vasnprintf.h". */
|
|
|
|
#define vasnwprintf libintl_vasnwprintf
|
|
|
|
#include "vasnprintf.c"
|
|
|
|
#if 0 /* not needed */
|
|
|
|
#define asnwprintf libintl_asnwprintf
|
|
|
|
#include "asnprintf.c"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
# if HAVE_DECL__SNWPRINTF
|
2015-02-26 19:01:30 +01:00
|
|
|
/* Windows. The function vswprintf() has a different signature than
|
|
|
|
on Unix; we use the function _vsnwprintf() instead. */
|
2004-07-27 17:12:00 +02:00
|
|
|
# define system_vswprintf _vsnwprintf
|
|
|
|
# else
|
|
|
|
/* Unix. */
|
|
|
|
# define system_vswprintf vswprintf
|
|
|
|
# endif
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
|
|
|
|
{
|
|
|
|
if (wcschr (format, '$') == NULL)
|
|
|
|
return vfwprintf (stream, format, args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t length;
|
|
|
|
wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
|
|
|
|
int retval = -1;
|
|
|
|
if (result != NULL)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
if (fputwc (result[i], stream) == WEOF)
|
|
|
|
break;
|
|
|
|
free (result);
|
|
|
|
if (i == length)
|
|
|
|
{
|
|
|
|
if (length > INT_MAX)
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
else
|
|
|
|
retval = length;
|
|
|
|
}
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vfwprintf (stream, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vwprintf (const wchar_t *format, va_list args)
|
|
|
|
{
|
|
|
|
return libintl_vfwprintf (stdout, format, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_wprintf (const wchar_t *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vwprintf (format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
|
|
|
|
{
|
|
|
|
if (wcschr (format, '$') == NULL)
|
|
|
|
return system_vswprintf (resultbuf, length, format, args);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t maxlength = length;
|
|
|
|
wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
|
2015-02-26 19:01:30 +01:00
|
|
|
if (result == NULL)
|
|
|
|
return -1;
|
2004-07-27 17:12:00 +02:00
|
|
|
if (result != resultbuf)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
if (maxlength > 0)
|
|
|
|
{
|
|
|
|
size_t pruned_length =
|
|
|
|
(length < maxlength ? length : maxlength - 1);
|
|
|
|
memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
|
|
|
|
resultbuf[pruned_length] = 0;
|
|
|
|
}
|
|
|
|
free (result);
|
|
|
|
/* Unlike vsnprintf, which has to return the number of character that
|
|
|
|
would have been produced if the resultbuf had been sufficiently
|
|
|
|
large, the vswprintf function has to return a negative value if
|
|
|
|
the resultbuf was not sufficiently large. */
|
|
|
|
if (length >= maxlength)
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-23 12:48:09 +02:00
|
|
|
if (length > INT_MAX)
|
2012-12-14 16:08:23 +01:00
|
|
|
{
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-27 17:12:00 +02:00
|
|
|
else
|
2012-12-14 16:08:23 +01:00
|
|
|
return length;
|
2004-07-27 17:12:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLL_EXPORTED
|
|
|
|
int
|
|
|
|
libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
retval = libintl_vswprintf (resultbuf, length, format, args);
|
|
|
|
va_end (args);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|