bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

prepare vasnprintf for Unicode strings


From: Bruno Haible
Subject: prepare vasnprintf for Unicode strings
Date: Mon, 11 Jun 2007 03:08:53 +0200
User-agent: KMail/1.5.4

The Unicode string I/O - essentially a *printf directive 'U' that accepts
Unicode strings as arguments, but also the ability to produce Unicode strings
rather than char* strings - requires some modifications to the vasnprintf
code.

The snprintfv code has not been migrating to gnulib (yet? dormant project?),
so I have no other choice than using gnulib's vasnprintf.c as code base.

Earlier I had the modifications in separate files, but it turns out that this
hampers maintainability. And the modified code is only ca. 20% of the
vasnprintf code. So, although it's an extension, it makes sense to put the
code into vasnprintf.c and its companion files.

2007-06-10  Bruno Haible  <address@hidden>

        Prepare vasnprintf code for use with Unicode strings.
        * lib/printf-args.h (PRINTF_FETCHARGS): New macro.
        (arg_type) [ENABLE_UNISTDIO]: Define TYPE_U8_STRING, TYPE_U16_STRING,
        TYPE_U32_STRING.
        (argument) [ENABLE_UNISTDIO]: Add a_u8_string, a_u16_string,
        a_u32_string variants.
        (PRINTF_FETCHARGS): Renamed from printf_fetchargs.
        * lib/printf-args.c: Don't include config.h and the specification
        header if PRINTF_FETCHARGS is already defined.
        (PRINTF_FETCHARGS): Renamed from printf_fetchargs.
        (PRINTF_FETCHARGS) [ENABLE_UNISTDIO]: Add code for TYPE_U8_STRING,
        TYPE_U16_STRING, TYPE_U32_STRING.
        * lib/printf-parse.h [ENABLE_UNISTDIO] (u8_directive, u8_directives,
        u16_directive, u16_directives, u32_directive, u32_directives): New
        types.
        (ulc_printf_parse, u8_printf_parse, u16_printf_parse, u32_printf_parse):
        New declarations.
        * lib/printf-parse.c: Don't include config.h and the specification
        header if PRINTF_PARSE is already defined. Eliminate the set of
        parameters for WIDE_CHAR_VERSION; the user of this file must provide
        them now. Include c-ctype.h.
        (PRINTF_PARSE) [ENABLE_UNISTDIO]: Add code implementing the 'U'
        directive and CHAR_T_ONLY_ASCII.
        * lib/vasnprintf.c: Don't include config.h and the specification header
        if VASNPRINTF is already defined.
        (DCHAR_IS_TCHAR, DCHAR_CPY): New macros.
        (VASNPRINTF): Use PRINTF_FETCHARGS instead of printf_fetchargs. Use
        DCHAR_CPY. Handle the case that DCHAR_T and FCHAR_T are not the same
        type. Handle the case that TCHAR_T and FCHAR_T are not of the same
        size. Handle the case that DCHAR_T and TCHAR_T are not the same type,
        add a conversion from TCHAR_T[] to DCHAR_T[], and rework the padding
        code accordingly.
        (VASNPRINTF) [ENABLE_UNISTDIO]: Implement the 'U' directive. Enable
        pad_ourselves also in this case, with the 'c' and 's' directives, and
        with a different notion of "width".
        * m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_WITH_EXTRAS): New macros.

*** lib/printf-args.h   6 Apr 2007 14:36:56 -0000       1.7
--- lib/printf-args.h   11 Jun 2007 00:46:59 -0000
***************
*** 18,23 ****
--- 18,33 ----
  #ifndef _PRINTF_ARGS_H
  #define _PRINTF_ARGS_H
  
+ /* This file can be parametrized with the following macros:
+      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.
+      PRINTF_FETCHARGS   Name of the function to be declared.
+      STATIC             Set to 'static' to declare the function static.  */
+ 
+ /* Default parameters.  */
+ #ifndef PRINTF_FETCHARGS
+ # define PRINTF_FETCHARGS printf_fetchargs
+ #endif
+ 
  /* Get size_t.  */
  #include <stddef.h>
  
***************
*** 69,74 ****
--- 79,90 ----
  #if HAVE_LONG_LONG_INT
  , TYPE_COUNT_LONGLONGINT_POINTER
  #endif
+ #if ENABLE_UNISTDIO
+   /* The unistdio extensions.  */
+ , TYPE_U8_STRING
+ , TYPE_U16_STRING
+ , TYPE_U32_STRING
+ #endif
  } arg_type;
  
  /* Polymorphic argument */
***************
*** 108,113 ****
--- 124,135 ----
  #if HAVE_LONG_LONG_INT
      long long int *           a_count_longlongint_pointer;
  #endif
+ #if ENABLE_UNISTDIO
+     /* The unistdio extensions.  */
+     const uint8_t *           a_u8_string;
+     const uint16_t *          a_u16_string;
+     const uint32_t *          a_u32_string;
+ #endif
    }
    a;
  }
***************
*** 127,132 ****
  #else
  extern
  #endif
! int printf_fetchargs (va_list args, arguments *a);
  
  #endif /* _PRINTF_ARGS_H */
--- 149,154 ----
  #else
  extern
  #endif
! int PRINTF_FETCHARGS (va_list args, arguments *a);
  
  #endif /* _PRINTF_ARGS_H */
*** lib/printf-args.c   6 Apr 2007 14:36:56 -0000       1.10
--- lib/printf-args.c   11 Jun 2007 00:46:59 -0000
***************
*** 15,30 ****
     with this program; if not, write to the Free Software Foundation,
     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  
! #include <config.h>
  
  /* Specification.  */
! #include "printf-args.h"
  
  #ifdef STATIC
  STATIC
  #endif
  int
