From 9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 11 Jun 2003 23:22:36 +0000 Subject: Update. 2003-06-11 Ulrich Drepper * time/tzfile.c: Add a couple of __builtin_expect. Remove warnings gcc 3.3 shows. * argp/argp-help.c (hol_entry_short_iterate): Don't inline. * elf/dl-load.c (fillin_rpath): Likewise. (add_path): Likewise. * elf/dl-version.c (find_needed): Always inline. * elf/do-lookup.c (FCT): Don't inline. * iconv/Makefile: Extend vpath to intl subdir. (iconvconfig-modules): Add hash-string. * iconv/gconv_charset.h (strip): Don't inline. (upstr): Always inline. Move __gconv_compare_alias prototype to... * iconv/gconv_int.h: ...here. * iconv/gconv_db.c: Don't include gconv_charset.h. * iconv/gconv_conf.c (add_alias): Don't inline. (insert_module): Likewise. * iconv/gconv_simple.c (internal_ucs4_loop): Always inline. (internal_ucs4_loop_unaligned): Likewise. (internal_ucs4_loop_single): Likewise. (ucs4_internal_loop): Likewise. (ucs4_internal_loop_unaligned): Likewise. (ucs4_internal_loop_single): Likewise. (internal_ucs4le_loop): Always inline. (internal_ucs4le_loop_unaligned): Likewise. (internal_ucs4le_loop_single): Likewise. (ucs4le_internal_loop): Likewise. (ucs4le_internal_loop_unaligned): Likewise. (ucs4le_internal_loop_single): Likewise. * iconv/loop.c: Always inline the defined functions. * iconvdata/cns11642.h: Likewise. * iconvdata/cns11642l1.h: Likewise. * iconvdata/euc-kr.c: Likewise. * iconvdata/gb2312.h: Likewise. * iconvdata/jis0201.h: Likewise. * iconvdata/jis0208.h: Likewise. * iconvdata/jis0212.h: Likewise. * iconvdata/jisx0213.h: Likewise. * iconvdata/ksc5601.h: Likewise. * iconvdata/utf-7.c (base64): Don't inline. * include/libc-symbols.h (symbol_set_first_element): Add cast (symbol_set_end_p): Likewise. * include/set-hooks (RUN_HOOK): Likewise. * inet/Makefile (aux): Add ifreq. * intl/Makefile (aux): Add some entries from routines. Add hash-string. * intl/hash-string.c: New file. * intl/hash-string.h: Remove hash_string definition. Declare __hash_string. * iconv/gconv_cache.c (find_module_idx): Adjust hash_string caller. * iconv/iconvconfig.c (new_name): Likewise. * intl/dcigettext.c (_nl_find_msg): Likewise. * intl/loadmsgcat.c (_nl_load_domain): Likewise. * io/ftw.c (open_dir_stream): Always inline. (process_entry): Don't inline. * locale/findlocale.c: Include gconv_int.h. * locale/setlocale.c (new_composite_name): Don't inline. * locale/weight.h (findidx): Always inline. * locale/weightwc.h (findidx): Likewise. * locale/programs/linereader.c (lr_ignore_rest): Define here. * locale/programs/linereader.h (lr_ignore_rest): Don't define here, just declare it. (lr_getc): Always inline. (lr_ungetc): Likewise. * nss/nss_files/files-parse.c (parse_list): Likewise. * stdio-common/Makefile (aux): Add printf-parsemb and printf-parsewc. * stdio-common/_itoa.h (_itoa_word): Always inline. (_fitoa_word, _fitoa): Don't define here, only declare. * stdio-common/_itoa.c (_iftoa_word): Add here. (_fitoa): Likewise. * stdio-common/_itowa.h (_itowa_word): Always inline. * stdio-common/printf-parse.h (read_int): Don't inline. (find_spec): Don't define. Declare __find_specmb and __find_specwc. (parse_one_spec): Don't define. Declare __parse_one_specmb and __parse_one_specwc. * stdio-common/printf-parsemb.c: New file. * stdio-common/printf-parsewc.c: New file. * stdio-common/vfprintf.c: Update calls to find_spec and parse_one_spec for new names. * stdio-common/printf-prs.c: Likewise. Define DONT_NEED_READ_INT. * stdlib/Makefile (aux): Add grouping and groupingwc. * stdlib/grouping.c: New file. * stdlib/groupingwc.c: New file. * stdlib/grouping.h (correctly_grouped_prefix): Don't define here. Just prototype. * stdlib/rpmatch.c (try): Don't inline. * stdlib/strtod.c (round_and_return): Don't line. (str_to_mpn): Likewise. (__mpn_lshift_1): Always inline. Optimize only for constant count. Adjust for name change of correctly_grouped_prefix. * sysdeps/generic/strtol.c: Adjust for name change of correctly_grouped_prefix. * string/strxfrm.c (utf8_encode): Don't inline. * sysdeps/generic/dl-cache.c: Define _dl_cache_libcmp. * sysdeps/generic/dl-cache.h: Just declare _dl_cache_libcmp. * sysdeps/generic/ifreq.c: New file. * sysdeps/unix/sysv/linux/ifreq.c: New file. * sysdeps/generic/ifreq.h (__ifreq): Only declare here. * sysdeps/unix/sysv/linux/ifreq.h: Likewise. * sysdeps/generic/ldsodefs.h (_dl_name_match_p): Always inline. * sysdeps/generic/unwind-dw2-fde.c (start_fde_sort): Don't inline. (fde_split): Likewise. (fde_merge): Likewise. (end_fde_sort): Likewise. (init_object): Likewise. (binary_search_unencoded_fdes): Likewise. (binary_search_single_encoding_fdes): Likewise. (binary_search_mixed_encoding_fdes): Likewise. * sysdeps/generic/wordexp.c (w_addchar): Don't inline. * sysdeps/i386/dl-machine.c (elf_machine_runtime_setup): Always inline. * sysdeps/posix/sprofil.c (profil_count): Don't inline. * sysdeps/unix/sysv/linux/Makefile [subdir=io] (sysdep_routines): Add xstatconv. * sysdeps/unix/sysv/linux/xstatconv.h: New file. * sysdeps/unix/sysv/linux/xstatconv.c: Don't inline the function. Export them. Prepend __ to name. * sysdeps/unix/sysv/linux/Dist: Add xstatconv.h. * sysdeps/unix/sysv/linux/fxstat.c: Adjust for name change of conversion functions. * sysdeps/unix/sysv/linux/fxstat64.c: Likewise. * sysdeps/unix/sysv/linux/lxstat.c: Likewise. * sysdeps/unix/sysv/linux/lxstat64.c: Likewise. * sysdeps/unix/sysv/linux/xstat.c: Likewise. * sysdeps/unix/sysv/linux/xstat64.c: Likewise. * sysdeps/unix/sysv/linux/i386/fxstat.c: Likewise. * sysdeps/unix/sysv/linux/i386/lxstat.c: Likewise. * sysdeps/unix/sysv/linux/i386/xstat.c: Likewise. * sysdeps/unix/sysv/linux/pathconf.c (__statfs_link_max, __statfs_filesize_max, __statfs_symlinks): Define here. __ prepended to name. Change callers. * sysdeps/unix/sysv/linux/pathconf.h (__statfs_link_max, __statfs_filesize_max, __statfs_symlinks): Don't define here, just declare. * sysdeps/unix/sysv/linux/fpathconf.c: Change all callers. * time/tzfile.c (decode): Always inline. * wcsmbs/wcsnrtombs.c: Change type of inbuf to unsigned char*. Remove cast in tomb function call. * wcsmbs/wcsrtombs.c Likewise. * wcsmbs/wcstob.c: Introduce new temp variable to take pointer in tomb function call. --- stdio-common/Makefile | 2 +- stdio-common/_itoa.c | 20 +++ stdio-common/_itoa.h | 29 +-- stdio-common/_itowa.h | 4 +- stdio-common/printf-parse.h | 382 +++------------------------------------ stdio-common/printf-parsemb.c | 407 ++++++++++++++++++++++++++++++++++++++++++ stdio-common/printf-parsewc.c | 2 + stdio-common/printf-prs.c | 7 +- stdio-common/vfprintf.c | 14 +- 9 files changed, 471 insertions(+), 396 deletions(-) create mode 100644 stdio-common/printf-parsemb.c create mode 100644 stdio-common/printf-parsewc.c (limited to 'stdio-common') diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 1c34605..f5ef190 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 7bc6c08..e39d88d 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 6249adc..77f5b0c 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 d3a5447..009458b 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 ed0dc8b..aa49c7a 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 -#include #include #include #include -#include - -#define NDEBUG 1 -#include 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 0000000..0d01d56 --- /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 +#include +#include +#include +#include + +#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 + + + +/* 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; + } + 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_specwc (format); +#else + spec->next_fmt = __find_specmb (format, ps); +#endif + } + + return nargs; +} diff --git a/stdio-common/printf-parsewc.c b/stdio-common/printf-parsewc.c new file mode 100644 index 0000000..3de67d8 --- /dev/null +++ b/stdio-common/printf-parsewc.c @@ -0,0 +1,2 @@ +#define COMPILE_WPRINTF 1 +#include "printf-parsemb.c" diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c index ecbb47d..7aef42d 100644 --- a/stdio-common/printf-prs.c +++ b/stdio-common/printf-prs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,92,95,96,99,2000,2002 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,95,96,99,2000,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 @@ -70,6 +70,7 @@ ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n)); # endif #endif +#define DONT_NEED_READ_INT #include "printf-parse.h" @@ -88,10 +89,10 @@ parse_printf_format (fmt, n, argtypes) max_ref_arg = 0; /* Search for format specifications. */ - for (fmt = find_spec (fmt, &mbstate); *fmt != '\0'; fmt = spec.next_fmt) + for (fmt = __find_specmb (fmt, &mbstate); *fmt != '\0'; fmt = spec.next_fmt) { /* Parse this spec. */ - nargs += parse_one_spec (fmt, nargs, &spec, &max_ref_arg, &mbstate); + nargs += __parse_one_specmb (fmt, nargs, &spec, &max_ref_arg, &mbstate); /* If the width is determined by an argument this is an int. */ if (spec.width_arg != -1 && (size_t) spec.width_arg < n) diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 63440f4..16f280e 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1294,13 +1294,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) #ifdef COMPILE_WPRINTF /* Find the first format specifier. */ - f = lead_str_end = find_spec ((const UCHAR_T *) format); + f = lead_str_end = __find_specwc ((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); + f = lead_str_end = __find_specmb (format, &mbstate); #endif /* Lock stream. */ @@ -1596,9 +1596,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* Look for next format specifier. */ #ifdef COMPILE_WPRINTF - f = find_spec ((end_of_spec = ++f)); + f = __find_specwc ((end_of_spec = ++f)); #else - f = find_spec ((end_of_spec = ++f), &mbstate); + f = __find_specmb ((end_of_spec = ++f), &mbstate); #endif /* Write the following constant string. */ @@ -1677,10 +1677,10 @@ do_positional: /* Parse the format specifier. */ #ifdef COMPILE_WPRINTF - nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg); + nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg); #else - nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg, - &mbstate); + nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg, + &mbstate); #endif } -- cgit v1.1