[Top][All Lists]
[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],
[
- prepare vasnprintf for Unicode strings,
Bruno Haible <=
Re: prepare vasnprintf for Unicode strings, Daniel Jacobowitz, 2007/06/11