! printf_fetchargs (va_list args, arguments *a)
  {
    size_t i;
    argument *ap;
--- 15,39 ----
     with this program; if not, write to the Free Software Foundation,
     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  
! /* This file can be parametrized with the following macros:
!      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.
!      PRINTF_FETCHARGS   Name of the function to be defined.
!      STATIC             Set to 'static' to declare the function static.  */
! 
! #ifndef PRINTF_FETCHARGS
! # include <config.h>
! #endif
  
  /* Specification.  */
! #ifndef PRINTF_FETCHARGS
! # include "printf-args.h"
! #endif
  
  #ifdef STATIC
  STATIC
  #endif
  int
! PRINTF_FETCHARGS (va_list args, arguments *a)
  {
    size_t i;
    argument *ap;
***************
*** 131,136 ****
--- 140,184 ----
        ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
        break;
  #endif
+ #if ENABLE_UNISTDIO
+       /* The unistdio extensions.  */
+       case TYPE_U8_STRING:
+       ap->a.a_u8_string = va_arg (args, const uint8_t *);
+       /* A null pointer is an invalid argument for "%U", but in practice
+          it occurs quite frequently in printf statements that produce
+          debug output.  Use a fallback in this case.  */
+       if (ap->a.a_u8_string == NULL)
+         {
+           static const uint8_t u8_null_string[] =
+             { '(', 'N', 'U', 'L', 'L', 0 };
+           ap->a.a_u8_string = u8_null_string;
+         }
+       break;
+       case TYPE_U16_STRING:
+       ap->a.a_u16_string = va_arg (args, const uint16_t *);
+       /* A null pointer is an invalid argument for "%lU", but in practice
+          it occurs quite frequently in printf statements that produce
+          debug output.  Use a fallback in this case.  */
+       if (ap->a.a_u16_string == NULL)
+         {
+           static const uint16_t u16_null_string[] =
+             { '(', 'N', 'U', 'L', 'L', 0 };
+           ap->a.a_u16_string = u16_null_string;
+         }
+       break;
+       case TYPE_U32_STRING:
+       ap->a.a_u32_string = va_arg (args, const uint32_t *);
+       /* A null pointer is an invalid argument for "%llU", but in practice
+          it occurs quite frequently in printf statements that produce
+          debug output.  Use a fallback in this case.  */
+       if (ap->a.a_u32_string == NULL)
+         {
+           static const uint32_t u32_null_string[] =
+             { '(', 'N', 'U', 'L', 'L', 0 };
+           ap->a.a_u32_string = u32_null_string;
+         }
+       break;
+ #endif
        default:
        /* Unknown type.  */
        return -1;
*** lib/printf-parse.h  14 May 2005 06:03:58 -0000      1.5
--- lib/printf-parse.h  11 Jun 2007 00:46:59 -0000
***************
*** 1,5 ****
  /* Parse printf format string.
!    Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,5 ----
  /* Parse printf format string.
!    Copyright (C) 1999, 2002-2003, 2005, 2007 Free Software Foundation, Inc.
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 18,23 ****
--- 18,27 ----
  #ifndef _PRINTF_PARSE_H
  #define _PRINTF_PARSE_H
  
+ /* This file can be parametrized with the following macros:
+      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.
+      STATIC             Set to 'static' to declare the function static.  */
+ 
  #include "printf-args.h"
  
  
***************
*** 32,37 ****
--- 36,44 ----
  /* arg_index value indicating that no argument is consumed.  */
  #define ARG_NONE      (~(size_t)0)
  
+ /* xxx_directive: A parsed directive.
+    xxx_directives: A parsed format string.  */
+ 
  /* A parsed directive.  */
  typedef struct
  {
***************
*** 59,74 ****
  }
  char_directives;
  
  
  /* Parses the format string.  Fills in the number N of directives, and fills
     in directives[0], ..., directives[N-1], and sets directives[N].dir_start
     to the end of the format string.  Also fills in the arg_type fields of the
     arguments and the needed count of arguments.  */
! #ifdef STATIC
! STATIC
  #else
  extern
! #endif
  int printf_parse (const char *format, char_directives *d, arguments *a);
  
  #endif /* _PRINTF_PARSE_H */
--- 66,179 ----
  }
  char_directives;
  
+ #if ENABLE_UNISTDIO
+ 
+ /* A parsed directive.  */
+ typedef struct
+ {
+   const uint8_t* dir_start;
+   const uint8_t* dir_end;
+   int flags;
+   const uint8_t* width_start;
+   const uint8_t* width_end;
+   size_t width_arg_index;
+   const uint8_t* precision_start;
+   const uint8_t* precision_end;
+   size_t precision_arg_index;
+   uint8_t conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+   size_t arg_index;
+ }
+ u8_directive;
+ 
+ /* A parsed format string.  */
+ typedef struct
+ {
+   size_t count;
+   u8_directive *dir;
+   size_t max_width_length;
+   size_t max_precision_length;
+ }
+ u8_directives;
+ 
+ /* A parsed directive.  */
+ typedef struct
+ {
+   const uint16_t* dir_start;
+   const uint16_t* dir_end;
+   int flags;
+   const uint16_t* width_start;
+   const uint16_t* width_end;
+   size_t width_arg_index;
+   const uint16_t* precision_start;
+   const uint16_t* precision_end;
+   size_t precision_arg_index;
+   uint16_t conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+   size_t arg_index;
+ }
+ u16_directive;
+ 
+ /* A parsed format string.  */
+ typedef struct
+ {
+   size_t count;
+   u16_directive *dir;
+   size_t max_width_length;
+   size_t max_precision_length;
+ }
+ u16_directives;
+ 
+ /* A parsed directive.  */
+ typedef struct
+ {
+   const uint32_t* dir_start;
+   const uint32_t* dir_end;
+   int flags;
+   const uint32_t* width_start;
+   const uint32_t* width_end;
+   size_t width_arg_index;
+   const uint32_t* precision_start;
+   const uint32_t* precision_end;
+   size_t precision_arg_index;
+   uint32_t conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+   size_t arg_index;
+ }
+ u32_directive;
+ 
+ /* A parsed format string.  */
+ typedef struct
+ {
+   size_t count;
+   u32_directive *dir;
+   size_t max_width_length;
+   size_t max_precision_length;
+ }
+ u32_directives;
+ 
+ #endif
+ 
  
  /* Parses the format string.  Fills in the number N of directives, and fills
     in directives[0], ..., directives[N-1], and sets directives[N].dir_start
     to the end of the format string.  Also fills in the arg_type fields of the
     arguments and the needed count of arguments.  */
! #if ENABLE_UNISTDIO
! extern int
!        ulc_printf_parse (const char *format, char_directives *d, arguments 
*a);
! extern int
!        u8_printf_parse (const uint8_t *format, u8_directives *d, arguments 
*a);
! extern int
!        u16_printf_parse (const uint16_t *format, u16_directives *d,
!                        arguments *a);
! extern int
!        u32_printf_parse (const uint32_t *format, u32_directives *d,
!                        arguments *a);
  #else
+ # ifdef STATIC
+ STATIC
+ # else
  extern
! # endif
  int printf_parse (const char *format, char_directives *d, arguments *a);
+ #endif
  
  #endif /* _PRINTF_PARSE_H */
*** lib/printf-parse.c  6 Apr 2007 14:36:56 -0000       1.12
--- lib/printf-parse.c  11 Jun 2007 00:46:59 -0000
***************
*** 15,29 ****
     with this program; if not, write to the Free Software Foundation,
     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  
! #include <config.h>
  
  /* Specification.  */
! #if WIDE_CHAR_VERSION
! # include "wprintf-parse.h"
! #else
  # include "printf-parse.h"
  #endif
  
  /* Get size_t, NULL.  */
  #include <stddef.h>
  
--- 15,50 ----
     with this program; if not, write to the Free Software Foundation,
     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  
! /* This file can be parametrized with the following macros:
!      CHAR_T             The element type of the format string.
!      CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
!                         in the format string are ASCII.
!      DIRECTIVE          Structure denoting a format directive.
!                         Depends on CHAR_T.
!      DIRECTIVES         Structure denoting the set of format directives of a
!                         format string.  Depends on CHAR_T.
!      PRINTF_PARSE       Function that parses a format string.
!                         Depends on CHAR_T.
!      STATIC             Set to 'static' to declare the function static.
!      ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
! 
! #ifndef PRINTF_PARSE
! # include <config.h>
! #endif
  
  /* Specification.  */
! #ifndef PRINTF_PARSE
  # include "printf-parse.h"
  #endif
  
+ /* Default parameters.  */
+ #ifndef PRINTF_PARSE
+ # define PRINTF_PARSE printf_parse
+ # define CHAR_T char
+ # define DIRECTIVE char_directive
+ # define DIRECTIVES char_directives
+ #endif
+ 
  /* Get size_t, NULL.  */
  #include <stddef.h>
  
***************
*** 45,60 ****
  /* Checked size_t computations.  */
  #include "xsize.h"
  
! #if WIDE_CHAR_VERSION
! # define PRINTF_PARSE wprintf_parse
! # define CHAR_T wchar_t
! # define DIRECTIVE wchar_t_directive
! # define DIRECTIVES wchar_t_directives
! #else
! # define PRINTF_PARSE printf_parse
! # define CHAR_T char
! # define DIRECTIVE char_directive
! # define DIRECTIVES char_directives
  #endif
  
  #ifdef STATIC
--- 66,74 ----
  /* Checked size_t computations.  */
  #include "xsize.h"
  
! #if CHAR_T_ONLY_ASCII
! /* c_isascii().  */
! # include "c-ctype.h"
  #endif
  
  #ifdef STATIC
***************
*** 119,125 ****
        if (c == '%')
        {
          size_t arg_index = ARG_NONE;
!         DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
  
          /* Initialize the next directive.  */
          dp->dir_start = cp - 1;
--- 133,139 ----
        if (c == '%')
        {
          size_t arg_index = ARG_NONE;
!         DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
  
          /* Initialize the next directive.  */
          dp->dir_start = cp - 1;
***************
*** 479,484 ****
--- 493,509 ----
                  else
                    type = TYPE_COUNT_INT_POINTER;
                  break;
+ #if ENABLE_UNISTDIO
+               /* The unistdio extensions.  */
+               case 'U':
+                 if (flags >= 16)
+                   type = TYPE_U32_STRING;
+                 else if (flags >= 8)
+                   type = TYPE_U16_STRING;
+                 else
+                   type = TYPE_U8_STRING;
+                 break;
+ #endif
                case '%':
                  type = TYPE_NONE;
                  break;
***************
*** 522,527 ****
--- 547,559 ----
              d->dir = memory;
            }
        }
+ #if CHAR_T_ONLY_ASCII
+       else if (!c_isascii (c))
+       {
+         /* Non-ASCII character.  Not supported.  */
+         goto error;
+       }
+ #endif
      }
    d->dir[d->count].dir_start = cp;
  
