diff options
Diffstat (limited to 'stdio-common')
| -rw-r--r-- | stdio-common/Makefile | 2 | ||||
| -rw-r--r-- | stdio-common/_itoa.c | 20 | ||||
| -rw-r--r-- | stdio-common/_itoa.h | 29 | ||||
| -rw-r--r-- | stdio-common/_itowa.h | 4 | ||||
| -rw-r--r-- | stdio-common/printf-parse.h | 382 | ||||
| -rw-r--r-- | stdio-common/printf-parsemb.c | 407 | ||||
| -rw-r--r-- | stdio-common/printf-parsewc.c | 2 | ||||
| -rw-r--r-- | stdio-common/printf-prs.c | 7 | ||||
| -rw-r--r-- | stdio-common/vfprintf.c | 14 |
9 files changed, 471 insertions, 396 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 1c34605f65..f5ef190850 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -40,7 +40,7 @@ install-others = $(inst_includedir)/bits/stdio_lim.h include ../Makeconfig -aux := errlist siglist +aux := errlist siglist printf-parsemb printf-parsewc distribute := _itoa.h _itowa.h _i18n_number.h \ printf-parse.h stdio_lim.h.in tst-unbputc.sh tst-printf.sh diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c index 7bc6c08115..e39d88df7f 100644 --- a/stdio-common/_itoa.c +++ b/stdio-common/_itoa.c @@ -424,3 +424,23 @@ _itoa (value, buflim, base, upper_case) return buflim; } + +char * +_fitoa_word (unsigned long value, char *buf, unsigned int base, int upper_case) +{ + char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */ + char *cp = _itoa_word (value, tmpbuf + sizeof (value) * 4, base, upper_case); + while (cp < tmpbuf + sizeof (value) * 4) + *buf++ = *cp++; + return buf; +} + +char * +_fitoa (unsigned long long value, char *buf, unsigned int base, int upper_case) +{ + char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */ + char *cp = _itoa (value, tmpbuf + sizeof (value) * 4, base, upper_case); + while (cp < tmpbuf + sizeof (value) * 4) + *buf++ = *cp++; + return buf; +} diff --git a/stdio-common/_itoa.h b/stdio-common/_itoa.h index 6249adca91..77f5b0c026 100644 --- a/stdio-common/_itoa.h +++ b/stdio-common/_itoa.h @@ -1,5 +1,5 @@ /* Internal function for converting integers to ASCII. - Copyright (C) 1994, 95, 96, 97, 98, 99, 2002 Free Software Foundation, Inc. + Copyright (C) 1994,95,96,97,98,99,2002,2003 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 @@ -34,7 +34,7 @@ extern const char _itoa_upper_digits_internal[] attribute_hidden; extern const char _itoa_lower_digits[]; extern const char _itoa_lower_digits_internal[] attribute_hidden; -static inline char * __attribute__ ((unused)) +static inline char * __attribute__ ((unused, always_inline)) _itoa_word (unsigned long value, char *buflim, unsigned int base, int upper_case) { @@ -69,24 +69,11 @@ _itoa_word (unsigned long value, char *buflim, } #undef SPECIAL -static inline char * __attribute__ ((unused)) -_fitoa_word (unsigned long value, char *buf, unsigned int base, int upper_case) -{ - char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */ - char *cp = _itoa_word (value, tmpbuf + sizeof (value) * 4, base, upper_case); - while (cp < tmpbuf + sizeof (value) * 4) - *buf++ = *cp++; - return buf; -} - -static inline char * __attribute__ ((unused)) -_fitoa (unsigned long long value, char *buf, unsigned int base, int upper_case) -{ - char tmpbuf[sizeof (value) * 4]; /* Worst case length: base 2. */ - char *cp = _itoa (value, tmpbuf + sizeof (value) * 4, base, upper_case); - while (cp < tmpbuf + sizeof (value) * 4) - *buf++ = *cp++; - return buf; -} +/* Similar to the _itoa functions, but output starts at buf and pointer + after the last written character is returned. */ +extern char *_fitoa_word (unsigned long value, char *buf, unsigned int base, + int upper_case) attribute_hidden; +extern char *_fitoa (unsigned long long value, char *buf, unsigned int base, + int upper_case) attribute_hidden; #endif /* itoa.h */ diff --git a/stdio-common/_itowa.h b/stdio-common/_itowa.h index d3a5447304..009458b4be 100644 --- a/stdio-common/_itowa.h +++ b/stdio-common/_itowa.h @@ -1,5 +1,5 @@ /* Internal function for converting integers to ASCII. - Copyright (C) 1994, 95, 96, 97, 98, 99, 2002 Free Software Foundation, Inc. + Copyright (C) 1994,95,96,97,98,99,2002,2003 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 @@ -31,7 +31,7 @@ extern wchar_t *_itowa (unsigned long long int value, wchar_t *buflim, unsigned int base, int upper_case); static inline wchar_t * -__attribute__ ((unused)) +__attribute__ ((unused, always_inline)) _itowa_word (unsigned long value, wchar_t *buflim, unsigned int base, int upper_case) { diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h index ed0dc8bbc8..aa49c7a642 100644 --- a/stdio-common/printf-parse.h +++ b/stdio-common/printf-parse.h @@ -1,5 +1,5 @@ /* Internal header for parsing printf format strings. - Copyright (C) 1995-1999, 2000, 2002 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000, 2002, 2003 Free Software Foundation, Inc. This file is part of th GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -17,15 +17,9 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <ctype.h> -#include <limits.h> #include <printf.h> #include <stdint.h> #include <stddef.h> -#include <string.h> - -#define NDEBUG 1 -#include <assert.h> struct printf_spec @@ -66,9 +60,10 @@ union printf_arg }; +#ifndef DONT_NEED_READ_INT /* Read a simple integer from a string and update the string pointer. It is assumed that the first character is a digit. */ -static inline unsigned int +static unsigned int read_int (const UCHAR_T * *pstr) { unsigned int retval = **pstr - L_('0'); @@ -81,35 +76,7 @@ read_int (const UCHAR_T * *pstr) return retval; } - - - -/* 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 UCHAR_T * -#ifdef COMPILE_WPRINTF -find_spec (const UCHAR_T *format) -#else -find_spec (const UCHAR_T *format, mbstate_t *ps) -#endif -{ -#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 += len; - else - ++format; - } - return format; #endif -} /* These are defined in reg-printf.c. */ @@ -117,334 +84,25 @@ extern printf_arginfo_function **__printf_arginfo_table attribute_hidden; extern printf_function **__printf_function_table attribute_hidden; +/* Find the next spec in FORMAT, or the end of the string. Returns + a pointer into FORMAT, to a '%' or a '\0'. */ +extern const unsigned char *__find_specmb (const UCHAR_T *format, + mbstate_t *ps) attribute_hidden; + +extern const unsigned int *__find_specwc (const UCHAR_T *format) + attribute_hidden; + + /* FORMAT must point to a '%' at the beginning of a spec. Fills in *SPEC with the parsed details. POSN is the number of arguments already consumed. At most MAXTYPES - POSN types are filled in TYPES. Return 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; - - /* Skip the '%'. */ - ++format; - - /* Clear information structure. */ - spec->data_arg = -1; - spec->info.alt = 0; - spec->info.space = 0; - spec->info.left = 0; - spec->info.showsign = 0; - spec->info.group = 0; - spec->info.i18n = 0; - spec->info.pad = ' '; - spec->info.wide = sizeof (UCHAR_T) > 1; - - /* Test for positional argument. */ - if (ISDIGIT (*format)) - { - const UCHAR_T *begin = format; - - n = read_int (&format); - - if (n > 0 && *format == L_('$')) - /* Is positional parameter. */ - { - ++format; /* Skip the '$'. */ - spec->data_arg = n - 1; - *max_ref_arg = MAX (*max_ref_arg, n); - } - else - /* Oops; that was actually the width and/or 0 padding flag. - Step back and read it again. */ - format = begin; - } - - /* Check for spec modifiers. */ - do - { - switch (*format) - { - case L_(' '): - /* Output a space in place of a sign, when there is no sign. */ - spec->info.space = 1; - continue; - case L_('+'): - /* Always output + or - for numbers. */ - spec->info.showsign = 1; - continue; - case L_('-'): - /* Left-justify things. */ - spec->info.left = 1; - continue; - case L_('#'): - /* Use the "alternate form": - Hex has 0x or 0X, FP always has a decimal point. */ - spec->info.alt = 1; - continue; - case L_('0'): - /* Pad with 0s. */ - spec->info.pad = '0'; - continue; - case L_('\''): - /* Show grouping in numbers if the locale information - indicates any. */ - spec->info.group = 1; - continue; - case L_('I'): - /* Use the internationalized form of the output. Currently - means to use the `outdigits' of the current locale. */ - spec->info.i18n = 1; - continue; - default: - break; - } - break; - } - while (*++format); - - if (spec->info.left) - spec->info.pad = ' '; - - /* Get the field width. */ - spec->width_arg = -1; - spec->info.width = 0; - if (*format == L_('*')) - { - /* The field width is given in an argument. - A negative field width indicates left justification. */ - const UCHAR_T *begin = ++format; - - if (ISDIGIT (*format)) - { - /* The width argument might be found in a positional parameter. */ - n = read_int (&format); - - if (n > 0 && *format == L_('$')) - { - spec->width_arg = n - 1; - *max_ref_arg = MAX (*max_ref_arg, n); - ++format; /* Skip '$'. */ - } - } - - if (spec->width_arg < 0) - { - /* Not in a positional parameter. Consume one argument. */ - spec->width_arg = posn++; - ++nargs; - format = begin; /* Step back and reread. */ - } - } - else if (ISDIGIT (*format)) - /* Constant width specification. */ - spec->info.width = read_int (&format); - - /* Get the precision. */ - spec->prec_arg = -1; - /* -1 means none given; 0 means explicit 0. */ - spec->info.prec = -1; - if (*format == L_('.')) - { - ++format; - if (*format == L_('*')) - { - /* The precision is given in an argument. */ - const UCHAR_T *begin = ++format; - - if (ISDIGIT (*format)) - { - n = read_int (&format); - - if (n > 0 && *format == L_('$')) - { - spec->prec_arg = n - 1; - *max_ref_arg = MAX (*max_ref_arg, n); - ++format; - } - } - - if (spec->prec_arg < 0) - { - /* Not in a positional parameter. */ - spec->prec_arg = posn++; - ++nargs; - format = begin; - } - } - else if (ISDIGIT (*format)) - spec->info.prec = read_int (&format); - else - /* "%.?" is treated like "%.0?". */ - spec->info.prec = 0; - } - - /* Check for type modifiers. */ - spec->info.is_long_double = 0; - spec->info.is_short = 0; - spec->info.is_long = 0; - spec->info.is_char = 0; - - switch (*format++) - { - case L_('h'): - /* ints are short ints or chars. */ - if (*format != L_('h')) - spec->info.is_short = 1; - else - { - ++format; - spec->info.is_char = 1; - } - break; - case L_('l'): - /* ints are long ints. */ - spec->info.is_long = 1; - if (*format != L_('l')) - break; - ++format; - /* FALLTHROUGH */ - case L_('L'): - /* doubles are long doubles, and ints are long long ints. */ - case L_('q'): - /* 4.4 uses this for long long. */ - spec->info.is_long_double = 1; - break; - case L_('z'): - case L_('Z'): - /* ints are size_ts. */ - assert (sizeof (size_t) <= sizeof (unsigned long long int)); -#if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = sizeof (size_t) > sizeof (unsigned long int); -#endif - spec->info.is_long = sizeof (size_t) > sizeof (unsigned int); - break; - case L_('t'): - assert (sizeof (ptrdiff_t) <= sizeof (long long int)); -#if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = (sizeof (ptrdiff_t) > sizeof (long int)); -#endif - spec->info.is_long = sizeof (ptrdiff_t) > sizeof (int); - break; - case L_('j'): - assert (sizeof (uintmax_t) <= sizeof (unsigned long long int)); -#if LONG_MAX != LONG_LONG_MAX - spec->info.is_long_double = (sizeof (uintmax_t) - > sizeof (unsigned long int)); -#endif - spec->info.is_long = sizeof (uintmax_t) > sizeof (unsigned int); - break; - default: - /* Not a recognized modifier. Backup. */ - --format; - break; - } - - /* Get the format specification. */ - spec->info.spec = (wchar_t) *format++; - if (__builtin_expect (__printf_function_table != NULL, 0) - && spec->info.spec <= UCHAR_MAX - && __printf_arginfo_table[spec->info.spec] != NULL) - /* We don't try to get the types for all arguments if the format - uses more than one. The normal case is covered though. */ - spec->ndata_args = (*__printf_arginfo_table[spec->info.spec]) - (&spec->info, 1, &spec->data_arg_type); - else - { - /* Find the data argument types of a built-in spec. */ - spec->ndata_args = 1; - - switch (spec->info.spec) - { - 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; - else -#endif - if (spec->info.is_long) - spec->data_arg_type = PA_INT|PA_FLAG_LONG; - else if (spec->info.is_short) - spec->data_arg_type = PA_INT|PA_FLAG_SHORT; - else if (spec->info.is_char) - spec->data_arg_type = PA_CHAR; - else - spec->data_arg_type = PA_INT; - break; - case L'e': - case L'E': - case L'f': - 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': - spec->data_arg_type = PA_CHAR; - break; - case L'C': - spec->data_arg_type = PA_WCHAR; - break; - case L's': - spec->data_arg_type = PA_STRING; - break; - case L'S': - spec->data_arg_type = PA_WSTRING; - break; - case L'p': - spec->data_arg_type = PA_POINTER; - break; - case L'n': - spec->data_arg_type = PA_INT|PA_FLAG_PTR; - break; - - case L'm': - default: - /* An unknown spec will consume no args. */ - spec->ndata_args = 0; - break; - } - } - - if (spec->data_arg == -1 && spec->ndata_args > 0) - { - /* There are args consumed, but no positional spec. Use the - next sequential arg position. */ - spec->data_arg = posn; - nargs += spec->ndata_args; - } - - if (spec->info.spec == L'\0') - /* Format ended before this spec was complete. */ - spec->end_of_fmt = spec->next_fmt = format - 1; - else - { - /* 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; -} +extern size_t __parse_one_specmb (const unsigned char *format, size_t posn, + struct printf_spec *spec, + size_t *max_ref_arg, mbstate_t *ps) + attribute_hidden; + +extern size_t __parse_one_specwc (const unsigned int *format, size_t posn, + struct printf_spec *spec, + size_t *max_ref_arg) attribute_hidden; diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c new file mode 100644 index 0000000000..0d01d5693e --- /dev/null +++ b/stdio-common/printf-parsemb.c @@ -0,0 +1,407 @@ +/* Internal header for parsing printf format strings. + Copyright (C) 1995-1999, 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of th GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#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) +#else +# define CHAR_T wchar_t +# define UCHAR_T unsigned int +# define INT_T wint_t +# define L_(Str) L##Str +# define ISDIGIT(Ch) iswdigit (Ch) +#endif + +#include "printf-parse.h" + +#define NDEBUG 1 +#include <assert.h> + + + +/* Find the next spec in FORMAT, or the end of the string. Returns + a pointer into FORMAT, to a '%' or a '\0'. */ +const UCHAR_T * +#ifdef COMPILE_WPRINTF +__find_specwc (const UCHAR_T *format) +#else +__find_specmb (const UCHAR_T *format, mbstate_t *ps) +#endif +{ +#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 += len; + else + ++format; + } + return format; +#endif +} + + +/* FORMAT must point to a '%' at the beginning of a spec. Fills in *SPEC + with the parsed details. POSN is the number of arguments already + consumed. At most MAXTYPES - POSN types are filled in TYPES. Return + the number of args consumed by this spec; *MAX_REF_ARG is updated so it + remains the highest argument index used. */ +size_t +attribute_hidden +#ifdef COMPILE_WPRINTF +__parse_one_specwc (const UCHAR_T *format, size_t posn, + struct printf_spec *spec, size_t *max_ref_arg) +#else +__parse_one_specmb (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; + + /* Skip the '%'. */ + ++format; + + /* Clear information structure. */ + spec->data_arg = -1; + spec->info.alt = 0; + spec->info.space = 0; + spec->info.left = 0; + spec->info.showsign = 0; + spec->info.group = 0; + spec->info.i18n = 0; + spec->info.pad = ' '; + spec->info.wide = sizeof (UCHAR_T) > 1; + + /* Test for positional argument. */ + if (ISDIGIT (*format)) + { + const UCHAR_T *begin = format; + + n = read_int (&format); + + if (n > 0 && *format == L_('$')) + /* Is positional parameter. */ + { + ++format; /* Skip the '$'. */ + spec->data_arg = n - 1; + *max_ref_arg = MAX (*max_ref_arg, n); + } + else + /* Oops; that was actually the width and/or 0 padding flag. + Step back and read it again. */ + format = begin; + } + + /* Check for spec modifiers. */ + do + { + switch (*format) + { + case L_(' '): + /* Output a space in place of a sign, when there is no sign. */ + spec->info.space = 1; + continue; + case L_('+'): + /* Always output + or - for numbers. */ + spec->info.showsign = 1; + continue; + case L_('-'): + /* Left-justify things. */ + spec->info.left = 1; + continue; + case L_('#'): + /* Use the "alternate form": + Hex has 0x or 0X, FP always has a decimal point. */ + spec->info.alt = 1; + continue; + case L_('0'): + /* Pad with 0s. */ + spec->info.pad = '0'; + continue; + case L_('\''): + /* Show grouping in numbers if the locale information + indicates any. */ + spec->info.group = 1; + continue; + case L_('I'): + /* Use the internationalized form of the output. Currently + means to use the `outdigits' of the current locale. */ + spec->info.i18n = 1; + continue; + default: + break; + } + break; + } |
