mirror of https://github.com/aria2/aria2
				
				
				
			
		
			
				
	
	
		
			428 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			428 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
| /* Formatted output to strings, using POSIX/XSI format strings with positions.
 | |
|    Copyright (C) 2003, 2006-2007 Free Software Foundation, Inc.
 | |
|    Written by Bruno Haible <bruno@clisp.org>, 2003.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify it
 | |
|    under the terms of the GNU Library General Public License as published
 | |
|    by the Free Software Foundation; either version 2, or (at your option)
 | |
|    any later version.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Library General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Library General Public
 | |
|    License along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 | |
|    USA.  */
 | |
| 
 | |
| #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
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <limits.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
 | |
| #ifndef EOVERFLOW
 | |
| # define EOVERFLOW E2BIG
 | |
| #endif
 | |
| 
 | |
| /* 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.  */
 | |
| #if defined _MSC_VER && BUILDING_DLL
 | |
| # define DLL_EXPORTED __declspec(dllexport)
 | |
| #else
 | |
| # define DLL_EXPORTED
 | |
| #endif
 | |
| 
 | |
| #define STATIC static
 | |
| 
 | |
| /* This needs to be consistent with libgnuintl.h.in.  */
 | |
| #if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
 | |
| /* 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
 | |
| 
 | |
| /* 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)
 | |
| 	{
 | |
| 	  size_t written = fwrite (result, 1, length, stream);
 | |
| 	  free (result);
 | |
| 	  if (written == length)
 | |
| 	    {
 | |
| 	      if (length > INT_MAX)
 | |
| 		errno = EOVERFLOW;
 | |
| 	      else
 | |
| 		retval = length;
 | |
| 	    }
 | |
| 	}
 | |
|       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)
 | |
| 	{
 | |
| 	  free (result);
 | |
| 	  return -1;
 | |
| 	}
 | |
|       if (length > INT_MAX)
 | |
| 	{
 | |
| 	  errno = EOVERFLOW;
 | |
| 	  return -1;
 | |
| 	}
 | |
|       else
 | |
| 	return length;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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
 | |
|    /* Windows.  */
 | |
| #  define system_vsnprintf _vsnprintf
 | |
| # 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);
 | |
|       if (result != resultbuf)
 | |
| 	{
 | |
| 	  if (maxlength > 0)
 | |
| 	    {
 | |
| 	      size_t pruned_length =
 | |
| 		(length < maxlength ? length : maxlength - 1);
 | |
| 	      memcpy (resultbuf, result, pruned_length);
 | |
| 	      resultbuf[pruned_length] = '\0';
 | |
| 	    }
 | |
| 	  free (result);
 | |
| 	}
 | |
|       if (length > INT_MAX)
 | |
| 	{
 | |
| 	  errno = EOVERFLOW;
 | |
| 	  return -1;
 | |
| 	}
 | |
|       else
 | |
| 	return length;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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;
 | |
|   if (length > INT_MAX)
 | |
|     {
 | |
|       free (result);
 | |
|       errno = EOVERFLOW;
 | |
|       return -1;
 | |
|     }
 | |
|   *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
 | |
| 
 | |
| #include "wprintf-parse.h"
 | |
| /* Define auxiliary functions declared in "wprintf-parse.h".  */
 | |
| #define CHAR_T wchar_t
 | |
| #define DIRECTIVE wchar_t_directive
 | |
| #define DIRECTIVES wchar_t_directives
 | |
| #define PRINTF_PARSE wprintf_parse
 | |
| #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
 | |
|    /* Windows.  */
 | |
| #  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)
 | |
| 	{
 | |
| 	  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;
 | |
| 	    }
 | |
| 	}
 | |
|       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);
 | |
|       if (result != resultbuf)
 | |
| 	{
 | |
| 	  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;
 | |
| 	}
 | |
|       if (length > INT_MAX)
 | |
| 	{
 | |
| 	  errno = EOVERFLOW;
 | |
| 	  return -1;
 | |
| 	}
 | |
|       else
 | |
| 	return length;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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
 |