***************
*** 537,543 ****
    return -1;
  }
  
  #undef DIRECTIVES
  #undef DIRECTIVE
  #undef CHAR_T
- #undef PRINTF_PARSE
--- 569,576 ----
    return -1;
  }
  
+ #undef PRINTF_PARSE
  #undef DIRECTIVES
  #undef DIRECTIVE
+ #undef CHAR_T_ONLY_ASCII
  #undef CHAR_T
*** lib/vasnprintf.c    10 Jun 2007 12:02:55 -0000      1.57
--- lib/vasnprintf.c    11 Jun 2007 00:47:00 -0000
***************
*** 15,20 ****
--- 15,49 ----
     with this program; if not, write to the Free Software Foundation,
     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
  
+ /* This file can be parametrized with the following macros:
+      VASNPRINTF         The name of the function being defined.
+      FCHAR_T            The element type of the format string.
+      DCHAR_T            The element type of the destination (result) string.
+      FCHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters
+                         in the format string are ASCII. MUST be set if
+                         FCHAR_T and DCHAR_T are not the same type.
+      DIRECTIVE          Structure denoting a format directive.
+                         Depends on FCHAR_T.
+      DIRECTIVES         Structure denoting the set of format directives of a
+                         format string.  Depends on FCHAR_T.
+      PRINTF_PARSE       Function that parses a format string.
+                         Depends on FCHAR_T.
+      DCHAR_CPY          memcpy like function for DCHAR_T[] arrays.
+      DCHAR_SET          memset like function for DCHAR_T[] arrays.
+      DCHAR_MBSNLEN      mbsnlen like function for DCHAR_T[] arrays.
+      SNPRINTF           The system's snprintf (or similar) function.
+                         This may be either snprintf or swprintf.
+      TCHAR_T            The element type of the argument and result string
+                         of the said SNPRINTF function.  This may be either
+                         char or wchar_t.  The code exploits that
+                         sizeof (TCHAR_T) | sizeof (DCHAR_T) and
+                         alignof (TCHAR_T) <= alignof (DCHAR_T).
+      DCHAR_IS_TCHAR     Set to 1 if DCHAR_T and TCHAR_T are the same type.
+      DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[].
+      DCHAR_IS_UINT8_T   Set to 1 if DCHAR_T is uint8_t.
+      DCHAR_IS_UINT16_T  Set to 1 if DCHAR_T is uint16_t.
+      DCHAR_IS_UINT32_T  Set to 1 if DCHAR_T is uint32_t.  */
+ 
  /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
     This must come before <config.h> because <config.h> may include
     <features.h>, and once <features.h> has been included, it's too late.  */
***************
*** 22,37 ****
  # define _GNU_SOURCE    1
  #endif
  
! #include <config.h>
  #ifndef IN_LIBINTL
  # include <alloca.h>
  #endif
  
  /* Specification.  */
! #if WIDE_CHAR_VERSION
! # include "vasnwprintf.h"
! #else
! # include "vasnprintf.h"
  #endif
  
  #include <locale.h>   /* localeconv() */
--- 51,70 ----
  # define _GNU_SOURCE    1
  #endif
  
! #ifndef VASNPRINTF
! # include <config.h>
! #endif
  #ifndef IN_LIBINTL
  # include <alloca.h>
  #endif
  
  /* Specification.  */
! #ifndef VASNPRINTF
! # if WIDE_CHAR_VERSION
! #  include "vasnwprintf.h"
! # else
! #  include "vasnprintf.h"
! # endif
  #endif
  
  #include <locale.h>   /* localeconv() */
***************
*** 44,53 ****
  #if HAVE_NL_LANGINFO
  # include <langinfo.h>
  #endif
! #if WIDE_CHAR_VERSION
! # include "wprintf-parse.h"
! #else
! # include "printf-parse.h"
  #endif
  
  /* Checked size_t computations.  */
--- 77,88 ----
  #if HAVE_NL_LANGINFO
  # include <langinfo.h>
  #endif
! #ifndef VASNPRINTF
! # if WIDE_CHAR_VERSION
! #  include "wprintf-parse.h"
! # else
! #  include "printf-parse.h"
! # endif
  #endif
  
  /* Checked size_t computations.  */
***************
*** 107,135 ****
  # endif
  #endif
  
! /* Define some macros that parametrize the code:
!      VASNPRINTF         The name of the function being defined.
!      FCHAR_T            The element type of the format string.
!      DCHAR_T            The element type of the destination (result) string.
!      TCHAR_T            The element type of the temporary buffer that is
!                         filled with a simple format directive, executed by
!                         the system's sprintf/snprintf (or similar) function.
!      DIRECTIVE          Structure denoting a format directive.
!                         Depends on FCHAR_T.
!      DIRECTIVES         Structure denoting the set of format directives of a
!                         format string.  Depends on FCHAR_T.
!      PRINTF_PARSE       Function that parses a format string.
!                         Depends on FCHAR_T.
!      SNPRINTF           The system's snprintf (or similar) function.
!                         Depends on DCHAR_T.  */
  #if WIDE_CHAR_VERSION
! # define VASNPRINTF vasnwprintf
! # define FCHAR_T wchar_t
! # define DCHAR_T wchar_t
! # define TCHAR_T wchar_t
! # define DIRECTIVE wchar_t_directive
! # define DIRECTIVES wchar_t_directives
! # define PRINTF_PARSE wprintf_parse
  # define USE_SNPRINTF 1
  # if HAVE_DECL__SNWPRINTF
     /* On Windows, the function swprintf() has a different signature than
--- 142,173 ----
  # endif
  #endif
  
! /* Default parameters.  */
! #ifndef VASNPRINTF
! # if WIDE_CHAR_VERSION
! #  define VASNPRINTF vasnwprintf
! #  define FCHAR_T wchar_t
! #  define DCHAR_T wchar_t
! #  define TCHAR_T wchar_t
! #  define DCHAR_IS_TCHAR 1
! #  define DIRECTIVE wchar_t_directive
! #  define DIRECTIVES wchar_t_directives
! #  define PRINTF_PARSE wprintf_parse
! #  define DCHAR_CPY wmemcpy
! # else
! #  define VASNPRINTF vasnprintf
! #  define FCHAR_T char
! #  define DCHAR_T char
! #  define TCHAR_T char
! #  define DCHAR_IS_TCHAR 1
! #  define DIRECTIVE char_directive
! #  define DIRECTIVES char_directives
! #  define PRINTF_PARSE printf_parse
! #  define DCHAR_CPY memcpy
! # endif
! #endif
  #if WIDE_CHAR_VERSION
