diff options
author | Ulrich Drepper <drepper@redhat.com> | 2003-06-11 23:22:36 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2003-06-11 23:22:36 +0000 |
commit | 9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b (patch) | |
tree | ea5cb10211192245fd1b92b9b2f07a3d045f3548 /stdio-common/printf-parsemb.c | |
parent | dd9423a67a7650a9b0f50d8151e4f3797c5a14f8 (diff) | |
download | glibc-9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b.tar glibc-9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b.tar.gz glibc-9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b.tar.bz2 glibc-9c7ff11a5cd628ffbe31a7b2de3027ec5b030d8b.zip |
Update.
2003-06-11 Ulrich Drepper <drepper@redhat.com>
* 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.
Diffstat (limited to 'stdio-common/printf-parsemb.c')
-rw-r--r-- | stdio-common/printf-parsemb.c | 407 |
1 files changed, 407 insertions, 0 deletions
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; + } + 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; +} |