aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common')
-rw-r--r--stdio-common/Makefile3
-rw-r--r--stdio-common/_itoa.c4
-rw-r--r--stdio-common/_itowa.c346
-rw-r--r--stdio-common/_itowa.h63
-rw-r--r--stdio-common/itoa-digits.c7
-rw-r--r--stdio-common/itowa-digits.c27
-rw-r--r--stdio-common/printf-parse.h71
-rw-r--r--stdio-common/printf-prs.c4
-rw-r--r--stdio-common/printf.h3
-rw-r--r--stdio-common/printf_fp.c13
-rw-r--r--stdio-common/printf_size.c3
-rw-r--r--stdio-common/vfprintf.c585
-rw-r--r--stdio-common/vfscanf.c1313
-rw-r--r--stdio-common/vfwprintf.c3
-rw-r--r--stdio-common/vfwscanf.c2
15 files changed, 1874 insertions, 573 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 9fb0c5d15d..74900189a8 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -25,11 +25,12 @@ headers := printf.h
routines := \
ctermid cuserid \
- _itoa itoa-digits \
+ _itoa _itowa itoa-digits itowa-digits \
vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \
printf_size fprintf printf snprintf sprintf asprintf dprintf \
vfscanf \
fscanf scanf sscanf \
+ vfwprintf vfwscanf \
perror psignal \
tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname \
getline getw putw \
diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c
index 3a7cd78003..2eca838229 100644
--- a/stdio-common/_itoa.c
+++ b/stdio-common/_itoa.c
@@ -78,7 +78,7 @@ struct base_table_t
/* Local variables. */
-static const struct base_table_t base_table[] =
+const struct base_table_t _itoa_base_table[] =
{
#if BITS_PER_MP_LIMB == 64
/* 2 */ {SEL1(0ul) 1, 1},
@@ -171,7 +171,7 @@ _itoa (value, buflim, base, upper_case)
{
const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits;
char *bp = buflim;
- const struct base_table_t *brec = &base_table[base - 2];
+ const struct base_table_t *brec = &_itoa_base_table[base - 2];
switch (base)
{
diff --git a/stdio-common/_itowa.c b/stdio-common/_itowa.c
new file mode 100644
index 0000000000..430415b96b
--- /dev/null
+++ b/stdio-common/_itowa.c
@@ -0,0 +1,346 @@
+/* Internal function for converting integers to ASCII.
+ Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Torbjorn Granlund <tege@matematik.su.se>
+ and Ulrich Drepper <drepper@gnu.org>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <gmp-mparam.h>
+#include <stdlib/gmp.h>
+#include <stdlib/gmp-impl.h>
+#include <stdlib/longlong.h>
+
+#include "_itowa.h"
+
+
+/* Canonize environment. For some architectures not all values might
+ be defined in the GMP header files. */
+#ifndef UMUL_TIME
+# define UMUL_TIME 1
+#endif
+#ifndef UDIV_TIME
+# define UDIV_TIME 3
+#endif
+
+/* Control memory layout. */
+#ifdef PACK
+# undef PACK
+# define PACK __attribute__ ((packed))
+#else
+# define PACK
+#endif
+
+
+/* Declare local types. */
+struct base_table_t
+{
+#if (UDIV_TIME > 2 * UMUL_TIME)
+ mp_limb_t base_multiplier;
+#endif
+ char flag;
+ char post_shift;
+#if BITS_PER_MP_LIMB == 32
+ struct
+ {
+ char normalization_steps;
+ char ndigits;
+ mp_limb_t base PACK;
+#if UDIV_TIME > 2 * UMUL_TIME
+ mp_limb_t base_ninv PACK;
+#endif
+ } big;
+#endif
+};
+
+/* To reduce the memory needed we include some fields of the tables
+ only conditionally. */
+#if UDIV_TIME > 2 * UMUL_TIME
+# define SEL1(X) X,
+# define SEL2(X) ,X
+#else
+# define SEL1(X)
+# define SEL2(X)
+#endif
+
+/* Factor table for the different bases. */
+extern const struct base_table_t _itoa_base_table[];
+
+/* Lower-case digits. */
+extern const wchar_t _itowa_lower_digits[];
+/* Upper-case digits. */
+extern const wchar_t _itowa_upper_digits[];
+
+
+wchar_t *
+_itowa (value, buflim, base, upper_case)
+ unsigned long long int value;
+ wchar_t *buflim;
+ unsigned int base;
+ int upper_case;
+{
+ const wchar_t *digits = (upper_case
+ ? _itowa_upper_digits : _itowa_lower_digits);
+ wchar_t *bp = buflim;
+ const struct base_table_t *brec = &_itoa_base_table[base - 2];
+
+ switch (base)
+ {
+#define RUN_2N(BITS) \
+ do \
+ { \
+ /* `unsigned long long int' always has 64 bits. */ \
+ mp_limb_t work_hi = value >> (64 - BITS_PER_MP_LIMB); \
+ \
+ if (BITS_PER_MP_LIMB == 32) \
+ { \
+ if (work_hi != 0) \
+ { \
+ mp_limb_t work_lo; \
+ int cnt; \
+ \
+ work_lo = value & 0xfffffffful; \
+ for (cnt = BITS_PER_MP_LIMB / BITS; cnt > 0; --cnt) \
+ { \
+ *--bp = digits[work_lo & ((1ul << BITS) - 1)]; \
+ work_lo >>= BITS; \
+ } \
+ if (BITS_PER_MP_LIMB % BITS != 0) \
+ { \
+ work_lo \
+ |= ((work_hi \
+ & ((1 << (BITS - BITS_PER_MP_LIMB%BITS)) \
+ - 1)) \
+ << BITS_PER_MP_LIMB % BITS); \
+ work_hi >>= BITS - BITS_PER_MP_LIMB % BITS; \
+ if (work_hi == 0) \
+ work_hi = work_lo; \
+ else \
+ *--bp = digits[work_lo]; \
+ } \
+ } \
+ else \
+ work_hi = value & 0xfffffffful; \
+ } \
+ do \
+ { \
+ *--bp = digits[work_hi & ((1 << BITS) - 1)]; \
+ work_hi >>= BITS; \
+ } \
+ while (work_hi != 0); \
+ } \
+ while (0)
+ case 8:
+ RUN_2N (3);
+ break;
+
+ case 16:
+ RUN_2N (4);
+ break;
+
+ default:
+ {
+#if BITS_PER_MP_LIMB == 64
+ mp_limb_t base_multiplier = brec->base_multiplier;
+ if (brec->flag)
+ while (value != 0)
+ {
+ mp_limb_t quo, rem, x, dummy;
+
+ umul_ppmm (x, dummy, value, base_multiplier);
+ quo = (x + ((value - x) >> 1)) >> (brec->post_shift - 1);
+ rem = value - quo * base;
+ *--bp = digits[rem];
+ value = quo;
+ }
+ else
+ while (value != 0)
+ {
+ mp_limb_t quo, rem, x, dummy;
+
+ umul_ppmm (x, dummy, value, base_multiplier);
+ quo = x >> brec->post_shift;
+ rem = value - quo * base;
+ *--bp = digits[rem];
+ value = quo;
+ }
+#endif
+#if BITS_PER_MP_LIMB == 32
+ mp_limb_t t[3];
+ int n;
+
+ /* First convert x0 to 1-3 words in base s->big.base.
+ Optimize for frequent cases of 32 bit numbers. */
+ if ((mp_limb_t) (value >> 32) >= 1)
+ {
+#if UDIV_TIME > 2 * UMUL_TIME || UDIV_NEEDS_NORMALIZATION
+ int big_normalization_steps = brec->big.normalization_steps;
+ mp_limb_t big_base_norm
+ = brec->big.base << big_normalization_steps;
+#endif
+ if ((mp_limb_t) (value >> 32) >= brec->big.base)
+ {
+ mp_limb_t x1hi, x1lo, r;
+ /* If you want to optimize this, take advantage of
+ that the quotient in the first udiv_qrnnd will
+ always be very small. It might be faster just to
+ subtract in a tight loop. */
+
+#if UDIV_TIME > 2 * UMUL_TIME
+ mp_limb_t x, xh, xl;
+
+ if (big_normalization_steps == 0)
+ xh = 0;
+ else
+ xh = (mp_limb_t) (value >> (64 - big_normalization_steps));
+ xl = (mp_limb_t) (value >> (32 - big_normalization_steps));
+ udiv_qrnnd_preinv (x1hi, r, xh, xl, big_base_norm,
+ brec->big.base_ninv);
+
+ xl = ((mp_limb_t) value) << big_normalization_steps;
+ udiv_qrnnd_preinv (x1lo, x, r, xl, big_base_norm,
+ brec->big.base_ninv);
+ t[2] = x >> big_normalization_steps;
+
+ if (big_normalization_steps == 0)
+ xh = x1hi;
+ else
+ xh = ((x1hi << big_normalization_steps)
+ | (x1lo >> (32 - big_normalization_steps)));
+ xl = x1lo << big_normalization_steps;
+ udiv_qrnnd_preinv (t[0], x, xh, xl, big_base_norm,
+ brec->big.base_ninv);
+ t[1] = x >> big_normalization_steps;
+#elif UDIV_NEEDS_NORMALIZATION
+ mp_limb_t x, xh, xl;
+
+ if (big_normalization_steps == 0)
+ xh = 0;
+ else
+ xh = (mp_limb_t) (value >> 64 - big_normalization_steps);
+ xl = (mp_limb_t) (value >> 32 - big_normalization_steps);
+ udiv_qrnnd (x1hi, r, xh, xl, big_base_norm);
+
+ xl = ((mp_limb_t) value) << big_normalization_steps;
+ udiv_qrnnd (x1lo, x, r, xl, big_base_norm);
+ t[2] = x >> big_normalization_steps;
+
+ if (big_normalization_steps == 0)
+ xh = x1hi;
+ else
+ xh = ((x1hi << big_normalization_steps)
+ | (x1lo >> 32 - big_normalization_steps));
+ xl = x1lo << big_normalization_steps;
+ udiv_qrnnd (t[0], x, xh, xl, big_base_norm);
+ t[1] = x >> big_normalization_steps;
+#else
+ udiv_qrnnd (x1hi, r, 0, (mp_limb_t) (value >> 32),
+ brec->big.base);
+ udiv_qrnnd (x1lo, t[2], r, (mp_limb_t) value, brec->big.base);
+ udiv_qrnnd (t[0], t[1], x1hi, x1lo, brec->big.base);
+#endif
+ n = 3;
+ }
+ else
+ {
+#if (UDIV_TIME > 2 * UMUL_TIME)
+ mp_limb_t x;
+
+ value <<= brec->big.normalization_steps;
+ udiv_qrnnd_preinv (t[0], x, (mp_limb_t) (value >> 32),
+ (mp_limb_t) value, big_base_norm,
+ brec->big.base_ninv);
+ t[1] = x >> brec->big.normalization_steps;
+#elif UDIV_NEEDS_NORMALIZATION
+ mp_limb_t x;
+
+ value <<= big_normalization_steps;
+ udiv_qrnnd (t[0], x, (mp_limb_t) (value >> 32),
+ (mp_limb_t) value, big_base_norm);
+ t[1] = x >> big_normalization_steps;
+#else
+ udiv_qrnnd (t[0], t[1], (mp_limb_t) (value >> 32),
+ (mp_limb_t) value, brec->big.base);
+#endif
+ n = 2;
+ }
+ }
+ else
+ {
+ t[0] = value;
+ n = 1;
+ }
+
+ /* Convert the 1-3 words in t[], word by word, to ASCII. */
+ do
+ {
+ mp_limb_t ti = t[--n];
+ int ndig_for_this_limb = 0;
+
+#if UDIV_TIME > 2 * UMUL_TIME
+ mp_limb_t base_multiplier = brec->base_multiplier;
+ if (brec->flag)
+ while (ti != 0)
+ {
+ mp_limb_t quo, rem, x, dummy;
+
+ umul_ppmm (x, dummy, ti, base_multiplier);
+ quo = (x + ((ti - x) >> 1)) >> (brec->post_shift - 1);
+ rem = ti - quo * base;
+ *--bp = digits[rem];
+ ti = quo;
+ ++ndig_for_this_limb;
+ }
+ else
+ while (ti != 0)
+ {
+ mp_limb_t quo, rem, x, dummy;
+
+ umul_ppmm (x, dummy, ti, base_multiplier);
+ quo = x >> brec->post_shift;
+ rem = ti - quo * base;
+ *--bp = digits[rem];
+ ti = quo;
+ ++ndig_for_this_limb;
+ }
+#else
+ while (ti != 0)
+ {
+ mp_limb_t quo, rem;
+
+ quo = ti / base;
+ rem = ti % base;
+ *--bp = digits[rem];
+ ti = quo;
+ ++ndig_for_this_limb;
+ }
+#endif
+ /* If this wasn't the most significant word, pad with zeros. */
+ if (n != 0)
+ while (ndig_for_this_limb < brec->big.ndigits)
+ {
+ *--bp = '0';
+ ++ndig_for_this_limb;
+ }
+ }
+ while (n != 0);
+#endif
+ }
+ break;
+ }
+
+ return bp;
+}
diff --git a/stdio-common/_itowa.h b/stdio-common/_itowa.h
new file mode 100644
index 0000000000..e219f298ee
--- /dev/null
+++ b/stdio-common/_itowa.h
@@ -0,0 +1,63 @@
+/* Internal function for converting integers to ASCII.
+ Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _ITOWA_H
+#define _ITOWA_H 1
+#include <features.h>
+#include <wchar.h>
+
+/* Convert VALUE into ASCII in base BASE (2..36).
+ Write backwards starting the character just before BUFLIM.
+ Return the address of the first (left-to-right) character in the number.
+ Use upper case letters iff UPPER_CASE is nonzero. */
+
+extern wchar_t *_itowa __P ((unsigned long long int value, wchar_t *buflim,
+ unsigned int base, int upper_case));
+
+static inline wchar_t *
+__attribute__ ((unused))
+_itowa_word (unsigned long value, wchar_t *buflim,
+ unsigned int base, int upper_case)
+{
+ extern const wchar_t _itowa_upper_digits[], _itowa_lower_digits[];
+ const wchar_t *digits = (upper_case
+ ? _itowa_upper_digits : _itowa_lower_digits);
+ wchar_t *bp = buflim;
+
+ switch (base)
+ {
+#define SPECIAL(Base) \
+ case Base: \
+ do \
+ *--bp = digits[value % Base]; \
+ while ((value /= Base) != 0); \
+ break
+
+ SPECIAL (10);
+ SPECIAL (16);
+ SPECIAL (8);
+ default:
+ do
+ *--bp = digits[value % base];
+ while ((value /= base) != 0);
+ }
+ return bp;
+}
+
+#endif /* itowa.h */
diff --git a/stdio-common/itoa-digits.c b/stdio-common/itoa-digits.c
index b475bbca42..34699dbcc8 100644
--- a/stdio-common/itoa-digits.c
+++ b/stdio-common/itoa-digits.c
@@ -1,5 +1,5 @@
/* Digits.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -18,9 +18,8 @@
Boston, MA 02111-1307, USA. */
/* Lower-case digits. */
-const char _itoa_lower_digits[]
+const char _itoa_lower_digits[36]
= "0123456789abcdefghijklmnopqrstuvwxyz";
/* Upper-case digits. */
-const char _itoa_upper_digits[]
+const char _itoa_upper_digits[36]
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
diff --git a/stdio-common/itowa-digits.c b/stdio-common/itowa-digits.c
new file mode 100644
index 0000000000..60a85789e3
--- /dev/null
+++ b/stdio-common/itowa-digits.c
@@ -0,0 +1,27 @@
+/* Digits.
+ Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <wchar.h>
+
+/* Lower-case digits. */
+const wchar_t _itowa_lower_digits[36]
+ = L"0123456789abcdefghijklmnopqrstuvwxyz";
+/* Upper-case digits. */
+const wchar_t _itowa_upper_digits[36]
+ = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h
index a915f03f18..d62f3a835e 100644
--- a/stdio-common/printf-parse.h
+++ b/stdio-common/printf-parse.h
@@ -35,7 +35,7 @@ struct printf_spec
/* Pointers into the format string for the end of this format
spec and the next (or to the end of the string if no more). */
- const char *end_of_fmt, *next_fmt;
+ const UCHAR_T *end_of_fmt, *next_fmt;
/* Position of arguments for precision and width, or -1 if `info' has
the constant value. */
@@ -90,21 +90,29 @@ read_int (const UCHAR_T * *pstr)
/* Find the next spec in FORMAT, or the end of the string. Returns
a pointer into FORMAT, to a '%' or a '\0'. */
-static inline const char *
-find_spec (const char *format, mbstate_t *ps)
+static inline const UCHAR_T *
+#ifdef COMPILE_WPRINTF
+find_spec (const UCHAR_T *format)
+#else
+find_spec (const UCHAR_T *format, mbstate_t *ps)
+#endif
{
- while (*format != '\0' && *format != '%')
+#ifdef COMPILE_WPRINTF
+ return (const UCHAR_T *) __wcschrnul ((const CHAR_T *) format, L'%');
+#else
+ while (*format != L_('\0') && *format != L_('%'))
{
int len;
/* Remove any hints of a wrong encoding. */
ps->count = 0;
- if (isascii (*format) || (len = mbrlen (format, MB_CUR_MAX, ps)) <= 0)
- ++format;
- else
+ if (! ISASCII (*format) && (len = MBRLEN (format, MB_CUR_MAX, ps)) > 0)
format += len;
+ else
+ ++format;
}
return format;
+#endif
}
@@ -119,8 +127,13 @@ extern printf_function **__printf_function_table;
the number of args consumed by this spec; *MAX_REF_ARG is updated so it
remains the highest argument index used. */
static inline size_t
+#ifdef COMPILE_WPRINTF
+parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
+ size_t *max_ref_arg)
+#else
parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
size_t *max_ref_arg, mbstate_t *ps)
+#endif
{
unsigned int n;
size_t nargs = 0;
@@ -342,12 +355,12 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
switch (spec->info.spec)
{
- case L'i':
- case L'd':
- case L'u':
- case L'o':
- case L'X':
- case L'x':
+ case L_('i'):
+ case L_('d'):
+ case L_('u'):
+ case L_('o'):
+ case L_('X'):
+ case L_('x'):
#if LONG_MAX != LONG_LONG_MAX
if (spec->info.is_long_double)
spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG;
@@ -362,38 +375,38 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
else
spec->data_arg_type = PA_INT;
break;
- case L'e':
- case L'E':
- case L'f':
- case L'g':
- case L'G':
- case L'a':
- case L'A':
+ case L_('e'):
+ case L_('E'):
+ case L_('f'):
+ case L_('g'):
+ case L_('G'):
+ case L_('a'):
+ case L_('A'):
if (spec->info.is_long_double)
spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
else
spec->data_arg_type = PA_DOUBLE;
break;
- case L'c':
+ case L_('c'):
spec->data_arg_type = PA_CHAR;
break;
- case L'C':
+ case L_('C'):
spec->data_arg_type = PA_WCHAR;
break;
- case L's':
+ case L_('s'):
spec->data_arg_type = PA_STRING;
break;
- case L'S':
+ case L_('S'):
spec->data_arg_type = PA_WSTRING;
break;
- case L'p':
+ case L_('p'):
spec->data_arg_type = PA_POINTER;
break;
- case L'n':
+ case L_('n'):
spec->data_arg_type = PA_INT|PA_FLAG_PTR;
break;
- case L'm':
+ case L_('m'):
default:
/* An unknown spec will consume no args. */
spec->ndata_args = 0;
@@ -416,7 +429,11 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
{
/* Find the next format spec. */
spec->end_of_fmt = format;
+#ifdef COMPILE_WPRINTF
+ spec->next_fmt = find_spec (format);
+#else
spec->next_fmt = find_spec (format, ps);
+#endif
}
return nargs;
diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c
index 4f15373544..19869cad19 100644
--- a/stdio-common/printf-prs.c
+++ b/stdio-common/printf-prs.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1995, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1995, 1996, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -29,6 +29,8 @@
# define INT_T int
# define L_(Str) Str
# define ISDIGIT(Ch) isdigit (Ch)
+# define ISASCII(Ch) isascii (Ch)
+# define MBRLEN(Cp, L, St) mbrlen (Cp, L, St)
# ifdef USE_IN_LIBIO
# define PUT(F, S, N) _IO_sputn (F, S, N)
diff --git a/stdio-common/printf.h b/stdio-common/printf.h
index 18b2f4ab8a..66ac5d0742 100644
--- a/stdio-common/printf.h
+++ b/stdio-common/printf.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 95, 96, 97, 98 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,95,96,97,98,99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -45,6 +45,7 @@ struct printf_info
unsigned int group:1; /* ' flag. */
unsigned int extra:1; /* For special use. */
unsigned int is_char:1; /* hh flag. */
+ unsigned int wide:1; /* Nonzero for wide character streams. */
wchar_t pad; /* Padding character. */
};
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
index c75289a3a9..1b550abe4f 100644
--- a/stdio-common/printf_fp.c
+++ b/stdio-common/printf_fp.c
@@ -52,11 +52,12 @@
the GNU I/O library. */
#ifdef USE_IN_LIBIO
# define PUT(f, s, n) _IO_sputn (f, s, n)
-# define PAD(f, c, n) _IO_padn (f, c, n)
+# define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n))
/* We use this file GNU C library and GNU I/O library. So make
names equal. */
# undef putc
-# define putc(c, f) _IO_putc_unlocked (c, f)
+# define putc(c, f) (wide \
+ ? _IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
# define size_t _IO_size_t
# define FILE _IO_FILE
#else /* ! USE_IN_LIBIO */
@@ -188,6 +189,9 @@ __printf_fp (FILE *fp,
/* General helper (carry limb). */
mp_limb_t cy;
+ /* Nonzero if this is output on a wide character stream. */
+ int wide = info->wide;
+
char hack_digit (void)
{
mp_limb_t hi;
@@ -765,7 +769,10 @@ __printf_fp (FILE *fp,
if ((expsign == 0 && exponent >= dig_max)
|| (expsign != 0 && exponent > 4))
{
- type = isupper (info->spec) ? 'E' : 'e';
+ if ('g' - 'G' == 'e' - 'E')
+ type = 'E' + (info->spec - 'G');
+ else
+ type = isupper (info->spec) ? 'E' : 'e';
fracdig_max = dig_max - 1;
intdig_max = 1;
chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4;
diff --git a/stdio-common/printf_size.c b/stdio-common/printf_size.c
index 34581067dc..654675a0d7 100644
--- a/stdio-common/printf_size.c
+++ b/stdio-common/printf_size.c
@@ -1,5 +1,5 @@
/* Print size value using units for orders of magnitude.
- Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
Based on a proposal by Larry McVoy <lm@sgi.com>.
@@ -212,6 +212,7 @@ printf_size (FILE *fp, const struct printf_info *info, const void *const *args)
fp_info.group = info->group;
fp_info.extra = info->extra;
fp_info.pad = info->pad;
+ fp_info.wide = 0;
if (fp_info.left && fp_info.pad == L' ')
{
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 390ce91f71..fe145d6a3d 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -36,74 +36,16 @@
Beside this it is also shared between the normal and wide character
implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */
-#ifndef COMPILE_WPRINTF
-# define CHAR_T char
-# define UCHAR_T unsigned char
-# define INT_T int
-# define L_(Str) Str
-# define ISDIGIT(Ch) isdigit (Ch)
-
-# ifdef USE_IN_LIBIO
-# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
-# define PAD(Padchar) \
- if (width > 0) \
- done += _IO_padn (s, (Padchar), width)
-# else
-# define PUTC(C, F) putc (C, F)
-ssize_t __printf_pad __P ((FILE *, char pad, size_t n));
-# define PAD(Padchar) \
- if (width > 0) \
- { ssize_t __res = __printf_pad (s, (Padchar), width); \
- if (__res == -1) \
- { \
- done = -1; \
- goto all_done; \
- } \
- done += __res; }
-# endif
-#else
-# define vfprintf vfwprintf
-# define CHAR_T wchar_t
-# define UCHAR_T uwchar_t
-# define INT_T wint_t
-# define L_(Str) L##Str
-# define ISDIGIT(Ch) iswdigit (Ch)
-
-# ifdef USE_IN_LIBIO
-# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
-# define PAD(Padchar) \
- if (width > 0) \
- done += _IO_wpadn (s, (Padchar), width)
-# else
-# define PUTC(C, F) wputc (C, F)
-ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
-# define PAD(Padchar) \
- if (width > 0) \
- { ssize_t __res = __wprintf_pad (s, (Padchar), width); \
- if (__res == -1) \
- { \
- done = -1; \
- goto all_done; \
- } \
- done += __res; }
-# endif
-#endif
-
-/* Include the shared code for parsing the format string. */
-#include "printf-parse.h"
-
#ifdef USE_IN_LIBIO
/* This code is for use in libio. */
# include <libioP.h>
-# define PUTC(C, F) _IO_putc_unlocked (C, F)
-# define vfprintf _IO_vfprintf
# define FILE _IO_FILE
# undef va_list
# define va_list _IO_va_list
-# undef BUFSIZ
+# undef BUFSIZ
# define BUFSIZ _IO_BUFSIZ
-# define ARGCHECK(S, Format) \
+# define ARGCHECK(S, Format) \
do \
{ \
/* Check file argument for consistence. */ \
@@ -120,11 +62,54 @@ ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
} \
} while (0)
# define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED)
+
+# ifndef COMPILE_WPRINTF
+# define vfprintf _IO_vfprintf
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define INT_T int
+# define L_(Str) Str
+# define ISDIGIT(Ch) isdigit (Ch)
+# define ISASCII(Ch) isascii (Ch)
+# define MBRLEN(Cp, L, St) mbrlen (Cp, L, St)
+
+# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
+# define PAD(Padchar) \
+ if (width > 0) \
+ done += _IO_padn (s, (Padchar), width)
+# define PUTC(C, F) _IO_putc_unlocked (C, F)
+# define ORIENT if (_IO_fwide (s, -1) != -1) return -1
+# else
+# include "_itowa.h"
+
+# define vfprintf _IO_vfwprintf
+# define CHAR_T wchar_t
+/* This is a hack!!! There should be a type uwchar_t. */
+# define UCHAR_T unsigned int /* uwchar_t */
+# define INT_T wint_t
+# define L_(Str) L##Str
+# define ISDIGIT(Ch) iswdigit (Ch)
+# define ISASCII(Ch) (((unsigned int) (Ch) & ~0x7f) == 0)
+# define MBRLEN(Cp, L, St) wcslen ((const wchar_t *) (Cp))
+
+# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
+# define PAD(Padchar) \
+ if (width > 0) \
+ done += _IO_wpadn (s, (Padchar), width)
+# define PUTC(C, F) _IO_putwc_unlocked (C, F)
+# define ORIENT if (_IO_fwide (s, 1) != 1) return -1
+
+# define _itoa(Val, Buf, Base, Case) _itowa (Val, (wchar_t *) Buf, Base, Case)
+# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, (wchar_t *) Buf, \
+ Base, Case)
+# undef EOF
+# define EOF WEOF
+# endif
#else /* ! USE_IN_LIBIO */
/* This code is for use in the GNU C library. */
# include <stdio.h>
# define PUT(F, S, N) fwrite (S, 1, N, F)
-# define ARGCHECK(S, Format) \
+# define ARGCHECK(S, Format) \
do \
{ \
/* Check file argument for consistence. */ \
@@ -153,11 +138,14 @@ extern void __flockfile (FILE *);
extern void __funlockfile (FILE *);
#endif /* USE_IN_LIBIO */
+/* Include the shared code for parsing the format string. */
+#include "printf-parse.h"
+
#define outchar(Ch) \
do \
{ \
- register const int outc = (Ch); \
+ register const INT_T outc = (Ch); \
if (PUTC (outc, s) == EOF) \
{ \
done = -1; \
@@ -199,7 +187,7 @@ extern void __funlockfile (FILE *);
/* Global variables. */
-static const char null[] = "(null)";
+static const CHAR_T null[] = L_("(null)");
/* Helper function to provide temporary buffering for unbuffered streams. */
@@ -211,7 +199,8 @@ static int printf_unknown __P ((FILE *, const struct printf_info *,
const void *const *));
/* Group digits of number string. */
-static char *group_number __P ((CHAR_T *, CHAR_T *, const CHAR_T *, wchar_t))
+static UCHAR_T *group_number __P ((UCHAR_T *, UCHAR_T *, const char *,
+ wchar_t))
internal_function;
@@ -238,11 +227,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
const UCHAR_T *end_of_spec;
/* Buffer intermediate results. */
- char work_buffer[1000];
- char *workend;
+ UCHAR_T work_buffer[1000];
+ UCHAR_T *workend;
/* State for restartable multibyte character handling functions. */
+#ifndef COMPILE_WPRINTF
mbstate_t mbstate;
+#endif
/* We have to save the original argument pointer. */
va_list ap_save;
@@ -505,7 +496,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
now process the wanted format specifier. */ \
LABEL (form_percent): \
/* Write a literal "%". */ \
- outchar ('%'); \
+ outchar (L_('%')); \
break; \
\
LABEL (form_integer): \
@@ -588,7 +579,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
else \
/* We have to take care for the '0' flag. If a precision \
is given it must be ignored. */ \
- pad = ' '; \
+ pad = L_(' '); \
\
/* If the precision is 0 and the number is 0 nothing has to \
be written for the number, except for the 'o' format in \
@@ -597,13 +588,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
{ \
string = workend; \
if (base == 8 && alt) \
- *string-- = '0'; \
+ *string-- = L_('0'); \
} \
else \
{ \
/* Put the number in WORK. */ \
- string = _itoa (number.longlong, workend + 1, base, \
- spec == 'X'); \
+ string = (UCHAR_T *) _itoa (number.longlong, workend + 1, base, \
+ spec == L_('X')); \
string -= 1; \
if (group && grouping) \
string = group_number (string, workend, grouping, \
@@ -642,7 +633,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
else \
/* We have to take care for the '0' flag. If a precision \
is given it must be ignored. */ \
- pad = ' '; \
+ pad = L_(' '); \
\
/* If the precision is 0 and the number is 0 nothing has to \
be written for the number, except for the 'o' format in \
@@ -651,13 +642,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
{ \
string = workend; \
if (base == 8 && alt) \
- *string-- = '0'; \
+ *string-- = L_('0'); \
} \
else \
{ \
/* Put the number in WORK. */ \
- string = _itoa_word (number.word, workend + 1, base, \
- spec == 'X'); \
+ string = (UCHAR_T *) _itoa_word (number.word, workend + 1, \
+ base, spec == L_('X')); \
string -= 1; \
if (group && grouping) \
string = group_number (string, workend, grouping, \
@@ -670,10 +661,10 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (prec > 0) \
/* Add zeros to the precision. */ \
while (prec-- > 0) \
- *string-- = '0'; \
+ *string-- = L_('0'); \
else if (number.word != 0 && alt && base == 8) \
/* Add octal marker. */ \
- *string-- = '0'; \
+ *string-- = L_('0'); \
\
if (!left) \
{ \
@@ -686,41 +677,41 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (is_negative || showsign || space) \
--width; \
\
- if (pad == '0') \
+ if (pad == L_('0')) \
{ \
while (width-- > 0) \
- *string-- = '0'; \
+ *string-- = L_('0'); \
\
if (number.word != 0 && alt && base == 16) \
{ \
*string-- = spec; \
- *string-- = '0'; \
+ *string-- = L_('0'); \
} \
\
if (is_negative) \
- *string-- = '-'; \
+ *string-- = L_('-'); \
else if (showsign) \
- *string-- = '+'; \
+ *string-- = L_('+'); \
else if (space) \
- *string-- = ' '; \
+ *string-- = L_(' '); \
} \
else \
{ \
if (number.word != 0 && alt && base == 16) \
{ \
*string-- = spec; \
- *string-- = '0'; \
+ *string-- = L_('0'); \
} \
\
if (is_negative) \
- *string-- = '-'; \
+ *string-- = L_('-'); \
else if (showsign) \
- *string-- = '+'; \
+ *string-- = L_('+'); \
else if (space) \
- *string-- = ' '; \
+ *string-- = L_(' '); \
\
while (width-- > 0) \
- *string-- = ' '; \
+ *string-- = L_(' '); \
} \
\
outstring (string + 1, workend - string); \
@@ -732,20 +723,20 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (number.word != 0 && alt && base == 16) \
{ \
*string-- = spec; \
- *string-- = '0'; \
+ *string-- = L_('0'); \
} \
\
if (is_negative) \
- *string-- = '-'; \
+ *string-- = L_('-'); \
else if (showsign) \
- *string-- = '+'; \
+ *string-- = L_('+'); \
else if (space) \
- *string-- = ' '; \
+ *string-- = L_(' '); \
\
width -= workend - string; \
outstring (string + 1, workend - string); \
\
- PAD (' '); \
+ PAD (L_(' ')); \
break; \
} \
\
@@ -771,7 +762,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
showsign: showsign, \
group: group, \
pad: pad, \
- extra: 0 }; \
+ extra: 0, \
+ wide: sizeof (CHAR_T) != 1 }; \
\
if (is_long_double) \
the_arg.pa_long_double = va_arg (ap, long double); \
@@ -821,7 +813,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
showsign: showsign, \
group: group, \
pad: pad, \
- extra: 0 }; \
+ extra: 0, \
+ wide: sizeof (CHAR_T) != 1 }; \
\
if (is_long_double) \
the_arg.pa_long_double = va_arg (ap, long double); \
@@ -849,6 +842,178 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
} \
break; \
\
+ LABEL (form_pointer): \
+ /* Generic pointer. */ \
+ { \
+ const void *ptr; \
+ if (fspec == NULL) \
+ ptr = va_arg (ap, void *); \
+ else \
+ ptr = args_value[fspec->data_arg].pa_pointer; \
+ if (ptr != NULL) \
+ { \
+ /* If the pointer is not NULL, write it as a %#x spec. */ \
+ base = 16; \
+ number.word = (unsigned long int) ptr; \
+ is_negative = 0; \
+ alt = 1; \
+ group = 0; \
+ spec = 'x'; \
+ goto LABEL (number); \
+ } \
+ else \
+ { \
+ /* Write "(nil)" for a nil pointer. */ \
+ string = (UCHAR_T *) L_("(nil)"); \
+ /* Make sure the full string "(nil)" is printed. */ \
+ if (prec < 5) \
+ prec = 5; \
+ is_long = 0; /* This is no wide-char string. */ \
+ goto LABEL (print_string); \
+ } \
+ } \
+ /* NOTREACHED */ \
+ \
+ LABEL (form_number): \
+ /* Answer the count of characters written. */ \
+ if (fspec == NULL) \
+ { \
+ if (is_longlong) \
+ *(long long int *) va_arg (ap, void *) = done; \
+ else if (is_long_num) \
+ *(long int *) va_arg (ap, void *) = done; \
+ else if (!is_short) \
+ *(int *) va_arg (ap, void *) = done; \
+ else \
+ *(short int *) va_arg (ap, void *) = done; \
+ } \
+ else \
+ if (is_longlong) \
+ *(long long int *) args_value[fspec->data_arg].pa_pointer = done; \
+ else if (is_long_num) \
+ *(long int *) args_value[fspec->data_arg].pa_pointer = done; \
+ else if (!is_short) \
+ *(int *) args_value[fspec->data_arg].pa_pointer = done; \
+ else \
+ *(short int *) args_value[fspec->data_arg].pa_pointer = done; \
+ break; \
+ \
+ LABEL (form_strerror): \
+ /* Print description of error ERRNO. */ \
+ string = \
+ (UCHAR_T *) __strerror_r (save_errno, (char *) work_buffer, \
+ sizeof work_buffer); \
+ is_long = 0; /* This is no wide-char string. */ \
+ goto LABEL (print_string)
+
+#ifdef COMPILE_WPRINTF
+# define process_string_arg(fspec) \
+ LABEL (form_character): \
+ /* Character. */ \
+ if (is_long) \
+ goto LABEL (form_wcharacter); \
+ --width; /* Account for the character itself. */ \
+ if (!left) \
+ PAD (L' '); \
+ if (fspec == NULL) \
+ outchar (btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
+ else \
+ outchar (btowc ((unsigned char) args_value[fspec->data_arg].pa_char));\
+ if (left) \
+ PAD (L' '); \
+ break; \
+ \
+ LABEL (form_wcharacter): \
+ { \
+ /* Wide character. */ \
+ --width; \
+ if (!left) \
+ PAD (L' '); \
+ if (fspec == NULL) \
+ outchar (va_arg (ap, wint_t)); \
+ else \
+ outchar (args_value[fspec->data_arg].pa_wchar); \
+ if (left) \
+ PAD (L' '); \
+ } \
+ break; \
+ \
+ LABEL (form_string): \
+ { \
+ size_t len; \
+ \
+ /* The string argument could in fact be `char *' or `wchar_t *'. \
+ But this should not make a difference here. */ \
+ if (fspec == NULL) \
+ string = (UCHAR_T *) va_arg (ap, const wchar_t *); \
+ else \
+ string = (UCHAR_T *) args_value[fspec->data_arg].pa_wstring; \
+ \
+ /* Entry point for printing other strings. */ \
+ LABEL (print_string): \
+ \
+ if (string == NULL) \
+ { \
+ /* Write "(null)" if there's space. */ \
+ if (prec == -1 \
+ || prec >= (int) (sizeof (null) / sizeof (null[0])) - 1) \
+ { \
+ string = (UCHAR_T *) null; \
+ len = (sizeof (null) / sizeof (null[0])) - 1; \
+ } \
+ else \
+ { \
+ string = (UCHAR_T *) L""; \
+ len = 0; \
+ } \
+ } \
+ else if (!is_long && spec != L_('S')) \
+ { \
+ /* This is complicated. We have to transform the multibyte \
+ string into a wide character string. */ \
+ const char *mbs = (const char *) string; \
+ mbstate_t mbstate; \
+ \
+ len = prec == -1 ? strnlen (mbs, prec) : strlen (mbs); \
+ \
+ /* Allocate dynamically an array which definitely is long \
+ enough for the wide character version. */ \
+ string = (UCHAR_T *) alloca ((len + 1) * sizeof (wchar_t)); \
+ \
+ memset (&mbstate, '\0', sizeof (mbstate_t)); \
+ len = __mbsrtowcs ((wchar_t *) string, &mbs, len + 1, &mbstate); \
+ if (len == (size_t) -1) \
+ { \
+ /* Illegal multibyte character. */ \
+ done = -1; \
+ goto all_done; \
+ } \
+ } \
+ else \
+ { \
+ if (prec != -1) \
+ /* Search for the end of the string, but don't search past \
+ the length specified by the precision. */ \
+ len = __wcsnlen ((wchar_t *) string, prec); \
+ else \
+ len = __wcslen ((wchar_t *) string); \
+ } \
+ \
+ if ((width -= len) < 0) \
+ { \
+ outstring (string, len); \
+ break; \
+ } \
+ \
+ if (!left) \
+ PAD (L' '); \
+ outstring (string, len); \
+ if (left) \
+ PAD (L' '); \
+ } \
+ break;
+#else
+# define process_string_arg(fspec) \
LABEL (form_character): \
/* Character. */ \
if (is_long) \
@@ -917,7 +1082,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (prec != -1) \
/* Search for the end of the string, but don't search past \
the length specified by the precision. */ \
- len = strnlen (string, prec); \
+ len = __strnlen (string, prec); \
else \
len = strlen (string); \
} \
@@ -939,7 +1104,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
s2 = (const wchar_t *) string; \
string = alloca (len + 1); \
(void) __wcsrtombs (string, &s2, len + 1, &mbstate); \
- if (prec < len) \
+ if (prec > 0 && prec < len) \
len = prec; \
} \
\
@@ -955,75 +1120,23 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
if (left) \
PAD (' '); \
} \
- break; \
- \
- LABEL (form_pointer): \
- /* Generic pointer. */ \
- { \
- const void *ptr; \
- if (fspec == NULL) \
- ptr = va_arg (ap, void *); \
- else \
- ptr = args_value[fspec->data_arg].pa_pointer; \
- if (ptr != NULL) \
- { \
- /* If the pointer is not NULL, write it as a %#x spec. */ \
- base = 16; \
- number.word = (unsigned long int) ptr; \
- is_negative = 0; \
- alt = 1; \
- group = 0; \
- spec = 'x'; \
- goto LABEL (number); \
- } \
- else \
- { \
- /* Write "(nil)" for a nil pointer. */ \
- string = (char *) "(nil)"; \
- /* Make sure the full string "(nil)" is printed. */ \
- if (prec < 5) \
- prec = 5; \
- is_long = 0; /* This is no wide-char string. */ \
- goto LABEL (print_string); \
- } \
- } \
- /* NOTREACHED */ \
- \
- LABEL (form_number): \
- /* Answer the count of characters written. */ \
- if (fspec == NULL) \
- { \
- if (is_longlong) \
- *(long long int *) va_arg (ap, void *) = done; \
- else if (is_long_num) \
- *(long int *) va_arg (ap, void *) = done; \
- else if (!is_short) \
- *(int *) va_arg (ap, void *) = done; \
- else \
- *(short int *) va_arg (ap, void *) = done; \
- } \
- else \
- if (is_longlong) \
- *(long long int *) args_value[fspec->data_arg].pa_pointer = done; \
- else if (is_long_num) \
- *(long int *) args_value[fspec->data_arg].pa_pointer = done; \
- else if (!is_short) \
- *(int *) args_value[fspec->data_arg].pa_pointer = done; \
- else \
- *(short int *) args_value[fspec->data_arg].pa_pointer = done; \
- break; \
- \
- LABEL (form_strerror): \
- /* Print description of error ERRNO. */ \
- string = \
- (char *) __strerror_r (save_errno, work_buffer, sizeof work_buffer); \
- is_long = 0; /* This is no wide-char string. */ \
- goto LABEL (print_string)
+ break;
+#endif
+ /* Orient the stream. */
+#ifdef ORIENT
+ ORIENT;
+#endif
/* Sanity check of arguments. */
ARGCHECK (s, format);
+ /* Check for correct orientation. */
+ if (_IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
+ != (sizeof (CHAR_T) == 1 ? -1 : 1))
+ /* The stream is already oriented otherwise. */
+ return EOF;
+
if (UNBUFFERED_P (s))
/* Use a helper function which will allocate a local temporary buffer
for the stream and then call us again. */
@@ -1041,11 +1154,16 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
#endif
nspecs_done = 0;
+#ifdef COMPILE_WPRINTF
+ /* Find the first format specifier. */
+ f = lead_str_end = find_spec ((const UCHAR_T *) format);
+#else
/* Put state for processing format string in initial state. */
memset (&mbstate, '\0', sizeof (mbstate_t));
/* Find the first format specifier. */
f = lead_str_end = find_spec (format, &mbstate);
+#endif
/* Lock stream. */
#ifdef USE_IN_LIBIO
@@ -1081,7 +1199,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
} number;
int base;
union printf_arg the_arg;
- char *string; /* Pointer to argument string. */
+ UCHAR_T *string; /* Pointer to argument string. */
int alt = 0; /* Alternate format. */
int space = 0; /* Use space prefix if no sign is needed. */
int left = 0; /* Left-justify output. */
@@ -1093,10 +1211,10 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
int is_char = 0; /* Argument is promoted (unsigned) char. */
int width = 0; /* Width of output; 0 means none specified. */
int prec = -1; /* Precision of output; -1 means none specified. */
- char pad = ' '; /* Padding character. */
+ UCHAR_T pad = L_(' ');/* Padding character. */
CHAR_T spec;
- workend = &work_buffer[sizeof (work_buffer) - 1];
+ workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T) - 1];
/* Get current character in format string. */
JUMP (*++f, step0_jumps);
@@ -1172,10 +1290,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
left = 1;
}
- if (width + 32 >= sizeof (work_buffer))
+ if (width + 32 >= sizeof (work_buffer) / sizeof (work_buffer[0]))
/* We have to use a special buffer. The "32" is just a safe
bet for all the output which is not counted in the width. */
- workend = alloca (width + 32) + (width + 31);
+ workend = ((UCHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
+ + (width + 31));
}
JUMP (*f, step1_jumps);
@@ -1183,10 +1302,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
LABEL (width):
width = read_int (&f);
- if (width + 32 >= sizeof (work_buffer))
+ if (width + 32 >= sizeof (work_buffer) / sizeof (work_buffer[0]))
/* We have to use a special buffer. The "32" is just a safe
bet for all the output which is not counted in the width. */
- workend = alloca (width + 32) + (width + 31);
+ workend = ((UCHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
+ + (width + 31));
if (*f == L_('$'))
/* Oh, oh. The argument comes from a positional parameter. */
goto do_positional;
@@ -1213,7 +1333,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
prec = read_int (&f);
else
prec = 0;
- if (prec > width && prec + 32 > sizeof (work_buffer))
+ if (prec > width
+ && prec + 32 > sizeof (work_buffer) / sizeof (work_buffer[0]))
workend = alloca (spec + 32) + (spec + 31);
JUMP (*f, step2_jumps);
@@ -1258,6 +1379,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
while (1)
{
process_arg (((struct printf_spec *) NULL));
+ process_string_arg (((struct printf_spec *) NULL));
LABEL (form_unknown):
if (spec == L_('\0'))
@@ -1276,7 +1398,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
++nspecs_done;
/* Look for next format specifier. */
+#ifdef COMPILE_WPRINTF
+ f = find_spec ((end_of_spec = ++f));
+#else
f = find_spec ((end_of_spec = ++f), &mbstate);
+#endif
/* Write the following constant string. */
outstring (end_of_spec, f - end_of_spec);
@@ -1301,7 +1427,7 @@ do_positional:
attributes. */
size_t nargs = 0;
int *args_type;
- union printf_arg *args_value;
+ union printf_arg *args_value = NULL;
/* Positional parameters refer to arguments directly. This could
also determine the maximum number of arguments. Track the
@@ -1329,7 +1455,7 @@ do_positional:
grouping = NULL;
}
- for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)
+ for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
{
if (nspecs >= nspecs_max)
{
@@ -1356,8 +1482,12 @@ do_positional:
}
/* Parse the format specifier. */
+#ifdef COMPILE_WPRINTF
+ nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg);
+#else
nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg,
&mbstate);
+#endif
}
/* Determine the number of arguments the format string consumes. */
@@ -1449,7 +1579,7 @@ do_positional:
} number;
int base;
union printf_arg the_arg;
- char *string; /* Pointer to argument string. */
+ UCHAR_T *string; /* Pointer to argument string. */
/* Fill variables from values in struct. */
int alt = specs[nspecs_done].info.alt;
@@ -1498,8 +1628,10 @@ do_positional:
}
/* Maybe the buffer is too small. */
- if (MAX (prec, width) + 32 > sizeof (work_buffer))
- workend = alloca (MAX (prec, width) + 32) + (MAX (prec, width) + 31);
+ if (MAX (prec, width) + 32 > sizeof (work_buffer) / sizeof (UCHAR_T))
+ workend = ((UCHAR_T *) alloca ((MAX (prec, width) + 32)
+ * sizeof (UCHAR_T))
+ + (MAX (prec, width) + 31));
/* Process format specifiers. */
while (1)
@@ -1507,6 +1639,7 @@ do_positional:
JUMP (spec, step4_jumps);
process_arg ((&specs[nspecs_done]));
+ process_string_arg ((&specs[nspecs_done]));
LABEL (form_unknown):
{
@@ -1564,21 +1697,6 @@ all_done:
return done;
}
-
-#ifdef USE_IN_LIBIO
-# undef vfprintf
-# ifdef strong_alias
-/* This is for glibc. */
-strong_alias (_IO_vfprintf, vfprintf);
-# else
-# if defined __ELF__ || defined __GNU_LIBRARY__
-# include <gnu-stabs.h>
-# ifdef weak_alias
-weak_alias (_IO_vfprintf, vfprintf);
-# endif
-# endif
-# endif
-#endif
/* Handle an unknown format specifier. This prints out a canonicalized
representation of the format spec itself. */
@@ -1588,24 +1706,25 @@ printf_unknown (FILE *s, const struct printf_info *info,
{
int done = 0;
- char work_buffer[MAX (info->width, info->spec) + 32];
- char *const workend = &work_buffer[sizeof (work_buffer) - 1];
- register char *w;
+ CHAR_T work_buffer[MAX (info->width, info->spec) + 32];
+ CHAR_T *const workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)
+ - 1];
+ register CHAR_T *w;
- outchar ('%');
+ outchar (L_('%'));
if (info->alt)
- outchar ('#');
+ outchar (L_('#'));
if (info->group)
- outchar ('\'');
+ outchar (L_('\''));
if (info->showsign)
- outchar ('+');
+ outchar (L_('+'));
else if (info->space)
- outchar (' ');
+ outchar (L_(' '));
if (info->left)
- outchar ('-');
+ outchar (L_('-'));
if (info->pad == '0')
- outchar ('0');
+ outchar (L_('0'));
if (info->width != 0)
{
@@ -1622,7 +1741,7 @@ printf_unknown (FILE *s, const struct printf_info *info,
outchar (*w++);
}
- if (info->spec != '\0')
+ if (info->spec != L_('\0'))
outchar (info->spec);
all_done:
@@ -1631,13 +1750,13 @@ printf_unknown (FILE *s, const struct printf_info *info,
/* Group the digits according to the grouping rules of the current locale.
The interpretation of GROUPING is as in `struct lconv' from <locale.h>. */
-static char *
+static UCHAR_T *
internal_function
-group_number (CHAR_T *w, CHAR_T *rear_ptr, const CHAR_T *grouping,
+group_number (UCHAR_T *w, UCHAR_T *rear_ptr, const char *grouping,
wchar_t thousands_sep)
{
int len;
- char *src, *s;
+ UCHAR_T *src, *s;
/* We treat all negative values like CHAR_MAX. */
@@ -1648,8 +1767,9 @@ group_number (CHAR_T *w, CHAR_T *rear_ptr, const CHAR_T *grouping,
len = *grouping;
/* Copy existing string so that nothing gets overwritten. */
- src = (char *) alloca (rear_ptr - w);
- s = (char *) __mempcpy (src, w + 1, rear_ptr - w) - 1;
+ src = (UCHAR_T *) alloca ((rear_ptr - w) * sizeof (UCHAR_T));
+ s = (UCHAR_T *) __mempcpy (src, w + 1,
+ (rear_ptr - w) * sizeof (UCHAR_T)) - 1;
w = rear_ptr;
/* Process all characters in the string. */
@@ -1699,12 +1819,22 @@ static int
_IO_helper_overflow (_IO_FILE *s, int c)
{
_IO_FILE *target = ((struct helper_file*) s)->_put_stream;
+#ifdef COMPILE_WPRINTF
+ int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
+ if (used)
+ {
+ _IO_size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base,
+ used);
+ s->_wide_data->_IO_write_ptr -= written;
+ }
+#else
int used = s->_IO_write_ptr - s->_IO_write_base;
if (used)
{
_IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
s->_IO_write_ptr -= written;
}
+#endif
return PUTC (c, s);
}
@@ -1735,16 +1865,18 @@ internal_function
buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
_IO_va_list args)
{
- char buf[_IO_BUFSIZ];
+ CHAR_T buf[_IO_BUFSIZ];
struct helper_file helper;
register _IO_FILE *hp = (_IO_FILE *) &helper;
int result, to_flush;
/* Initialize helper. */
helper._put_stream = s;
- hp->_IO_write_base = buf;
- hp->_IO_write_ptr = buf;
- hp->_IO_write_end = buf + sizeof buf;
+#ifdef COMPILE_WPRINTF
+ _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
+#else
+ _IO_setp (hp, buf, buf + sizeof buf);
+#endif
hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
#if _IO_JUMPS_OFFSET
hp->_vtable_offset = 0;
@@ -1756,14 +1888,24 @@ buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
_IO_JUMPS (hp) = (struct _IO_jump_t *) &_IO_helper_jumps;
/* Now print to helper instead. */
- result = _IO_vfprintf (hp, format, args);
+ result = vfprintf (hp, format, args);
/* Now flush anything from the helper to the S. */
+#ifdef COMPILE_WPRINTF
+ if ((to_flush = (hp->_wide_data->_IO_write_ptr
+ - hp->_wide_data->_IO_write_base)) > 0)
+ {
+ if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
+ != to_flush)
+ return -1;
+ }
+#else
if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
{
if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
return -1;
}
+#endif
return result;
}
@@ -1826,3 +1968,26 @@ __wprintf_pad (FILE *s, wchar_t pad, size_t count)
}
#undef PADSIZE
#endif /* USE_IN_LIBIO */
+
+#ifdef USE_IN_LIBIO
+# undef vfprintf
+# ifdef strong_alias
+/* This is for glibc. */
+# ifdef COMPILE_WPRINTF
+strong_alias (_IO_vfwprintf, vfwprintf);
+# else
+strong_alias (_IO_vfprintf, vfprintf);
+# endif
+# else
+# if defined __ELF__ || defined __GNU_LIBRARY__
+# include <gnu-stabs.h>
+# ifdef weak_alias
+# ifdef COMPILE_WPRINTF
+weak_alias (_IO_vfwprintf, vfwprintf);
+# else
+weak_alias (_IO_vfprintf, vfprintf);
+# endif
+# endif
+# endif
+# endif
+#endif
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 0339edbeca..5caf616be3 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -16,6 +16,7 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
@@ -69,13 +70,56 @@
# undef va_list
# define va_list _IO_va_list
-# define ungetc(c, s) ((void) ((int) c == EOF \
+
+# ifdef COMPILE_WPRINTF
+# define ungetc(c, s) ((void) ((int) c == WEOF \
+ || (--read_in, \
+ _IO_sputbackwc (s, (unsigned char) c))))
+# define inchar() (c == EOF ? EOF \
+ : ((c = _IO_getwc_unlocked (s)), \
+ (void) (c != EOF && ++read_in), c))
+
+# define MEMCPY(d, s, n) wmemcpy (d, s, n)
+# define ISSPACE(Ch) iswspace (Ch)
+# define ISDIGIT(Ch) iswdigit (Ch)
+# define ISXDIGIT(Ch) iswxdigit (Ch)
+# define UNGETC(Ch, S) ungetwc (Ch, S)
+# define TOLOWER(Ch) towlower (Ch)
+# define ORIENT if (_IO_fwide (s, 1) != 1) return EOF
+# define __strtoll_internal __wcstoll_internal
+# define __strtoull_internal __wcstoull_internal
+# define __strtol_internal __wcstol_internal
+# define __strtoul_internal __wcstoul_internal
+# define __strtold_internal __wcstold_internal
+# define __strtod_internal __wcstod_internal
+# define __strtof_internal __wcstof_internal
+
+# define L_(Str) L##Str
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# define WINT_T wint_t
+# else
+# define ungetc(c, s) ((void) ((int) c == EOF \
|| (--read_in, \
_IO_sputbackc (s, (unsigned char) c))))
-# define inchar() (c == EOF ? EOF \
+# define inchar() (c == EOF ? EOF \
: ((c = _IO_getc_unlocked (s)), \
(void) (c != EOF && ++read_in), c))
-# define encode_error() do { \
+# define MEMCPY(d, s, n) memcpy (d, s, n)
+# define ISSPACE(Ch) isspace (Ch)
+# define ISDIGIT(Ch) isdigit (Ch)
+# define ISXDIGIT(Ch) isxdigit (Ch)
+# define UNGETC(Ch, S) ungetc (Ch, S)
+# define TOLOWER(Ch) tolower (Ch)
+# define ORIENT if (_IO_fwide (s, -1) != -1) return EOF
+
+# define L_(Str) Str
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define WINT_T int
+# endif
+
+# define encode_error() do { \
if (errp != NULL) *errp |= 4; \
_IO_funlockfile (s); \
__libc_cleanup_end (0); \
@@ -94,7 +138,7 @@
__libc_cleanup_end (0); \
return done ?: EOF; \
} while (0)
-# define memory_error() do { \
+# define memory_error() do { \
_IO_funlockfile (s); \
__set_errno (ENOMEM); \
__libc_cleanup_end (0); \
@@ -180,30 +224,39 @@
FORMAT, using the argument list in ARG.
Return the number of assignments made, or -1 for an input error. */
#ifdef USE_IN_LIBIO
+# ifdef COMPILE_WPRINTF
+int
+_IO_vfwscanf (s, format, argptr, errp)
+ _IO_FILE *s;
+ const wchar_t *format;
+ _IO_va_list argptr;
+ int *errp;
+# else
int
_IO_vfscanf (s, format, argptr, errp)
_IO_FILE *s;
const char *format;
_IO_va_list argptr;
int *errp;
+# endif
#else
int
__vfscanf (FILE *s, const char *format, va_list argptr)
#endif
{
va_list arg;
- register const char *f = format;
- register unsigned char fc; /* Current character of the format. */
+ register const CHAR_T *f = format;
+ register UCHAR_T fc; /* Current character of the format. */
register size_t done = 0; /* Assignments done. */
register size_t read_in = 0; /* Chars read in. */
- register int c = 0; /* Last char read. */
+ register WINT_T c = 0; /* Last char read. */
register int width; /* Maximum field width. */
register int flags; /* Modifiers for current format element. */
/* Status for reading F-P nums. */
char got_dot, got_e, negative;
/* If a [...] is a [^...]. */
- char not_in;
+ CHAR_T not_in;
#define exp_char not_in
/* Base for integral numbers. */
int base;
@@ -236,8 +289,8 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
/* Nonzero if we are reading a pointer. */
int read_pointer;
/* Workspace. */
- char *tw; /* Temporary pointer. */
- char *wp = NULL; /* Workspace. */
+ CHAR_T *tw; /* Temporary pointer. */
+ CHAR_T *wp = NULL; /* Workspace. */
size_t wpmax = 0; /* Maximal size of workspace. */
size_t wpsize; /* Currently used bytes in workspace. */
#define ADDW(Ch) \
@@ -245,11 +298,11 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
{ \
if (wpsize == wpmax) \
{ \
- char *old = wp; \
+ CHAR_T *old = wp; \
wpmax = UCHAR_MAX > 2 * wpmax ? UCHAR_MAX : 2 * wpmax; \
- wp = (char *) alloca (wpmax); \
+ wp = (CHAR_T *) alloca (wpmax * sizeof (wchar_t)); \
if (old != NULL) \
- memcpy (wp, old, wpsize); \
+ MEMCPY (wp, old, wpsize); \
} \
wp[wpsize++] = (Ch); \
} \
@@ -261,6 +314,10 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
arg = (va_list) argptr;
#endif
+#ifdef ORIENT
+ ORIENT;
+#endif
+
ARGCHECK (s, format);
/* Figure out the decimal point character. */
@@ -280,8 +337,10 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
LOCK_STREAM (s);
+#ifndef COMPILE_WPRINTF
/* From now on we use `state' to convert the format string. */
memset (&state, '\0', sizeof (state));
+#endif
/* Run through the format string. */
while (*f != '\0')
@@ -320,6 +379,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
# endif
#endif
+#ifndef COMPILE_WPRINTF
if (!isascii (*f))
{
/* Non-ASCII, may be a multibyte. */
@@ -341,12 +401,13 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
continue;
}
}
+#endif
fc = *f++;
if (fc != '%')
{
/* Remember to skip spaces. */
- if (isspace (fc))
+ if (ISSPACE (fc))
{
skip_space = 1;
continue;
@@ -363,7 +424,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
string. Now it's time to skip all leading white space. */
if (skip_space)
{
- while (isspace (c))
+ while (ISSPACE (c))
if (inchar () == EOF && errno == EINTR)
conv_error ();
skip_space = 0;
@@ -371,7 +432,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
if (c != fc)
{
- ungetc (c, s);
+ UNGETC (c, s);
conv_error ();
}
@@ -391,12 +452,12 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
wpsize = 0;
/* Check for a positional parameter specification. */
- if (isdigit (*f))
+ if (ISDIGIT (*f))
{
- argpos = *f++ - '0';
- while (isdigit (*f))
- argpos = argpos * 10 + (*f++ - '0');
- if (*f == '$')
+ argpos = *f++ - L_('0');
+ while (ISDIGIT (*f))
+ argpos = argpos * 10 + (*f++ - L_('0'));
+ if (*f == L_('$'))
++f;
else
{
@@ -409,27 +470,27 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
/* Check for the assignment-suppressing and the number grouping flag. */
- while (*f == '*' || *f == '\'')
+ while (*f == L_('*') || *f == L_('\''))
switch (*f++)
{
- case '*':
+ case L_('*'):
flags |= SUPPRESS;
break;
- case '\'':
+ case L_('\''):
flags |= GROUP;
break;
}
/* We have seen width. */
- if (isdigit (*f))
+ if (ISDIGIT (*f))
flags |= WIDTH;
/* Find the maximum field width. */
width = 0;
- while (isdigit (*f))
+ while (ISDIGIT (*f))
{
width *= 10;
- width += *f++ - '0';
+ width += *f++ - L_('0');
}
got_width:
if (width == 0)
@@ -438,9 +499,9 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
/* Check for type modifiers. */
switch (*f++)
{
- case 'h':
+ case L_('h'):
/* ints are short ints or chars. */
- if (*f == 'h')
+ if (*f == L_('h'))
{
++f;
flags |= CHAR;
@@ -448,8 +509,8 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
else
flags |= SHORT;
break;
- case 'l':
- if (*f == 'l')
+ case L_('l'):
+ if (*f == L_('l'))
{
/* A double `l' is equivalent to an `L'. */
++f;
@@ -459,15 +520,15 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
/* ints are long ints. */
flags |= LONG;
break;
- case 'q':
- case 'L':
+ case L_('q'):
+ case L_('L'):
/* doubles are long doubles, and ints are long long ints. */
flags |= LONGDBL | LONG;
break;
- case 'a':
+ case L_('a'):
/* The `a' is used as a flag only if followed by `s', `S' or
`['. */
- if (*f != 's' && *f != 'S' && *f != '[')
+ if (*f != L_('s') && *f != L_('S') && *f != L_('['))
{
--f;
break;
@@ -476,19 +537,19 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
arg and fill it in with a malloc'd pointer. */
flags |= MALLOC;
break;
- case 'z':
+ case L_('z'):
if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))
flags |= LONGDBL;
else if (sizeof (size_t) > sizeof (unsigned int))
flags |= LONG;
break;
- case 'j':
+ case L_('j'):
if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))
flags |= LONGDBL;
else if (sizeof (uintmax_t) > sizeof (unsigned int))
flags |= LONG;
break;
- case 't':
+ case L_('t'):
if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))
flags |= LONGDBL;
else if (sizeof (ptrdiff_t) > sizeof (int))
@@ -501,12 +562,13 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
/* End of the format string? */
- if (*f == '\0')
+ if (*f == L_('\0'))
conv_error ();
/* Find the conversion specifier. */
fc = *f++;
- if (skip_space || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
+ if (skip_space || (fc != L_('[') && fc != L_('c')
+ && fc != L_('C') && fc != L_('n')))
{
/* Eat whitespace. */
int save_errno = errno;
@@ -514,15 +576,15 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
do
if (inchar () == EOF && errno == EINTR)
input_error ();
- while (isspace (c));
+ while (ISSPACE (c));
errno = save_errno;
- ungetc (c, s);
+ UNGETC (c, s);
skip_space = 0;
}
switch (fc)
{
- case '%': /* Must match a literal '%'. */
+ case L_('%'): /* Must match a literal '%'. */
c = inchar ();
if (c == EOF)
input_error ();
@@ -533,7 +595,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
break;
- case 'n': /* Answer number of assignments done. */
+ case L_('n'): /* Answer number of assignments done. */
/* Corrigendum 1 to ISO C 1990 describes the allowed flags
with the 'n' conversion specifier. */
if (!(flags & SUPPRESS))
@@ -581,7 +643,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
break;
- case 'c': /* Match characters. */
+ case L_('c'): /* Match characters. */
if ((flags & LONG) == 0)
{
if (!(flags & SUPPRESS))
@@ -598,6 +660,26 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
if (width == -1)
width = 1;
+#ifdef COMPILE_WPRINTF
+ /* We have to convert the wide character(s) into multibyte
+ characters and store the result. */
+ memset (&state, '\0', sizeof (state));
+
+ do
+ {
+ size_t n;
+
+ n = wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
+ if (n == (size_t) -1)
+ /* No valid wide character. */
+ input_error ();
+
+ /* Increment the output pointer. Even if we don't
+ write anything. */
+ str += n;
+ }
+ while (--width > 0 && inchar () != EOF);
+#else
if (!(flags & SUPPRESS))
{
do
@@ -606,6 +688,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
else
while (--width > 0 && inchar () != EOF);
+#endif
if (!(flags & SUPPRESS))
++done;
@@ -613,238 +696,448 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
break;
}
/* FALLTHROUGH */
- case 'C':
- /* Get UTF-8 encoded wide character. Here we assume (as in
- other parts of the libc) that we only have to handle
- UTF-8. */
+ case L_('C'):
+ if (!(flags & SUPPRESS))
+ {
+ wstr = ARG (wchar_t *);
+ if (str == NULL)
+ conv_error ();
+ }
+
+ c = inchar ();
+ if (c == EOF)
+ input_error ();
+
+#ifdef COMPILE_WPRINTF
+ /* Just store the incoming wide characters. */
+ if (!(flags & SUPPRESS))
+ {
+ do
+ *wstr++ = c;
+ while (--width > 0 && inchar () != EOF);
+ }
+ else
+ while (--width > 0 && inchar () != EOF);
+#else
{
- wint_t val;
- size_t cnt = 0;
- int first = 1;
+ /* We have to convert the multibyte input sequence to wide
+ characters. */
+ char buf[MB_LEN_MAX];
+ mbstate_t cstate;
- if (!(flags & SUPPRESS))
- {
- wstr = ARG (wchar_t *);
- if (str == NULL)
- conv_error ();
- }
+ memset (&cstate, '\0', sizeof (cstate));
do
{
-#define NEXT_WIDE_CHAR(First) \
- c = inchar (); \
- if (c == EOF) \
- { \
- /* EOF is only an error for the first character. */ \
- if (First) \
- input_error (); \
- else \
- break; \
- } \
- val = c; \
- if (val >= 0x80) \
- { \
- if ((c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
- encode_error (); \
- if ((c & 0xe0) == 0xc0) \
- { \
- /* We expect two bytes. */ \
- cnt = 1; \
- val &= 0x1f; \
- } \
- else if ((c & 0xf0) == 0xe0) \
- { \
- /* We expect three bytes. */ \
- cnt = 2; \
- val &= 0x0f; \
- } \
- else if ((c & 0xf8) == 0xf0) \
- { \
- /* We expect four bytes. */ \
- cnt = 3; \
- val &= 0x07; \
- } \
- else if ((c & 0xfc) == 0xf8) \
- { \
- /* We expect five bytes. */ \
- cnt = 4; \
- val &= 0x03; \
- } \
- else \
- { \
- /* We expect six bytes. */ \
- cnt = 5; \
- val &= 0x01; \
- } \
- \
- do \
- { \
- c = inchar (); \
- if (c == EOF \
- || (c & 0xc0) == 0x80 || (c & 0xfe) == 0xfe) \
- encode_error (); \
- val <<= 6; \
- val |= c & 0x3f; \
- } \
- while (--cnt > 0); \
- } \
- \
- if (!(flags & SUPPRESS)) \
- *wstr++ = val; \
- First = 0
-
- NEXT_WIDE_CHAR (first);
- }
- while (--width > 0);
+ size_t cnt;
- if (!(flags & SUPPRESS))
- ++done;
+ /* This is what we present the mbrtowc function first. */
+ buf[0] = c;
+ cnt = 1;
+
+ while (1)
+ {
+ size_t n;
+
+ n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
+ buf, cnt, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ /* Possibly correct character, just not enough
+ input. */
+ assert (cnt < MB_CUR_MAX);
+
+ if (inchar () == EOF)
+ encode_error ();
+
+ buf[cnt++] = c;
+ continue;
+ }
+
+ if (n != cnt)
+ encode_error ();
+
+ /* We have a match. */
+ break;
+ }
+
+ /* Advance the result pointer. */
+ ++wstr;
+ }
+ while (--width > 0 && inchar () != EOF);
}
- break;
+#endif
- case 's': /* Read a string. */
- if (flags & LONG)
- /* We have to process a wide character string. */
- goto wide_char_string;
+ if (!(flags & SUPPRESS))
+ ++done;
+ break;
+
+ case L_('s'): /* Read a string. */
+ if (!(flags & LONG))
+ {
#define STRING_ARG(Str, Type) \
- if (!(flags & SUPPRESS)) \
- { \
- if (flags & MALLOC) \
+ do if (!(flags & SUPPRESS)) \
{ \
- /* The string is to be stored in a malloc'd buffer. */ \
- strptr = ARG (char **); \
- if (strptr == NULL) \
+ if (flags & MALLOC) \
+ { \
+ /* The string is to be stored in a malloc'd buffer. */ \
+ strptr = ARG (char **); \
+ if (strptr == NULL) \
+ conv_error (); \
+ /* Allocate an initial buffer. */ \
+ strsize = 100; \
+ *strptr = (char *) malloc (strsize * sizeof (Type)); \
+ Str = (Type *) *strptr; \
+ } \
+ else \
+ Str = ARG (Type *); \
+ if (Str == NULL) \
conv_error (); \
- /* Allocate an initial buffer. */ \
- strsize = 100; \
- *strptr = malloc (strsize * sizeof (Type)); \
- Str = (Type *) *strptr; \
- } \
- else \
- Str = ARG (Type *); \
- if (Str == NULL) \
- conv_error (); \
- }
- STRING_ARG (str, char);
+ } while (0)
+ STRING_ARG (str, char);
- c = inchar ();
- if (c == EOF)
- input_error ();
+ c = inchar ();
+ if (c == EOF)
+ input_error ();
- do
- {
- if (isspace (c))
+#ifdef COMPILE_WPRINTF
+ memset (&state, '\0', sizeof (state));
+#endif
+
+ do
{
- ungetc (c, s);
- break;
- }
-#define STRING_ADD_CHAR(Str, c, Type) \
- if (!(flags & SUPPRESS)) \
- { \
- *Str++ = c; \
- if ((flags & MALLOC) && (char *) Str == *strptr + strsize) \
- { \
- /* Enlarge the buffer. */ \
- Str = realloc (*strptr, strsize * 2 * sizeof (Type)); \
- if (Str == NULL) \
- { \
- /* Can't allocate that much. Last-ditch effort. */\
- Str = realloc (*strptr, \
- (strsize + 1) * sizeof (Type)); \
- if (Str == NULL) \
- { \
- /* We lose. Oh well. \
- Terminate the string and stop converting, \
- so at least we don't skip any input. */ \
- ((Type *) (*strptr))[strsize] = '\0'; \
- ++done; \
- conv_error (); \
- } \
- else \
- { \
- *strptr = (char *) Str; \
- Str = ((Type *) *strptr) + strsize; \
- ++strsize; \
- } \
- } \
- else \
- { \
- *strptr = (char *) Str; \
- Str = ((Type *) *strptr) + strsize; \
- strsize *= 2; \
- } \
- } \
+ if (ISSPACE (c))
+ {
+ UNGETC (c, s);
+ break;
+ }
+
+#ifdef COMPILE_WPRINTF
+ /* This is quite complicated. We have to convert the
+ wide characters into multibyte characters and then
+ store them. */
+ {
+ size_t n;
+
+ if (!(flags & SUPPRESS) && (flags & MALLOC)
+ && str + MB_CUR_MAX >= *strptr + strsize)
+ {
+ /* We have to enlarge the buffer if the `a' flag
+ was given. */
+ str = (char *) realloc (*strptr, strsize * 2);
+ if (str == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ str = (char *) realloc (*strptr, strsize + 1);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the
+ string and stop converting,
+ so at least we don't skip any input. */
+ ((char *) (*strptr))[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ strsize *= 2;
+ }
+ }
+
+ n = wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
+ if (n == (size_t) -1)
+ encode_error ();
+
+ assert (n <= MB_CUR_MAX);
+ str += n;
+ }
+#else
+ /* This is easy. */
+ if (!(flags & SUPPRESS))
+ {
+ *str++ = c;
+ if ((flags & MALLOC)
+ && (char *) str == *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ str = (char *) realloc (*strptr, 2 * strsize);
+ if (str == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ str = (char *) realloc (*strptr, strsize + 1);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the
+ string and stop converting,
+ so at least we don't skip any input. */
+ ((char *) (*strptr))[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ strsize *= 2;
+ }
+ }
+ }
+#endif
}
- STRING_ADD_CHAR (str, c, char);
- } while ((width <= 0 || --width > 0) && inchar () != EOF);
+ while ((width <= 0 || --width > 0) && inchar () != EOF);
- if (!(flags & SUPPRESS))
- {
- *str = '\0';
- ++done;
+ if (!(flags & SUPPRESS))
+ {
+#ifdef COMPILE_WPRINTF
+ /* We have to emit the code to get into the intial
+ state. */
+ char buf[MB_LEN_MAX];
+ size_t n = wcrtomb (buf, L'\0', &state);
+ if (n > 0 && (flags & MALLOC)
+ && str + n >= *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ str = (char *) realloc (*strptr,
+ (str + n + 1) - *strptr);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the string
+ and stop converting, so at least we don't
+ skip any input. */
+ ((char *) (*strptr))[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str = ((char *) *strptr) + strsize;
+ strsize = (str + n + 1) - *strptr;
+ }
+ }
+
+ str = __mempcpy (str, buf, n);
+#endif
+ *str = '\0';
+
+ if ((flags & MALLOC) && str - *strptr != strsize)
+ {
+ char *cp = (char *) realloc (*strptr, str - *strptr);
+ if (cp != NULL)
+ *strptr = cp;
+ }
+
+ ++done;
+ }
+ break;
}
- break;
+ /* FALLTHROUGH */
- case 'S':
- /* Wide character string. */
- wide_char_string:
+ case L_('S'):
{
- wint_t val;
- int first = 1;
+#ifndef COMPILE_WPRINTF
+ mbstate_t cstate;
+#endif
+
+ /* Wide character string. */
STRING_ARG (wstr, wchar_t);
+ c = inchar ();
+ if (c == EOF)
+ input_error ();
+
+#ifndef COMPILE_WPRINTF
+ memset (&cstate, '\0', sizeof (cstate));
+#endif
+
do
{
- size_t cnt = 0;
- NEXT_WIDE_CHAR (first);
-
- if (__iswspace (val))
+ if (ISSPACE (c))
{
- /* XXX We would have to push back the whole wide char
- with possibly many bytes. But since scanf does
- not make a difference for white space characters
- we can simply push back a simple <SP> which is
- guaranteed to be in the [:space:] class. */
- ungetc (' ', s);
+ UNGETC (c, s);
break;
}
- STRING_ADD_CHAR (wstr, val, wchar_t);
- first = 0;
+#ifdef COMPILE_WPRINTF
+ /* This is easy. */
+ if (!(flags & SUPPRESS))
+ {
+ *wstr++ = c;
+ if ((flags & MALLOC)
+ && wstr == (wchar_t *) *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ wstr = (wchar_t *) realloc (*strptr,
+ (2 * strsize)
+ * sizeof (wchar_t));
+ if (wstr == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ wstr = (wchar_t *) realloc (*strptr,
+ (strsize
+ + sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* We lose. Oh well. Terminate the string
+ and stop converting, so at least we don't
+ skip any input. */
+ ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ strsize *= 2;
+ }
+ }
+ }
+#else
+ {
+ char buf[MB_LEN_MAX];
+ size_t cnt;
+
+ buf[0] = c;
+ cnt = 1;
+
+ while (1)
+ {
+ size_t n;
+
+ n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL,
+ buf, cnt, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ /* Possibly correct character, just not enough
+ input. */
+ assert (cnt < MB_CUR_MAX);
+
+ if (inchar () == EOF)
+ encode_error ();
+
+ buf[cnt++] = c;
+ continue;
+ }
+
+ if (n != cnt)
+ encode_error ();
+
+ /* We have a match. */
+ break;
+ }
+
+ if (!(flags & SUPPRESS) && (flags & MALLOC)
+ && wstr == (wchar_t *) *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ wstr = (wchar_t *) realloc (*strptr,
+ (2 * strsize
+ * sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* Can't allocate that much. Last-ditch effort. */
+ wstr = (wchar_t *) realloc (*strptr,
+ ((strsize + 1)
+ * sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* We lose. Oh well. Terminate the
+ string and stop converting, so at
+ least we don't skip any input. */
+ ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ strsize *= 2;
+ }
+ }
+ }
+#endif
}
- while (width <= 0 || --width > 0);
+ while ((width <= 0 || --width > 0) && inchar () != EOF);
if (!(flags & SUPPRESS))
{
- *wstr = L'\0';
+ *wstr++ = L'\0';
+
+ if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
+ {
+ wchar_t *cp = (wchar_t *) realloc (*strptr,
+ ((wstr
+ - (wchar_t *) *strptr)
+ * sizeof(wchar_t)));
+ if (cp != NULL)
+ *strptr = (char *) cp;
+ }
+
++done;
}
}
break;
- case 'x': /* Hexadecimal integer. */
- case 'X': /* Ditto. */
+ case L_('x'): /* Hexadecimal integer. */
+ case L_('X'): /* Ditto. */
base = 16;
number_signed = 0;
goto number;
- case 'o': /* Octal integer. */
+ case L_('o'): /* Octal integer. */
base = 8;
number_signed = 0;
goto number;
- case 'u': /* Unsigned decimal integer. */
+ case L_('u'): /* Unsigned decimal integer. */
base = 10;
number_signed = 0;
goto number;
- case 'd': /* Signed decimal integer. */
+ case L_('d'): /* Signed decimal integer. */
base = 10;
number_signed = 1;
goto number;
- case 'i': /* Generic number. */
+ case L_('i'): /* Generic number. */
base = 0;
number_signed = 1;
@@ -854,7 +1147,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
input_error ();
/* Check for a sign. */
- if (c == '-' || c == '+')
+ if (c == L_('-') || c == L_('+'))
{
ADDW (c);
if (width > 0)
@@ -863,7 +1156,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
/* Look for a leading indication of base. */
- if (width != 0 && c == '0')
+ if (width != 0 && c == L_('0'))
{
if (width > 0)
--width;
@@ -871,7 +1164,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
ADDW (c);
c = inchar ();
- if (width != 0 && _tolower (c) == 'x')
+ if (width != 0 && TOLOWER (c) == L_('x'))
{
if (base == 0)
base = 16;
@@ -892,8 +1185,8 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
/* Read the number into workspace. */
while (c != EOF && width != 0)
{
- if (base == 16 ? !isxdigit (c) :
- ((!isdigit (c) || c - '0' >= base) &&
+ if (base == 16 ? !ISXDIGIT (c) :
+ ((!ISDIGIT (c) || c - L_('0') >= base) &&
!((flags & GROUP) && base == 10 && c == thousands)))
break;
ADDW (c);
@@ -904,34 +1197,34 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
if (wpsize == 0 ||
- (wpsize == 1 && (wp[0] == '+' || wp[0] == '-')))
+ (wpsize == 1 && (wp[0] == L_('+') || wp[0] == L_('-'))))
{
/* There was no number. If we are supposed to read a pointer
we must recognize "(nil)" as well. */
if (wpsize == 0 && read_pointer && (width < 0 || width >= 0)
&& c == '('
- && _tolower (inchar ()) == 'n'
- && _tolower (inchar ()) == 'i'
- && _tolower (inchar ()) == 'l'
- && inchar () == ')')
+ && TOLOWER (inchar ()) == L_('n')
+ && TOLOWER (inchar ()) == L_('i')
+ && TOLOWER (inchar ()) == L_('l')
+ && inchar () == L_(')'))
/* We must produce the value of a NULL pointer. A single
'0' digit is enough. */
- ADDW ('0');
+ ADDW (L_('0'));
else
{
/* The last read character is not part of the number
anymore. */
- ungetc (c, s);
+ UNGETC (c, s);
conv_error ();
}
}
else
/* The just read character is not part of the number anymore. */
- ungetc (c, s);
+ UNGETC (c, s);
/* Convert the number. */
- ADDW ('\0');
+ ADDW (L_('\0'));
if (need_longlong && (flags & LONGDBL))
{
if (number_signed)
@@ -982,28 +1275,28 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
break;
- case 'e': /* Floating-point numbers. */
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
+ case L_('e'): /* Floating-point numbers. */
+ case L_('E'):
+ case L_('f'):
+ case L_('g'):
+ case L_('G'):
+ case L_('a'):
+ case L_('A'):
c = inchar ();
if (c == EOF)
input_error ();
/* Check for a sign. */
- if (c == '-' || c == '+')
+ if (c == L_('-') || c == L_('+'))
{
- negative = c == '-';
+ negative = c == L_('-');
if (inchar () == EOF)
/* EOF is only an input error before we read any chars. */
conv_error ();
- if (! isdigit (c) && c != decimal)
+ if (! ISDIGIT (c) && c != decimal)
{
/* This is no valid number. */
- ungetc (c, s);
+ UNGETC (c, s);
input_error ();
}
if (width > 0)
@@ -1013,69 +1306,69 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
negative = 0;
/* Take care for the special arguments "nan" and "inf". */
- if (_tolower (c) == 'n')
+ if (TOLOWER (c) == L_('n'))
{
/* Maybe "nan". */
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'a')
+ if (inchar () == EOF || TOLOWER (c) != L_('a'))
input_error ();
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'n')
+ if (inchar () == EOF || TOLOWER (c) != L_('n'))
input_error ();
ADDW (c);
/* It is "nan". */
goto scan_float;
}
- else if (_tolower (c) == 'i')
+ else if (TOLOWER (c) == L_('i'))
{
/* Maybe "inf" or "infinity". */
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'n')
+ if (inchar () == EOF || TOLOWER (c) != L_('n'))
input_error ();
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'f')
+ if (inchar () == EOF || TOLOWER (c) != L_('f'))
input_error ();
ADDW (c);
/* It is as least "inf". */
if (inchar () != EOF)
{
- if (_tolower (c) == 'i')
+ if (TOLOWER (c) == L_('i'))
{
/* Now we have to read the rest as well. */
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'n')
+ if (inchar () == EOF || TOLOWER (c) != L_('n'))
input_error ();
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'i')
+ if (inchar () == EOF || TOLOWER (c) != L_('i'))
input_error ();
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 't')
+ if (inchar () == EOF || TOLOWER (c) != L_('t'))
input_error ();
ADDW (c);
- if (inchar () == EOF || _tolower (c) != 'y')
+ if (inchar () == EOF || TOLOWER (c) != L_('y'))
input_error ();
ADDW (c);
}
else
/* Never mind. */
- ungetc (c, s);
+ UNGETC (c, s);
}
goto scan_float;
}
is_hexa = 0;
- exp_char = 'e';
- if (c == '0')
+ exp_char = L_('e');
+ if (c == L_('0'))
{
ADDW (c);
c = inchar ();
- if (_tolower (c) == 'x')
+ if (TOLOWER (c) == L_('x'))
{
/* It is a number in hexadecimal format. */
ADDW (c);
is_hexa = 1;
- exp_char = 'p';
+ exp_char = L_('p');
/* Grouping is not allowed. */
flags &= ~GROUP;
@@ -1086,14 +1379,14 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
got_dot = got_e = 0;
do
{
- if (isdigit (c))
+ if (ISDIGIT (c))
ADDW (c);
- else if (!got_e && is_hexa && isxdigit (c))
+ else if (!got_e && is_hexa && ISXDIGIT (c))
ADDW (c);
else if (got_e && wp[wpsize - 1] == exp_char
- && (c == '-' || c == '+'))
+ && (c == L_('-') || c == L_('+')))
ADDW (c);
- else if (wpsize > 0 && !got_e && _tolower (c) == exp_char)
+ else if (wpsize > 0 && !got_e && TOLOWER (c) == exp_char)
{
ADDW (exp_char);
got_e = got_dot = 1;
@@ -1109,7 +1402,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
{
/* The last read character is not part of the number
anymore. */
- ungetc (c, s);
+ UNGETC (c, s);
break;
}
if (width > 0)
@@ -1125,7 +1418,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
scan_float:
/* Convert the number. */
- ADDW ('\0');
+ ADDW (L_('\0'));
if (flags & LONGDBL)
{
long double d = __strtold_internal (wp, &tw, flags & GROUP);
@@ -1152,22 +1445,13 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
++done;
break;
- case '[': /* Character class. */
+ case L_('['): /* Character class. */
if (flags & LONG)
- {
- STRING_ARG (wstr, wchar_t);
- c = '\0'; /* This is to keep gcc quiet. */
- }
+ STRING_ARG (wstr, wchar_t);
else
- {
- STRING_ARG (str, char);
+ STRING_ARG (str, char);
- c = inchar ();
- if (c == EOF)
- input_error ();
- }
-
- if (*f == '^')
+ if (*f == L_('^'))
{
++f;
not_in = 1;
@@ -1175,6 +1459,29 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
else
not_in = 0;
+ if (width < 0)
+ /* There is no width given so there is also no limit on the
+ number of characters we read. Therefore we set width to
+ a very high value to make the algorithm easier. */
+ width = INT_MAX;
+
+#ifdef COMPILE_WPRINTF
+ /* Find the beginning and the end of the scanlist. We are not
+ creating a lookup table since it would have to be too large.
+ Instead we search each time through the string. This is not
+ a constant lookup time but who uses this feature deserves to
+ be punished. */
+ tw = (wchar_t *) f; /* Marks the beginning. */
+
+ if (*f == ']' || *f == '-')
+ ++f;
+
+ while ((fc = *f++) != L'\0' && fc != L']');
+
+ if (fc == L'\0')
+ conv_error ();
+ wp = (wchar_t *) f - 1;
+#else
/* Fill WP with byte flags indexed by character.
We will use this flag map for matching input characters. */
if (wpmax < UCHAR_MAX)
@@ -1182,7 +1489,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
wpmax = UCHAR_MAX;
wp = (char *) alloca (wpmax);
}
- memset (wp, 0, UCHAR_MAX);
+ memset (wp, '\0', UCHAR_MAX);
fc = *f;
if (fc == ']' || fc == '-')
@@ -1194,85 +1501,433 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
++f;
}
+ tw = (char *) f;
while ((fc = *f++) != '\0' && fc != ']')
- {
- if (fc == '-' && *f != '\0' && *f != ']' &&
- (unsigned char) f[-2] <= (unsigned char) *f)
- {
- /* Add all characters from the one before the '-'
- up to (but not including) the next format char. */
- for (fc = f[-2]; fc < *f; ++fc)
- wp[fc] = 1;
- }
- else
- /* Add the character to the flag map. */
- wp[fc] = 1;
- }
+ if (fc == '-' && *f != '\0' && *f != ']' && f - 2 != tw
+ && (unsigned char) f[-2] <= (unsigned char) *f)
+ {
+ /* Add all characters from the one before the '-'
+ up to (but not including) the next format char. */
+ for (fc = f[-2]; fc < *f; ++fc)
+ wp[fc] = 1;
+ }
+ else
+ /* Add the character to the flag map. */
+ wp[fc] = 1;
+
if (fc == '\0')
- {
- if (!(flags & LONG))
- ungetc (c, s);
- conv_error();
- }
+ conv_error();
+#endif
if (flags & LONG)
{
- wint_t val;
- int first = 1;
+ size_t now = read_in;
+#ifdef COMPILE_WPRINTF
+ do
+ {
+ wchar_t *runp;
+
+ if (inchar () == WEOF)
+ break;
+
+ /* Test whether it's in the scanlist. */
+ runp = tw;
+ while (runp < wp)
+ {
+ if (runp[0] == L'-' && runp[1] != '\0' && runp[1] != ']'
+ && runp != tw
+ && (unsigned int) runp[-1] <= (unsigned int) runp[1])
+ {
+ /* Match against all characters in between the
+ first and last character of the sequence. */
+ wchar_t wc;
+
+ for (wc = runp[-1] + 1; wc < runp[1]; ++wc)
+ if (wc == c)
+ break;
+
+ if (wc == runp[1] && !not_in)
+ break;
+ if (wc == runp[1] && not_in)
+ {
+ /* The current character is not in the
+ scanset. */
+ ungetwc (c, s);
+ goto out;
+ }
+ }
+ else
+ {
+ if (*runp == runp[1] && !not_in)
+ break;
+ if (*runp != runp[1] && not_in)
+ {
+ ungetwc (c ,s);
+ goto out;
+ }
+ }
+
+ ++runp;
+ }
+
+ if (!(flags & SUPPRESS))
+ {
+ *wstr++ = c;
+
+ if ((flags & MALLOC)
+ && wstr == (wchar_t *) *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ wstr = (wchar_t *) realloc (*strptr,
+ (2 * strsize)
+ * sizeof (wchar_t));
+ if (wstr == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ wstr = (wchar_t *)
+ realloc (*strptr, (strsize
+ + sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* We lose. Oh well. Terminate the string
+ and stop converting, so at least we don't
+ skip any input. */
+ ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ strsize *= 2;
+ }
+ }
+ }
+ }
+ while (--width > 0);
+ out:
+#else
+ char buf[MB_LEN_MAX];
+ size_t cnt = 0;
+ mbstate_t cstate;
+
+ memset (&cstate, '\0', sizeof (cstate));
do
{
- size_t cnt = 0;
- NEXT_WIDE_CHAR (first);
- if (val <= 255 && wp[val] == not_in)
+ again:
+ if (inchar () == EOF)
+ break;
+
+ if (wp[c] == not_in)
{
- ungetc (val, s);
+ ungetc (c, s);
break;
}
- STRING_ADD_CHAR (wstr, val, wchar_t);
- if (width > 0)
- --width;
- first = 0;
+
+ /* This is easy. */
+ if (!(flags & SUPPRESS))
+ {
+ size_t n;
+
+ /* Convert it into a wide character. */
+ n = __mbrtowc (wstr, buf, cnt, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ /* Possibly correct character, just not enough
+ input. */
+ assert (cnt < MB_CUR_MAX);
+ goto again;
+ }
+
+ if (n != cnt)
+ encode_error ();
+
+ ++wstr;
+ if ((flags & MALLOC)
+ && wstr == (wchar_t *) *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ wstr = (wchar_t *) realloc (*strptr,
+ (2 * strsize
+ * sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ wstr = (wchar_t *)
+ realloc (*strptr, ((strsize + 1)
+ * sizeof (wchar_t)));
+ if (wstr == NULL)
+ {
+ /* We lose. Oh well. Terminate the
+ string and stop converting,
+ so at least we don't skip any input. */
+ ((wchar_t *) (*strptr))[strsize - 1] = L'\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) wstr;
+ wstr += strsize;
+ strsize *= 2;
+ }
+ }
+ }
}
- while (width != 0);
+ while (--width > 0);
+
+ if (cnt != 0)
+ /* We stopped in the middle of recognizing another
+ character. That's a problem. */
+ encode_error ();
+#endif
- if (first)
+ if (now == read_in)
+ /* We haven't succesfully read any character. */
conv_error ();
if (!(flags & SUPPRESS))
{
- *wstr = L'\0';
+ *wstr++ = L'\0';
+
+ if ((flags & MALLOC)
+ && wstr - (wchar_t *) *strptr != strsize)
+ {
+ wchar_t *cp = (wchar_t *)
+ realloc (*strptr, ((wstr - (wchar_t *) *strptr)
+ * sizeof(wchar_t)));
+ if (cp != NULL)
+ *strptr = (char *) cp;
+ }
+
++done;
}
}
else
{
- num.ul = read_in - 1; /* -1 because we already read one char. */
+ size_t now = read_in;
+#ifdef COMPILE_WPRINTF
+
+ memset (&state, '\0', sizeof (state));
+
+ do
+ {
+ wchar_t *runp;
+ size_t n;
+
+ if (inchar () == WEOF)
+ break;
+
+ /* Test whether it's in the scanlist. */
+ runp = tw;
+ while (runp < wp)
+ {
+ if (runp[0] == L'-' && runp[1] != '\0' && runp[1] != ']'
+ && runp != tw
+ && (unsigned int) runp[-1] <= (unsigned int) runp[1])
+ {
+ /* Match against all characters in between the
+ first and last character of the sequence. */
+ wchar_t wc;
+
+ for (wc = runp[-1] + 1; wc < runp[1]; ++wc)
+ if (wc == c)
+ break;
+
+ if (wc == runp[1] && !not_in)
+ break;
+ if (wc == runp[1] && not_in)
+ {
+ /* The current character is not in the
+ scanset. */
+ ungetwc (c, s);
+ goto out2;
+ }
+ }
+ else
+ {
+ if (*runp == runp[1] && !not_in)
+ break;
+ if (*runp != runp[1] && not_in)
+ {
+ ungetwc (c ,s);
+ goto out2;
+ }
+ }
+
+ ++runp;
+ }
+
+ if (!(flags & SUPPRESS))
+ {
+ if ((flags & MALLOC)
+ && str + MB_CUR_MAX >= *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ str = (char *) realloc (*strptr, 2 * strsize);
+ if (str == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ str = (char *) realloc (*strptr, strsize + 1);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the string
+ and stop converting, so at least we don't
+ skip any input. */
+ (*strptr)[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = str;
+ str += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = str;
+ str += strsize;
+ strsize *= 2;
+ }
+ }
+ }
+
+ n = wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
+ if (n == (size_t) -1)
+ encode_error ();
+
+ assert (n <= MB_CUR_MAX);
+ str += n;
+ }
+ while (--width > 0);
+ out2:
+#else
do
{
+ if (inchar () == EOF)
+ break;
+
if (wp[c] == not_in)
{
ungetc (c, s);
break;
}
- STRING_ADD_CHAR (str, c, char);
- if (width > 0)
- --width;
+
+ /* This is easy. */
+ if (!(flags & SUPPRESS))
+ {
+ *str++ = c;
+ if ((flags & MALLOC)
+ && (char *) str == *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ str = (char *) realloc (*strptr, 2 * strsize);
+ if (str == NULL)
+ {
+ /* Can't allocate that much. Last-ditch
+ effort. */
+ str = (char *) realloc (*strptr, strsize + 1);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the
+ string and stop converting,
+ so at least we don't skip any input. */
+ ((char *) (*strptr))[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ ++strsize;
+ }
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str += strsize;
+ strsize *= 2;
+ }
+ }
+ }
}
- while (width != 0 && inchar () != EOF);
+ while (--width > 0);
+#endif
- if (read_in == num.ul)
+ if (now == read_in)
+ /* We haven't succesfully read any character. */
conv_error ();
if (!(flags & SUPPRESS))
{
+#ifdef COMPILE_WPRINTF
+ /* We have to emit the code to get into the intial
+ state. */
+ char buf[MB_LEN_MAX];
+ size_t n = wcrtomb (buf, L'\0', &state);
+ if (n > 0 && (flags & MALLOC)
+ && str + n >= *strptr + strsize)
+ {
+ /* Enlarge the buffer. */
+ str = (char *) realloc (*strptr,
+ (str + n + 1) - *strptr);
+ if (str == NULL)
+ {
+ /* We lose. Oh well. Terminate the string
+ and stop converting, so at least we don't
+ skip any input. */
+ ((char *) (*strptr))[strsize - 1] = '\0';
+ ++done;
+ conv_error ();
+ }
+ else
+ {
+ *strptr = (char *) str;
+ str = ((char *) *strptr) + strsize;
+ strsize = (str + n + 1) - *strptr;
+ }
+ }
+
+ str = __mempcpy (str, buf, n);
+#endif
*str = '\0';
+
+ if ((flags & MALLOC) && str - *strptr != strsize)
+ {
+ char *cp = (char *) realloc (*strptr, str - *strptr);
+ if (cp != NULL)
+ *strptr = cp;
+ }
+
++done;
}
}
break;
- case 'p': /* Generic pointer. */
+ case L_('p'): /* Generic pointer. */
base = 16;
/* A PTR must be the same size as a `long int'. */
flags &= ~(SHORT|LONGDBL);
@@ -1305,11 +1960,23 @@ __vfscanf (FILE *s, const char *format, va_list argptr)
}
#ifdef USE_IN_LIBIO
+# ifdef COMPILE_WPRINTF
+int
+__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
+{
+ return _IO_vfwscanf (s, format, argptr, NULL);
+}
+# else
int
__vfscanf (FILE *s, const char *format, va_list argptr)
{
return _IO_vfscanf (s, format, argptr, NULL);
}
+# endif
#endif
+#ifdef COMPILE_WPRINTF
+weak_alias (__vfwscanf, vfwscanf)
+#else
weak_alias (__vfscanf, vfscanf)
+#endif
diff --git a/stdio-common/vfwprintf.c b/stdio-common/vfwprintf.c
new file mode 100644
index 0000000000..2c3cd06fad
--- /dev/null
+++ b/stdio-common/vfwprintf.c
@@ -0,0 +1,3 @@
+#include <wctype.h>
+#define COMPILE_WPRINTF 1
+#include "vfprintf.c"
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
new file mode 100644
index 0000000000..62220bdccc
--- /dev/null
+++ b/stdio-common/vfwscanf.c
@@ -0,0 +1,2 @@
+#define COMPILE_WPRINTF 1
+#include "vfscanf.c"