!   /* TCHAR_T is wchar_t.  */
  # define USE_SNPRINTF 1
  # if HAVE_DECL__SNWPRINTF
     /* On Windows, the function swprintf() has a different signature than
***************
*** 140,152 ****
  #  define SNPRINTF swprintf
  # endif
  #else
! # define VASNPRINTF vasnprintf
! # define FCHAR_T char
! # define DCHAR_T char
! # define TCHAR_T char
! # define DIRECTIVE char_directive
! # define DIRECTIVES char_directives
! # define PRINTF_PARSE printf_parse
  # /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
       But don't use it on BeOS, since BeOS snprintf produces no output if the
       size argument is >= 0x3000000.  */
--- 178,184 ----
  #  define SNPRINTF swprintf
  # endif
  #else
!   /* TCHAR_T is char.  */
  # /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
       But don't use it on BeOS, since BeOS snprintf produces no output if the
       size argument is >= 0x3000000.  */
***************
*** 1157,1163 ****
  #endif
  
  DCHAR_T *
! VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, const FCHAR_T *format, 
va_list args)
  {
    DIRECTIVES d;
    arguments a;
--- 1189,1196 ----
  #endif
  
  DCHAR_T *
! VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
!           const FCHAR_T *format, va_list args)
  {
    DIRECTIVES d;
    arguments a;
***************
*** 1173,1179 ****
    if (a.arg)                                                          \
      free (a.arg);
  
!   if (printf_fetchargs (args, &a) < 0)
      {
        CLEANUP ();
        errno = EINVAL;
--- 1206,1212 ----
    if (a.arg)                                                          \
      free (a.arg);
  
!   if (PRINTF_FETCHARGS (args, &a) < 0)
      {
        CLEANUP ();
        errno = EINVAL;
***************
*** 1250,1256 ****
        if (memory == NULL)                                                  \
          goto out_of_memory;                                                \
        if (result == resultbuf && length > 0)                               \
!         memcpy (memory, result, length * sizeof (DCHAR_T));                \
        result = memory;                                                     \
        }
  
--- 1283,1289 ----
        if (memory == NULL)                                                  \
          goto out_of_memory;                                                \
        if (result == resultbuf && length > 0)                               \
!         DCHAR_CPY (memory, result, length);                                \
        result = memory;                                                     \
        }
  
***************
*** 1262,1269 ****
            size_t augmented_length = xsum (length, n);
  
            ENSURE_ALLOCATION (augmented_length);
!           memcpy (result + length, cp, n * sizeof (DCHAR_T));
!           length = augmented_length;
          }
        if (i == d.count)
          break;
--- 1295,1314 ----
            size_t augmented_length = xsum (length, n);
  
            ENSURE_ALLOCATION (augmented_length);
!           /* This copies a piece of FCHAR_T[] into a DCHAR_T[].  Here we
!              need that the format string contains only ASCII characters
!              if FCHAR_T and DCHAR_T are not the same type.  */
!           if (sizeof (FCHAR_T) == sizeof (DCHAR_T))
!             {
!               DCHAR_CPY (result + length, (const DCHAR_T *) cp, n);
!               length = augmented_length;
!             }
!           else
!             {
!               do
!                 result[length++] = (unsigned char) *cp++;
!               while (--n > 0);
!             }
          }
        if (i == d.count)
          break;
***************
*** 1310,1315 ****
--- 1355,1824 ----
                    abort ();
                  }
              }
