(root)/
gettext-0.22.4/
gettext-runtime/
intl/
printf.c
       1  /* Formatted output to strings, using POSIX/XSI format strings with positions.
       2     Copyright (C) 2003, 2006-2007, 2009-2011, 2018, 2020-2023 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
       6     it under the terms of the GNU Lesser General Public License as published by
       7     the Free Software Foundation; either version 2.1 of the License, or
       8     (at your option) 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
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #ifdef HAVE_CONFIG_H
      19  # include <config.h>
      20  #endif
      21  
      22  #ifdef __GNUC__
      23  # define alloca __builtin_alloca
      24  # define HAVE_ALLOCA 1
      25  #else
      26  # ifdef _MSC_VER
      27  #  include <malloc.h>
      28  #  define alloca _alloca
      29  # else
      30  #  if defined HAVE_ALLOCA_H || defined _LIBC
      31  #   include <alloca.h>
      32  #  else
      33  #   ifdef _AIX
      34   #pragma alloca
      35  #   else
      36  #    ifndef alloca
      37  char *alloca ();
      38  #    endif
      39  #   endif
      40  #  endif
      41  # endif
      42  #endif
      43  
      44  #include <stdio.h>
      45  
      46  #if !HAVE_POSIX_PRINTF
      47  
      48  #include <errno.h>
      49  #include <limits.h>
      50  #include <stdlib.h>
      51  #include <string.h>
      52  
      53  /* Specifications of the libintl_*printf functions.  */
      54  #include "libgnuintl.h"
      55  
      56  /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
      57  #ifndef EOVERFLOW
      58  # define EOVERFLOW E2BIG
      59  #endif
      60  
      61  /* When building a DLL, we must export some functions.  Note that because
      62     the functions are only defined for binary backward compatibility, we
      63     don't need to use __declspec(dllimport) in any case.  */
      64  #if HAVE_VISIBILITY && BUILDING_DLL
      65  # define DLL_EXPORTED __attribute__((__visibility__("default")))
      66  #elif defined _MSC_VER && BUILDING_DLL
      67  /* When building with MSVC, exporting a symbol means that the object file
      68     contains a "linker directive" of the form /EXPORT:symbol.  This can be
      69     inspected through the "objdump -s --section=.drectve FILE" or
      70     "dumpbin /directives FILE" commands.
      71     The symbols from this file should be exported if and only if the object
      72     file gets included in a DLL.  Libtool, on Windows platforms, defines
      73     the C macro DLL_EXPORT (together with PIC) when compiling for a DLL
      74     and does not define it when compiling an object file meant to be linked
      75     statically into some executable.  */
      76  # if defined DLL_EXPORT
      77  #  define DLL_EXPORTED __declspec(dllexport)
      78  # else
      79  #  define DLL_EXPORTED
      80  # endif
      81  #else
      82  # define DLL_EXPORTED
      83  #endif
      84  
      85  #define STATIC static
      86  
      87  /* You can enable this for debugging on Windows.  But not in a release!  */
      88  #if 0
      89  # define ENABLE_WCHAR_FALLBACK 1
      90  #endif
      91  
      92  /* This needs to be consistent with libgnuintl.in.h.  */
      93  #if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
      94  /* Don't break __attribute__((format(printf,M,N))).
      95     This redefinition is only possible because the libc in NetBSD, Cygwin,
      96     mingw does not have a function __printf__.  */
      97  # define libintl_printf __printf__
      98  #endif
      99  
     100  #if 0 /* not needed */
     101  
     102  /* Define auxiliary functions declared in "printf-args.h".  */
     103  #include "printf-args.c"
     104  
     105  /* Define auxiliary functions declared in "printf-parse.h".  */
     106  #include "printf-parse.c"
     107  
     108  /* Define functions declared in "vasnprintf.h".  */
     109  #define vasnprintf _libintl_vasnprintf
     110  #include "vasnprintf.c"
     111  #define asnprintf _libintl_asnprintf
     112  #include "asnprintf.c"
     113  
     114  #else
     115  
     116  /* Get the declaration of _libintl_vasnprintf.  */
     117  #include "vasnprintf.h"
     118  
     119  #endif
     120  
     121  /* Users don't expect libintl_fprintf to be less POSIX compliant
     122     than the fprintf implementation provided by gnulib or - on mingw -
     123     the one provided by mingw libs when __USE_MINGW_ANSI_STDIO is in
     124     effect.  */
     125  #define USE_REPLACEMENT_CODE_ALWAYS 1
     126  
     127  DLL_EXPORTED
     128  int
     129  libintl_vfprintf (FILE *stream, const char *format, va_list args)
     130  {
     131  #if !USE_REPLACEMENT_CODE_ALWAYS
     132    if (strchr (format, '$') == NULL)
     133      return vfprintf (stream, format, args);
     134    else
     135  #endif
     136      {
     137        size_t length;
     138        char *result = _libintl_vasnprintf (NULL, &length, format, args);
     139        int retval = -1;
     140        if (result != NULL)
     141          {
     142            size_t written = fwrite (result, 1, length, stream);
     143            free (result);
     144            if (written == length)
     145              {
     146                if (length > INT_MAX)
     147                  errno = EOVERFLOW;
     148                else
     149                  retval = length;
     150              }
     151          }
     152        return retval;
     153      }
     154  }
     155  
     156  DLL_EXPORTED
     157  int
     158  libintl_fprintf (FILE *stream, const char *format, ...)
     159  {
     160    va_list args;
     161    int retval;
     162  
     163    va_start (args, format);
     164    retval = libintl_vfprintf (stream, format, args);
     165    va_end (args);
     166    return retval;
     167  }
     168  
     169  DLL_EXPORTED
     170  int
     171  libintl_vprintf (const char *format, va_list args)
     172  {
     173    return libintl_vfprintf (stdout, format, args);
     174  }
     175  
     176  DLL_EXPORTED
     177  int
     178  libintl_printf (const char *format, ...)
     179  {
     180    va_list args;
     181    int retval;
     182  
     183    va_start (args, format);
     184    retval = libintl_vprintf (format, args);
     185    va_end (args);
     186    return retval;
     187  }
     188  
     189  DLL_EXPORTED
     190  int
     191  libintl_vsprintf (char *resultbuf, const char *format, va_list args)
     192  {
     193  #if !USE_REPLACEMENT_CODE_ALWAYS
     194    if (strchr (format, '$') == NULL)
     195      return vsprintf (resultbuf, format, args);
     196    else
     197  #endif
     198      {
     199        size_t length = (size_t) ~0 / (4 * sizeof (char));
     200        char *result = _libintl_vasnprintf (resultbuf, &length, format, args);
     201        if (result != resultbuf)
     202          {
     203            free (result);
     204            return -1;
     205          }
     206        if (length > INT_MAX)
     207          {
     208            errno = EOVERFLOW;
     209            return -1;
     210          }
     211        else
     212          return length;
     213      }
     214  }
     215  
     216  DLL_EXPORTED
     217  int
     218  libintl_sprintf (char *resultbuf, const char *format, ...)
     219  {
     220    va_list args;
     221    int retval;
     222  
     223    va_start (args, format);
     224    retval = libintl_vsprintf (resultbuf, format, args);
     225    va_end (args);
     226    return retval;
     227  }
     228  
     229  #if HAVE_SNPRINTF
     230  
     231  # if HAVE_DECL__SNPRINTF
     232     /* Windows.  The mingw function vsnprintf() has fewer bugs than the MSVCRT
     233        function _vsnprintf(), so prefer that.  */
     234  #  if defined __MINGW32__
     235  #   define system_vsnprintf vsnprintf
     236  #  else
     237  #   define system_vsnprintf _vsnprintf
     238  #  endif
     239  # else
     240     /* Unix.  */
     241  #  define system_vsnprintf vsnprintf
     242  # endif
     243  
     244  DLL_EXPORTED
     245  int
     246  libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
     247  {
     248  # if !USE_REPLACEMENT_CODE_ALWAYS
     249    if (strchr (format, '$') == NULL)
     250      return system_vsnprintf (resultbuf, length, format, args);
     251    else
     252  # endif
     253      {
     254        size_t maxlength = length;
     255        char *result = _libintl_vasnprintf (resultbuf, &length, format, args);
     256        if (result == NULL)
     257          return -1;
     258        if (result != resultbuf)
     259          {
     260            if (maxlength > 0)
     261              {
     262                size_t pruned_length =
     263                  (length < maxlength ? length : maxlength - 1);
     264                memcpy (resultbuf, result, pruned_length);
     265                resultbuf[pruned_length] = '\0';
     266              }
     267            free (result);
     268          }
     269        if (length > INT_MAX)
     270          {
     271            errno = EOVERFLOW;
     272            return -1;
     273          }
     274        else
     275          return length;
     276      }
     277  }
     278  
     279  DLL_EXPORTED
     280  int
     281  libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
     282  {
     283    va_list args;
     284    int retval;
     285  
     286    va_start (args, format);
     287    retval = libintl_vsnprintf (resultbuf, length, format, args);
     288    va_end (args);
     289    return retval;
     290  }
     291  
     292  #endif
     293  
     294  #if HAVE_ASPRINTF
     295  
     296  DLL_EXPORTED
     297  int
     298  libintl_vasprintf (char **resultp, const char *format, va_list args)
     299  {
     300    size_t length;
     301    char *result = _libintl_vasnprintf (NULL, &length, format, args);
     302    if (result == NULL)
     303      return -1;
     304    if (length > INT_MAX)
     305      {
     306        free (result);
     307        errno = EOVERFLOW;
     308        return -1;
     309      }
     310    *resultp = result;
     311    return length;
     312  }
     313  
     314  DLL_EXPORTED
     315  int
     316  libintl_asprintf (char **resultp, const char *format, ...)
     317  {
     318    va_list args;
     319    int retval;
     320  
     321    va_start (args, format);
     322    retval = libintl_vasprintf (resultp, format, args);
     323    va_end (args);
     324    return retval;
     325  }
     326  
     327  #endif
     328  
     329  #if HAVE_WPRINTF
     330  
     331  #include <wchar.h>
     332  
     333  #if 0 /* not needed */
     334  
     335  /* Define auxiliary functions declared in "printf-args.h".  */
     336  #include "printf-args.c"
     337  
     338  /* Define auxiliary functions declared in "wprintf-parse.h".  */
     339  #include "wprintf-parse.c"
     340  
     341  /* Define functions declared in "vasnwprintf.h".  */
     342  #define vasnwprintf _libintl_vasnwprintf
     343  #include "vasnwprintf.c"
     344  #define asnwprintf _libintl_asnwprintf
     345  #include "asnwprintf.c"
     346  
     347  #else
     348  
     349  /* Get the declaration of _libintl_vasnwprintf.  */
     350  #include "vasnwprintf.h"
     351  
     352  #endif
     353  
     354  # if HAVE_DECL__SNWPRINTF
     355     /* Windows.  The function vswprintf() has a different signature than
     356        on Unix; we use the function _vsnwprintf() instead.  */
     357  #  define system_vswprintf _vsnwprintf
     358  # else
     359     /* Unix.  */
     360  #  define system_vswprintf vswprintf
     361  # endif
     362  
     363  DLL_EXPORTED
     364  int
     365  libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
     366  {
     367  # if !USE_REPLACEMENT_CODE_ALWAYS
     368    if (wcschr (format, '$') == NULL)
     369      return vfwprintf (stream, format, args);
     370    else
     371  # endif
     372      {
     373        size_t length;
     374        wchar_t *result = _libintl_vasnwprintf (NULL, &length, format, args);
     375        int retval = -1;
     376        if (result != NULL)
     377          {
     378            size_t i;
     379            for (i = 0; i < length; i++)
     380              if (fputwc (result[i], stream) == WEOF)
     381                break;
     382            free (result);
     383            if (i == length)
     384              {
     385                if (length > INT_MAX)
     386                  errno = EOVERFLOW;
     387                else
     388                  retval = length;
     389              }
     390          }
     391        return retval;
     392      }
     393  }
     394  
     395  DLL_EXPORTED
     396  int
     397  libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
     398  {
     399    va_list args;
     400    int retval;
     401  
     402    va_start (args, format);
     403    retval = libintl_vfwprintf (stream, format, args);
     404    va_end (args);
     405    return retval;
     406  }
     407  
     408  DLL_EXPORTED
     409  int
     410  libintl_vwprintf (const wchar_t *format, va_list args)
     411  {
     412    return libintl_vfwprintf (stdout, format, args);
     413  }
     414  
     415  DLL_EXPORTED
     416  int
     417  libintl_wprintf (const wchar_t *format, ...)
     418  {
     419    va_list args;
     420    int retval;
     421  
     422    va_start (args, format);
     423    retval = libintl_vwprintf (format, args);
     424    va_end (args);
     425    return retval;
     426  }
     427  
     428  DLL_EXPORTED
     429  int
     430  libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
     431  {
     432  # if !USE_REPLACEMENT_CODE_ALWAYS
     433    if (wcschr (format, '$') == NULL)
     434      return system_vswprintf (resultbuf, length, format, args);
     435    else
     436  # endif
     437      {
     438        size_t maxlength = length;
     439        wchar_t *result = _libintl_vasnwprintf (resultbuf, &length, format, args);
     440        if (result == NULL)
     441          return -1;
     442        if (result != resultbuf)
     443          {
     444            if (maxlength > 0)
     445              {
     446                size_t pruned_length =
     447                  (length < maxlength ? length : maxlength - 1);
     448                memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
     449                resultbuf[pruned_length] = 0;
     450              }
     451            free (result);
     452            /* Unlike vsnprintf, which has to return the number of character that
     453               would have been produced if the resultbuf had been sufficiently
     454               large, the vswprintf function has to return a negative value if
     455               the resultbuf was not sufficiently large.  */
     456            if (length >= maxlength)
     457              return -1;
     458          }
     459        if (length > INT_MAX)
     460          {
     461            errno = EOVERFLOW;
     462            return -1;
     463          }
     464        else
     465          return length;
     466      }
     467  }
     468  
     469  DLL_EXPORTED
     470  int
     471  libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
     472  {
     473    va_list args;
     474    int retval;
     475  
     476    va_start (args, format);
     477    retval = libintl_vswprintf (resultbuf, length, format, args);
     478    va_end (args);
     479    return retval;
     480  }
     481  
     482  #endif
     483  
     484  #endif