+ #if ENABLE_UNISTDIO
+           /* The unistdio extensions.  */
+           else if (dp->conversion == 'U')
+             {
+               arg_type type = a.arg[dp->arg_index].type;
+               int flags = dp->flags;
+               int has_width;
+               size_t width;
+               int has_precision;
+               size_t precision;
+ 
+               has_width = 0;
+               width = 0;
+               if (dp->width_start != dp->width_end)
+                 {
+                   if (dp->width_arg_index != ARG_NONE)
+                     {
+                       int arg;
+ 
+                       if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+                         abort ();
+                       arg = a.arg[dp->width_arg_index].a.a_int;
+                       if (arg < 0)
+                         {
+                           /* "A negative field width is taken as a '-' flag
+                               followed by a positive field width."  */
+                           flags |= FLAG_LEFT;
+                           width = (unsigned int) (-arg);
+                         }
+                       else
+                         width = arg;
+                     }
+                   else
+                     {
+                       const FCHAR_T *digitp = dp->width_start;
+ 
+                       do
+                         width = xsum (xtimes (width, 10), *digitp++ - '0');
+                       while (digitp != dp->width_end);
+                     }
+                   has_width = 1;
+                 }
+ 
+               has_precision = 0;
+               precision = 0;
+               if (dp->precision_start != dp->precision_end)
+                 {
+                   if (dp->precision_arg_index != ARG_NONE)
+                     {
+                       int arg;
+ 
+                       if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+                         abort ();
+                       arg = a.arg[dp->precision_arg_index].a.a_int;
+                       /* "A negative precision is taken as if the precision
+                           were omitted."  */
+                       if (arg >= 0)
+                         {
+                           precision = arg;
+                           has_precision = 1;
+                         }
+                     }
+                   else
+                     {
+                       const FCHAR_T *digitp = dp->precision_start + 1;
+ 
+                       precision = 0;
+                       while (digitp != dp->precision_end)
+                         precision = xsum (xtimes (precision, 10), *digitp++ - 
'0');
+                       has_precision = 1;
+                     }
+                 }
+ 
+               switch (type)
+                 {
+                 case TYPE_U8_STRING:
+                   {
+                     const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string;
+                     const uint8_t *arg_end;
+                     size_t characters;
+ 
+                     if (has_precision)
+                       {
+                         /* Use only PRECISION characters, from the left.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (; precision > 0; precision--)
+                           {
+                             int count = u8_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else if (has_width)
+                       {
+                         /* Use the entire string, and count the number of
+                            characters.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (;;)
+                           {
+                             int count = u8_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else
+                       {
+                         /* Use the entire string.  */
+                         arg_end = arg + u8_strlen (arg);
+                         /* The number of characters doesn't matter.  */
+                         characters = 0;
+                       }
+ 
+                     if (has_width && width > characters
+                         && !(dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+ 
+ # if DCHAR_IS_UINT8_T
+                     {
+                       size_t n = arg_end - arg;
+                       ENSURE_ALLOCATION (xsum (length, n));
+                       DCHAR_CPY (result + length, arg, n);
+                       length += n;
+                     }
+ # else
+                     { /* Convert.  */
+                       DCHAR_T *converted = result + length;
+                       size_t converted_len = allocated - length;
+ #  if DCHAR_IS_TCHAR
+                       /* Convert from UTF-8 to locale encoding.  */
+                       if (u8_conv_to_encoding (locale_charset (),
+                                                iconveh_question_mark,
+                                                arg, arg_end - arg, NULL,
+                                                &converted, &converted_len)
+                           < 0)
+ #  else
+                       /* Convert from UTF-8 to UTF-16/UTF-32.  */
+                       converted =
+                         U8_TO_DCHAR (arg, arg_end - arg,
+                                      converted, &converted_len);
+                       if (converted == NULL)
+ #  endif
+                         {
+                           int saved_errno = errno;
+                           if (!(result == resultbuf || result == NULL))
+                             free (result);
+                           if (buf_malloced != NULL)
+                             free (buf_malloced);
+                           CLEANUP ();
+                           errno = saved_errno;
+                           return NULL;
+                         }
+                       if (converted != result + length)
+                         {
+                           ENSURE_ALLOCATION (xsum (length, converted_len));
+                           DCHAR_CPY (result + length, converted, 
converted_len);
+                           free (converted);
+                         }
+                       length += converted_len;
+                     }
+ # endif
+ 
+                     if (has_width && width > characters
+                         && (dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+                   }
+                   break;
+ 
+                 case TYPE_U16_STRING:
+                   {
+                     const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string;
+                     const uint16_t *arg_end;
+                     size_t characters;
+ 
+                     if (has_precision)
+                       {
+                         /* Use only PRECISION characters, from the left.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (; precision > 0; precision--)
+                           {
+                             int count = u16_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else if (has_width)
+                       {
+                         /* Use the entire string, and count the number of
+                            characters.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (;;)
+                           {
+                             int count = u16_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else
+                       {
+                         /* Use the entire string.  */
+                         arg_end = arg + u16_strlen (arg);
+                         /* The number of characters doesn't matter.  */
+                         characters = 0;
+                       }
+ 
+                     if (has_width && width > characters
+                         && !(dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+ 
+ # if DCHAR_IS_UINT16_T
+                     {
+                       size_t n = arg_end - arg;
+                       ENSURE_ALLOCATION (xsum (length, n));
+                       DCHAR_CPY (result + length, arg, n);
+                       length += n;
+                     }
+ # else
+                     { /* Convert.  */
+                       DCHAR_T *converted = result + length;
+                       size_t converted_len = allocated - length;
+ #  if DCHAR_IS_TCHAR
+                       /* Convert from UTF-16 to locale encoding.  */
+                       if (u16_conv_to_encoding (locale_charset (),
+                                                 iconveh_question_mark,
+                                                 arg, arg_end - arg, NULL,
+                                                 &converted, &converted_len)
+                           < 0)
+ #  else
+                       /* Convert from UTF-16 to UTF-8/UTF-32.  */
+                       converted =
+                         U16_TO_DCHAR (arg, arg_end - arg,
+                                       converted, &converted_len);
+                       if (converted == NULL)
+ #  endif
+                         {
+                           int saved_errno = errno;
+                           if (!(result == resultbuf || result == NULL))
+                             free (result);
+                           if (buf_malloced != NULL)
+                             free (buf_malloced);
+                           CLEANUP ();
+                           errno = saved_errno;
+                           return NULL;
+                         }
+                       if (converted != result + length)
+                         {
+                           ENSURE_ALLOCATION (xsum (length, converted_len));
+                           DCHAR_CPY (result + length, converted, 
converted_len);
+                           free (converted);
+                         }
+                       length += converted_len;
+                     }
+ # endif
+ 
+                     if (has_width && width > characters
+                         && (dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+                   }
+                   break;
+ 
+                 case TYPE_U32_STRING:
+                   {
+                     const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string;
+                     const uint32_t *arg_end;
+                     size_t characters;
+ 
+                     if (has_precision)
+                       {
+                         /* Use only PRECISION characters, from the left.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (; precision > 0; precision--)
+                           {
+                             int count = u32_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else if (has_width)
+                       {
+                         /* Use the entire string, and count the number of
+                            characters.  */
+                         arg_end = arg;
+                         characters = 0;
+                         for (;;)
+                           {
+                             int count = u32_strmblen (arg_end);
+                             if (count == 0)
+                               break;
+                             if (count < 0)
+                               {
+                                 if (!(result == resultbuf || result == NULL))
+                                   free (result);
+                                 if (buf_malloced != NULL)
+                                   free (buf_malloced);
+                                 CLEANUP ();
+                                 errno = EILSEQ;
+                                 return NULL;
+                               }
+                             arg_end += count;
+                             characters++;
+                           }
+                       }
+                     else
+                       {
+                         /* Use the entire string.  */
+                         arg_end = arg + u32_strlen (arg);
+                         /* The number of characters doesn't matter.  */
+                         characters = 0;
+                       }
+ 
+                     if (has_width && width > characters
+                         && !(dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+ 
+ # if DCHAR_IS_UINT32_T
+                     {
+                       size_t n = arg_end - arg;
+                       ENSURE_ALLOCATION (xsum (length, n));
+                       DCHAR_CPY (result + length, arg, n);
+                       length += n;
+                     }
+ # else
+                     { /* Convert.  */
+                       DCHAR_T *converted = result + length;
+                       size_t converted_len = allocated - length;
+ #  if DCHAR_IS_TCHAR
+                       /* Convert from UTF-32 to locale encoding.  */
+                       if (u32_conv_to_encoding (locale_charset (),
+                                                 iconveh_question_mark,
+                                                 arg, arg_end - arg, NULL,
+                                                 &converted, &converted_len)
+                           < 0)
+ #  else
+                       /* Convert from UTF-32 to UTF-8/UTF-16.  */
+                       converted =
+                         U32_TO_DCHAR (arg, arg_end - arg,
+                                       converted, &converted_len);
+                       if (converted == NULL)
+ #  endif
+                         {
+                           int saved_errno = errno;
+                           if (!(result == resultbuf || result == NULL))
+                             free (result);
+                           if (buf_malloced != NULL)
+                             free (buf_malloced);
+                           CLEANUP ();
+                           errno = saved_errno;
+                           return NULL;
+                         }
+                       if (converted != result + length)
+                         {
+                           ENSURE_ALLOCATION (xsum (length, converted_len));
+                           DCHAR_CPY (result + length, converted, 
converted_len);
+                           free (converted);
+                         }
+                       length += converted_len;
+                     }
+ # endif
+ 
+                     if (has_width && width > characters
+                         && (dp->flags & FLAG_LEFT))
+                       {
+                         size_t n = width - characters;
+                         ENSURE_ALLOCATION (xsum (length, n));
+                         DCHAR_SET (result + length, ' ', n);
+                         length += n;
+                       }
+                   }
+                   break;
+ 
+                 default:
+                   abort ();
+                 }
+             }
+ #endif
  #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
            else if (dp->conversion == 'a' || dp->conversion == 'A')
              {
***************
*** 1554,1564 ****
                                  { '%', '+', 'd', '\0' };
                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
                              }
- # else
-                             sprintf (p, "%+d", exponent);
- # endif
                              while (*p != '\0')
                                p++;
                          }
  
                        END_LONG_DOUBLE_ROUNDING ();
--- 2063,2086 ----
                                  { '%', '+', 'd', '\0' };
                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
                              }
                              while (*p != '\0')
                                p++;
+ # else
+                             if (sizeof (DCHAR_T) == 1)
+                               {
+                                 sprintf ((char *) p, "%+d", exponent);
+                                 while (*p != '\0')
+                                   p++;
+                               }
+                             else
+                               {
+                                 char expbuf[6 + 1];
+                                 const char *ep;
+                                 sprintf (expbuf, "%+d", exponent);
+                                 for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                   p++;
+                               }
+ # endif
                          }
  
                        END_LONG_DOUBLE_ROUNDING ();
***************
*** 1688,1698 ****
                                  { '%', '+', 'd', '\0' };
                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
                              }
- # else
-                             sprintf (p, "%+d", exponent);
- # endif
                              while (*p != '\0')
                                p++;
                          }
                      }
                  }
--- 2210,2233 ----
                                  { '%', '+', 'd', '\0' };
                                SNPRINTF (p, 6 + 1, decimal_format, exponent);
                              }
                              while (*p != '\0')
                                p++;
+ # else
+                             if (sizeof (DCHAR_T) == 1)
+                               {
+                                 sprintf ((char *) p, "%+d", exponent);
+                                 while (*p != '\0')
+                                   p++;
+                               }
+                             else
+                               {
+                                 char expbuf[6 + 1];
+                                 const char *ep;
+                                 sprintf (expbuf, "%+d", exponent);
+                                 for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                   p++;
+                               }
+ # endif
                          }
                      }
                  }
***************
*** 2084,2094 ****
                                    { '%', '+', '.', '2', 'd', '\0' };
                                  SNPRINTF (p, 6 + 1, decimal_format, exponent);
                                }
- #   else
-                               sprintf (p, "%+.2d", exponent);
- #   endif
                                while (*p != '\0')
                                  p++;
                              }
                            else if (dp->conversion == 'g' || dp->conversion == 
'G')
                              {
--- 2619,2642 ----
                                    { '%', '+', '.', '2', 'd', '\0' };
                                  SNPRINTF (p, 6 + 1, decimal_format, exponent);
                                }
                                while (*p != '\0')
                                  p++;
+ #   else
+                               if (sizeof (DCHAR_T) == 1)
+                                 {
+                                   sprintf ((char *) p, "%+.2d", exponent);
+                                   while (*p != '\0')
+                                     p++;
+                                 }
+                               else
+                                 {
+                                   char expbuf[6 + 1];
+                                   const char *ep;
+                                   sprintf (expbuf, "%+.2d", exponent);
+                                   for (ep = expbuf; (*p = *ep) != '\0'; ep++)
+                                     p++;
+                                 }
+ #   endif
                              }
                            else if (dp->conversion == 'g' || dp->conversion == 
'G')
                              {
***************
*** 2228,2238 ****
                                            { '%', '+', '.', '2', 'd', '\0' };
                                          SNPRINTF (p, 6 + 1, decimal_format, 
exponent);
                                        }
- #   else
-                                       sprintf (p, "%+.2d", exponent);
- #   endif
                                        while (*p != '\0')
                                          p++;
                                      }
  
                                    free (digits);
--- 2776,2799 ----
                                            { '%', '+', '.', '2', 'd', '\0' };
                                          SNPRINTF (p, 6 + 1, decimal_format, 
exponent);
                                        }
                                        while (*p != '\0')
                                          p++;
+ #   else
+                                       if (sizeof (DCHAR_T) == 1)
+                                         {
+                                           sprintf ((char *) p, "%+.2d", 
exponent);
+                                           while (*p != '\0')
+                                             p++;
+                                         }
+                                       else
+                                         {
+                                           char expbuf[6 + 1];
+                                           const char *ep;
+                                           sprintf (expbuf, "%+.2d", exponent);
+                                           for (ep = expbuf; (*p = *ep) != 
'\0'; ep++)
+                                             p++;
+                                         }
+ #   endif
                                      }
  
                                    free (digits);
***************
*** 2417,2427 ****
              {
                arg_type type = a.arg[dp->arg_index].type;
                int flags = dp->flags;
! #if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO
                int has_width;
                size_t width;
  #endif
! #if NEED_PRINTF_FLAG_ZERO
                int pad_ourselves;
  #else
  #             define pad_ourselves 0
--- 2978,2988 ----
              {
                arg_type type = a.arg[dp->arg_index].type;
                int flags = dp->flags;
! #if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_ZERO
                int has_width;
                size_t width;
  #endif
! #if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
                int pad_ourselves;
  #else
  #             define pad_ourselves 0
***************
*** 2435,2441 ****
                TCHAR_T *tmp;
  #endif
  
! #if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO
                has_width = 0;
                width = 0;
                if (dp->width_start != dp->width_end)
--- 2996,3002 ----
                TCHAR_T *tmp;
  #endif
  
! #if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_ZERO
                has_width = 0;
                width = 0;
                if (dp->width_start != dp->width_end)
***************
*** 2669,2676 ****
--- 3230,3247 ----
                      abort ();
                    }
  
+ # if ENABLE_UNISTDIO
+                 /* Padding considers the number of characters, therefore the
+                    number of elements after padding may be
+                      > max (tmp_length, width)
+                    but is certainly
+                      <= tmp_length + width.  */
+                 tmp_length = xsum (tmp_length, width);
+ # else
+                 /* Padding considers the number of elements, says POSIX.  */
                  if (tmp_length < width)
                    tmp_length = width;
+ # endif
  
                  tmp_length = xsum (tmp_length, 1); /* account for trailing 
NUL */
                }
***************
*** 2692,2702 ****
  #endif
  
                /* Decide whether to perform the padding ourselves.  */
! #if NEED_PRINTF_FLAG_ZERO
                switch (dp->conversion)
                  {
                  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
                  case 'a': case 'A':
                    pad_ourselves = 1;
                    break;
                  default:
--- 3263,3282 ----
  #endif
  
                /* Decide whether to perform the padding ourselves.  */
! #if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
                switch (dp->conversion)
                  {
+ # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
+                 /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
+                    to perform the padding after this conversion.  Functions
+                    with unistdio extensions perform the padding based on
+                    character count rather than element count.  */
+                 case 'c': case 's':
+ # endif
+ # if NEED_PRINTF_FLAG_ZERO
                  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
                  case 'a': case 'A':
+ # endif
                    pad_ourselves = 1;
                    break;
                  default:
***************
*** 2732,2746 ****
                    if (dp->width_start != dp->width_end)
                      {
                        size_t n = dp->width_end - dp->width_start;
!                       memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T));
!                       fbp += n;
                      }
                  }
                if (dp->precision_start != dp->precision_end)
                  {
                    size_t n = dp->precision_end - dp->precision_start;
!                   memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T));
!                   fbp += n;
                  }
  
                switch (type)
--- 3312,3350 ----
                    if (dp->width_start != dp->width_end)
                      {
                        size_t n = dp->width_end - dp->width_start;
!                       /* The width specification is known to consist only
!                          of standard ASCII characters.  */
!                       if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
!                         {
!                           memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T));
!                           fbp += n;
!                         }
!                       else
!                         {
!                           const FCHAR_T *mp = dp->width_start;
!                           do
!                             *fbp++ = (unsigned char) *mp++;
!                           while (--n > 0);
!                         }
                      }
                  }
                if (dp->precision_start != dp->precision_end)
                  {
                    size_t n = dp->precision_end - dp->precision_start;
!                   /* The precision specification is known to consist only
!                      of standard ASCII characters.  */
!                   if (sizeof (FCHAR_T) == sizeof (TCHAR_T))
!                     {
!                       memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T));
!                       fbp += n;
!                     }
!                   else
!                     {
!                       const FCHAR_T *mp = dp->precision_start;
!                       do
!                         *fbp++ = (unsigned char) *mp++;
!                       while (--n > 0);
!                     }
                  }
  
                switch (type)
***************
*** 2804,2838 ****
                  }
  
  #if USE_SNPRINTF
                /* Prepare checking whether snprintf returns the count
                   via %n.  */
                ENSURE_ALLOCATION (xsum (length, 1));
!               result[length] = '\0';
  #endif
  
                for (;;)
                  {
                    int count = -1;
-                   int retcount = 0;
  
  #if USE_SNPRINTF
                    size_t maxlen = allocated - length;
!                   /* SNPRINTF can fail if maxlen > INT_MAX.  */
!                   if (maxlen > INT_MAX)
                      goto overflow;
  # define SNPRINTF_BUF(arg) \
                    switch (prefix_count)                                   \
                      {                                                     \
                      case 0:                                               \
!                       retcount = SNPRINTF (result + length, maxlen, buf,  \
                                             arg, &count);                  \
                        break;                                              \
                      case 1:                                               \
!                       retcount = SNPRINTF (result + length, maxlen, buf,  \
                                             prefixes[0], arg, &count);     \
                        break;                                              \
                      case 2:                                               \
!                       retcount = SNPRINTF (result + length, maxlen, buf,  \
                                             prefixes[0], prefixes[1], arg, \
                                             &count);                       \
                        break;                                              \
--- 3408,3453 ----
                  }
  
  #if USE_SNPRINTF
+               /* The SNPRINTF result is appended after result[0..length].
+                  The latter is an array of DCHAR_T; SNPRINTF appends an
+                  array of TCHAR_T to it.  This is possible because
+                  sizeof (TCHAR_T) divides sizeof (DCHAR_T) and
+                  alignof (TCHAR_T) <= alignof (DCHAR_T).  */
+ # define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T))
                /* Prepare checking whether snprintf returns the count
                   via %n.  */
                ENSURE_ALLOCATION (xsum (length, 1));
!               *(TCHAR_T *) (result + length) = '\0';
  #endif
  
                for (;;)
                  {
                    int count = -1;
  
  #if USE_SNPRINTF
+                   int retcount = 0;
                    size_t maxlen = allocated - length;
!                   /* SNPRINTF can fail if its second argument is
!                      > INT_MAX.  */
!                   if (maxlen > INT_MAX / TCHARS_PER_DCHAR)
                      goto overflow;
+                   maxlen = maxlen * TCHARS_PER_DCHAR;
  # define SNPRINTF_BUF(arg) \
                    switch (prefix_count)                                   \
                      {                                                     \
                      case 0:                                               \
!                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
!                                            maxlen, buf,                   \
                                             arg, &count);                  \
                        break;                                              \
                      case 1:                                               \
!                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
!                                            maxlen, buf,                   \
                                             prefixes[0], arg, &count);     \
                        break;                                              \
                      case 2:                                               \
!                       retcount = SNPRINTF ((TCHAR_T *) (result + length), \
!                                            maxlen, buf,                   \
                                             prefixes[0], prefixes[1], arg, \
                                             &count);                       \
                        break;                                              \
***************
*** 2981,2987 ****
                      {
                        /* Verify that snprintf() has NUL-terminated its
                           result.  */
!                       if (count < maxlen && result[length + count] != '\0')
                          abort ();
                        /* Portability hack.  */
                        if (retcount > count)
--- 3596,3603 ----
                      {
                        /* Verify that snprintf() has NUL-terminated its
                           result.  */
!                       if (count < maxlen
!                           && ((TCHAR_T *) (result + length)) [count] != '\0')
                          abort ();
                        /* Portability hack.  */
                        if (retcount > count)
***************
*** 3032,3056 ****
                      }
  
  #if USE_SNPRINTF
!                   /* Make room for the result.  */
                    if (count >= maxlen)
                      {
!                       /* Need at least count bytes.  But allocate
!                          proportionally, to avoid looping eternally if
!                          snprintf() reports a too small count.  */
                        size_t n =
!                         xmax (xsum (length, count), xtimes (allocated, 2));
  
                        ENSURE_ALLOCATION (n);
                        continue;
                      }
  #endif
  
! #if !USE_SNPRINTF
                    /* Make room for the result.  */
                    if (count > allocated - length)
                      {
!                       /* Need at least count bytes.  But allocate
                           proportionally.  */
                        size_t n =
                          xmax (xsum (length, count), xtimes (allocated, 2));
--- 3648,3767 ----
                      }
  
  #if USE_SNPRINTF
!                   /* Handle overflow of the allocated buffer.  */
                    if (count >= maxlen)
                      {
!                       /* Need at least count * sizeof (TCHAR_T) bytes.  But
!                          allocate proportionally, to avoid looping eternally
!                          if snprintf() reports a too small count.  */
                        size_t n =
!                         xmax (xsum (length,
!                                     (count + TCHARS_PER_DCHAR - 1)
!                                     / TCHARS_PER_DCHAR),
!                               xtimes (allocated, 2));
  
                        ENSURE_ALLOCATION (n);
                        continue;
                      }
  #endif
  
! #if !DCHAR_IS_TCHAR
! # if !USE_SNPRINTF
!                   if (count >= tmp_length)
!                     /* tmp_length was incorrectly calculated - fix the
!                        code above!  */
!                     abort ();
! # endif
! 
!                   /* Convert from TCHAR_T[] to DCHAR_T[].  */
!                   if (dp->conversion == 'c' || dp->conversion == 's')
!                     {
!                       /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
!                          TYPE_WIDE_STRING.
!                          The result string is not certainly ASCII.  */
!                       const TCHAR_T *tmpsrc;
!                       DCHAR_T *tmpdst;
!                       size_t tmpdst_len;
!                       /* This code assumes that TCHAR_T is 'char'.  */
!                       typedef int TCHAR_T_verify
!                                   [2 * (sizeof (TCHAR_T) == 1) - 1];
! # if USE_SNPRINTF
!                       tmpsrc = (TCHAR_T *) (result + length);
! # else
!                       tmpsrc = tmp;
! # endif
!                       tmpdst = NULL;
!                       tmpdst_len = 0;
!                       if (DCHAR_CONV_FROM_ENCODING (locale_charset (),
!                                                     iconveh_question_mark,
!                                                     tmpsrc, count,
!                                                     NULL,
!                                                     &tmpdst, &tmpdst_len)
!                           < 0)
!                         {
!                           int saved_errno = errno;
!                           if (!(result == resultbuf || result == NULL))
!                             free (result);
!                           if (buf_malloced != NULL)
!                             free (buf_malloced);
!                           CLEANUP ();
!                           errno = saved_errno;
!                           return NULL;
!                         }
!                       ENSURE_ALLOCATION (xsum (length, tmpdst_len));
!                       DCHAR_CPY (result + length, tmpdst, tmpdst_len);
!                       free (tmpdst);
!                       count = tmpdst_len;
!                     }
!                   else
!                     {
!                       /* The result string is ASCII.
!                          Simple 1:1 conversion.  */
! # if USE_SNPRINTF
!                       /* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a
!                          no-op conversion, in-place on the array starting
!                          at (result + length).  */
!                       if (sizeof (DCHAR_T) != sizeof (TCHAR_T))
! # endif
!                         {
!                           const TCHAR_T *tmpsrc;
!                           DCHAR_T *tmpdst;
!                           size_t n;
! 
! # if USE_SNPRINTF
!                           if (result == resultbuf)
!                             {
!                               tmpsrc = (TCHAR_T *) (result + length);
!                               /* ENSURE_ALLOCATION will not move tmpsrc
!                                  (because it's part of resultbuf).  */
!                               ENSURE_ALLOCATION (xsum (length, count));
!                             }
!                           else
!                             {
!                               /* ENSURE_ALLOCATION will move the array
!                                  (because it uses realloc().  */
!                               ENSURE_ALLOCATION (xsum (length, count));
!                               tmpsrc = (TCHAR_T *) (result + length);
!                             }
! # else
!                           tmpsrc = tmp;
!                           ENSURE_ALLOCATION (xsum (length, count));
! # endif
!                           tmpdst = result + length;
!                           /* Copy backwards, because of overlapping.  */
!                           tmpsrc += count;
!                           tmpdst += count;
!                           for (n = count; n > 0; n--)
!                             *--tmpdst = (unsigned char) *--tmpsrc;
!                         }
!                     }
! #endif
! 
! #if DCHAR_IS_TCHAR && !USE_SNPRINTF
                    /* Make room for the result.  */
                    if (count > allocated - length)
                      {
!                       /* Need at least count elements.  But allocate
                           proportionally.  */
                        size_t n =
                          xmax (xsum (length, count), xtimes (allocated, 2));
***************
*** 3062,3138 ****
                    /* Here count <= allocated - length.  */
  
                    /* Perform padding.  */
! #if NEED_PRINTF_FLAG_ZERO
!                   if (pad_ourselves && has_width && count < width)
                      {
! # if USE_SNPRINTF
!                       /* Make room for the result.  */
!                       if (width > maxlen)
!                         {
!                           /* Need at least width bytes.  But allocate
!                              proportionally, to avoid looping eternally if
!                              snprintf() reports a too small count.  */
!                           size_t n =
!                             xmax (xsum (length, width),
!                                   xtimes (allocated, 2));
! 
!                           length += count;
!                           ENSURE_ALLOCATION (n);
!                           length -= count;
!                         }
!                       /* Here width <= allocated - length.  */
  # endif
!                       {
  # if USE_SNPRINTF
!                         DCHAR_T * const rp = result + length;
  # else
!                         DCHAR_T * const rp = tmp;
  # endif
!                         DCHAR_T *p = rp + count;
!                         size_t pad = width - count;
!                         DCHAR_T *end = p + pad;
!                         DCHAR_T *pad_ptr = (*rp == '-' ? rp + 1 : rp);
!                         /* No zero-padding of "inf" and "nan".  */
!                         if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
!                             || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
!                           pad_ptr = NULL;
!                         /* The generated string now extends from rp to p,
!                            with the zero padding insertion point being at
!                            pad_ptr.  */
  
!                         if (flags & FLAG_LEFT)
!                           {
!                             /* Pad with spaces on the right.  */
!                             for (; pad > 0; pad--)
!                               *p++ = ' ';
!                           }
!                         else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
!                           {
!                             /* Pad with zeroes.  */
!                             DCHAR_T *q = end;
  
!                             while (p > pad_ptr)
!                               *--q = *--p;
!                             for (; pad > 0; pad--)
!                               *p++ = '0';
!                           }
!                         else
!                           {
!                             /* Pad with spaces on the left.  */
!                             DCHAR_T *q = end;
  
!                             while (p > rp)
!                               *--q = *--p;
!                             for (; pad > 0; pad--)
!                               *p++ = ' ';
!                           }
  
!                         count = width; /* = count + pad = end - rp */
!                       }
                      }
  #endif
  
! #if !USE_SNPRINTF
                    if (count >= tmp_length)
                      /* tmp_length was incorrectly calculated - fix the
                         code above!  */
--- 3773,3876 ----
                    /* Here count <= allocated - length.  */
  
                    /* Perform padding.  */
! #if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO
!                   if (pad_ourselves && has_width)
                      {
!                       size_t w;
! # if ENABLE_UNISTDIO
!                       /* Outside POSIX, it's preferrable to compare the width
!                          against the number of _characters_ of the converted
!                          value.  */
!                       w = DCHAR_MBSNLEN (result + length, count);
! # else
!                       /* The width is compared against the number of _bytes_
!                          of the converted value, says POSIX.  */
!                       w = count;
  # endif
!                       if (w < width)
!                         {
!                           size_t pad = width - w;
  # if USE_SNPRINTF
!                           /* Make room for the result.  */
!                           if (xsum (count, pad) > allocated - length)
!                             {
!                               /* Need at least count + pad elements.  But
!                                  allocate proportionally.  */
!                               size_t n =
!                                 xmax (xsum3 (length, count, pad),
!                                       xtimes (allocated, 2));
! 
!                               length += count;
!                               ENSURE_ALLOCATION (n);
!                               length -= count;
!                             }
!                           /* Here count + pad <= allocated - length.  */
! # endif
!                           {
! # if !DCHAR_IS_TCHAR || USE_SNPRINTF
!                             DCHAR_T * const rp = result + length;
  # else
!                             DCHAR_T * const rp = tmp;
  # endif
!                             DCHAR_T *p = rp + count;
!                             DCHAR_T *end = p + pad;
! # if NEED_PRINTF_FLAG_ZERO
!                             DCHAR_T *pad_ptr;
! #  if !DCHAR_IS_TCHAR
!                             if (dp->conversion == 'c'
!                                 || dp->conversion == 's')
!                               /* No zero-padding for string directives.  */
!                               pad_ptr = NULL;
!                             else
! #  endif
!                               {
!                                 pad_ptr = (*rp == '-' ? rp + 1 : rp);
!                                 /* No zero-padding of "inf" and "nan".  */
!                                 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
!                                     || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
!                                   pad_ptr = NULL;
!                               }
! # endif
!                             /* The generated string now extends from rp to p,
!                                with the zero padding insertion point being at
!                                pad_ptr.  */
  
!                             count = count + pad; /* = end - rp */
  
!                             if (flags & FLAG_LEFT)
!                               {
!                                 /* Pad with spaces on the right.  */
!                                 for (; pad > 0; pad--)
!                                   *p++ = ' ';
!                               }
! # if NEED_PRINTF_FLAG_ZERO
!                             else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
!                               {
!                                 /* Pad with zeroes.  */
!                                 DCHAR_T *q = end;
  
!                                 while (p > pad_ptr)
!                                   *--q = *--p;
!                                 for (; pad > 0; pad--)
!                                   *p++ = '0';
!                               }
! # endif
!                             else
!                               {
!                                 /* Pad with spaces on the left.  */
!                                 DCHAR_T *q = end;
  
!                                 while (p > rp)
!                                   *--q = *--p;
!                                 for (; pad > 0; pad--)
!                                   *p++ = ' ';
!                               }
!                           }
!                         }
                      }
  #endif
  
! #if DCHAR_IS_TCHAR && !USE_SNPRINTF
                    if (count >= tmp_length)
                      /* tmp_length was incorrectly calculated - fix the
                         code above!  */
***************
*** 3141,3151 ****
  
                    /* Here still count <= allocated - length.  */
  
! #if USE_SNPRINTF
                    /* The snprintf() result did fit.  */
  #else
                    /* Append the sprintf() result.  */
                    memcpy (result + length, tmp, count * sizeof (DCHAR_T));
                    if (tmp != tmpbuf)
                      free (tmp);
  #endif
--- 3879,3891 ----
  
                    /* Here still count <= allocated - length.  */
  
! #if !DCHAR_IS_TCHAR || USE_SNPRINTF
                    /* The snprintf() result did fit.  */
  #else
                    /* Append the sprintf() result.  */
                    memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+ #endif
+ #if !USE_SNPRINTF
                    if (tmp != tmpbuf)
                      free (tmp);
  #endif
***************
*** 3214,3219 ****
--- 3954,3960 ----
    }
  }
  
+ #undef TCHARS_PER_DCHAR
  #undef SNPRINTF
  #undef USE_SNPRINTF
  #undef PRINTF_PARSE
*** m4/vasnprintf.m4    10 Jun 2007 15:05:31 -0000      1.27
--- m4/vasnprintf.m4    11 Jun 2007 00:47:00 -0000
***************
*** 1,4 ****
! # vasnprintf.m4 serial 19
  dnl Copyright (C) 2002-2004, 2006-2007 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
--- 1,4 ----
! # vasnprintf.m4 serial 20
  dnl Copyright (C) 2002-2004, 2006-2007 Free Software Foundation, Inc.
  dnl This file is free software; the Free Software Foundation
  dnl gives unlimited permission to copy and/or distribute it,
***************
*** 178,183 ****
--- 178,196 ----
    esac
  ])
  
+ # Prerequisites of lib/vasnprintf.c including all extras for POSIX compliance.
+ AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_EXTRAS],
+ [
+   AC_REQUIRE([gl_PREREQ_VASNPRINTF])
+   gl_PREREQ_VASNPRINTF_LONG_DOUBLE
+   gl_PREREQ_VASNPRINTF_INFINITE_DOUBLE
+   gl_PREREQ_VASNPRINTF_INFINITE_LONG_DOUBLE
+   gl_PREREQ_VASNPRINTF_DIRECTIVE_A
+   gl_PREREQ_VASNPRINTF_DIRECTIVE_F
+   gl_PREREQ_VASNPRINTF_FLAG_GROUPING
+   gl_PREREQ_VASNPRINTF_FLAG_ZERO
+ ])
+ 
  # Prerequisites of lib/asnprintf.c.
  AC_DEFUN([gl_PREREQ_ASNPRINTF],
  [





reply via email to

[Prev in Thread] Current Thread [Next in Thread]