diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
commit | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch) | |
tree | 2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /stdio-common/vfprintf.c | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.bz2 glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.zip |
2.5-18.1
Diffstat (limited to 'stdio-common/vfprintf.c')
-rw-r--r-- | stdio-common/vfprintf.c | 113 |
1 files changed, 71 insertions, 42 deletions
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 832a6ed547..bf5227873b 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006, 2007 + 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 @@ -64,7 +65,7 @@ #define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED) #ifndef COMPILE_WPRINTF -# define vfprintf _IO_vfprintf +# define vfprintf _IO_vfprintf_internal # define CHAR_T char # define UCHAR_T unsigned char # define INT_T int @@ -257,7 +258,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z')) #define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')]) -#if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED +#ifdef SHARED /* 'int' is enough and it saves some space on 64 bit systems. */ # define JUMP_TABLE_TYPE const int # define JUMP(ChExpr, table) \ @@ -529,14 +530,24 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) { \ if (is_long_num) \ signed_number = va_arg (ap, long int); \ - else /* `char' and `short int' will be promoted to `int'. */ \ + else if (is_char) \ + signed_number = (signed char) va_arg (ap, unsigned int); \ + else if (!is_short) \ signed_number = va_arg (ap, int); \ + else \ + signed_number = (short int) va_arg (ap, unsigned int); \ } \ else \ if (is_long_num) \ signed_number = args_value[fspec->data_arg].pa_long_int; \ - else /* `char' and `short int' will be promoted to `int'. */ \ + else if (is_char) \ + signed_number = (signed char) \ + args_value[fspec->data_arg].pa_u_int; \ + else if (!is_short) \ signed_number = args_value[fspec->data_arg].pa_int; \ + else \ + signed_number = (short int) \ + args_value[fspec->data_arg].pa_u_int; \ \ is_negative = signed_number < 0; \ number.word = is_negative ? (- signed_number) : signed_number; \ @@ -758,6 +769,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) \ if (fspec == NULL) \ { \ + if (__ldbl_is_dbl) \ + is_long_double = 0; \ + \ struct printf_info info = { .prec = prec, \ .width = width, \ .spec = spec, \ @@ -785,6 +799,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) else \ { \ ptr = (const void *) &args_value[fspec->data_arg]; \ + if (__ldbl_is_dbl) \ + { \ + fspec->data_arg_type = PA_DOUBLE; \ + fspec->info.is_long_double = 0; \ + } \ \ function_done = __printf_fp (s, &fspec->info, &ptr); \ } \ @@ -808,6 +827,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) \ if (fspec == NULL) \ { \ + if (__ldbl_is_dbl) \ + is_long_double = 0; \ + \ struct printf_info info = { .prec = prec, \ .width = width, \ .spec = spec, \ @@ -834,6 +856,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) else \ { \ ptr = (const void *) &args_value[fspec->data_arg]; \ + if (__ldbl_is_dbl) \ + fspec->info.is_long_double = 0; \ \ function_done = __printf_fphex (s, &fspec->info, &ptr); \ } \ @@ -1001,10 +1025,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) const char *mbs = (const char *) string; \ mbstate_t mbstate; \ \ - len = prec != -1 ? (size_t) prec : strlen (mbs); \ + len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \ \ /* Allocate dynamically an array which definitely is long \ - enough for the wide character version. */ \ + enough for the wide character version. Each byte in the \ + multi-byte string can produce at most one wide character. */ \ if (__libc_use_alloca (len * sizeof (wchar_t))) \ string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \ else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \ @@ -1135,19 +1160,26 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) else \ { \ /* In case we have a multibyte character set the \ - situation is more compilcated. We must not copy \ + situation is more complicated. We must not copy \ bytes at the end which form an incomplete character. */\ - wchar_t ignore[prec]; \ + size_t ignore_size = (unsigned) prec > 1024 ? 1024 : prec;\ + wchar_t ignore[ignore_size]; \ const char *str2 = string; \ - mbstate_t ps; \ + const char *strend = string + prec; \ + if (strend < string) \ + strend = (const char *) UINTPTR_MAX; \ \ + mbstate_t ps; \ memset (&ps, '\0', sizeof (ps)); \ - if (__mbsnrtowcs (ignore, &str2, prec, prec, &ps) \ - == (size_t) -1) \ - { \ - done = -1; \ - goto all_done; \ - } \ + \ + while (str2 != NULL && str2 < strend) \ + if (__mbsnrtowcs (ignore, &str2, strend - str2, \ + ignore_size, &ps) == (size_t) -1) \ + { \ + done = -1; \ + goto all_done; \ + } \ + \ if (str2 == NULL) \ len = strlen (string); \ else \ @@ -1283,7 +1315,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) /* Process whole format string. */ do { -#if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED +#ifdef SHARED # define REF(Name) &&do_##Name - &&do_form_unknown #else # define REF(Name) &&do_##Name @@ -1594,6 +1626,8 @@ do_positional: /* Just a counter. */ size_t cnt; + free (workstart); + workstart = NULL; if (grouping == (const char *) -1) { @@ -1704,7 +1738,15 @@ do_positional: T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int); T (PA_FLOAT, pa_double, double); /* Promoted. */ T (PA_DOUBLE, pa_double, double); - T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double); + case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: + if (__ldbl_is_dbl) + { + args_value[cnt].pa_double = va_arg (ap_save, double); + args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE; + } + else + args_value[cnt].pa_long_double = va_arg (ap_save, long double); + break; T (PA_STRING, pa_string, const char *); T (PA_WSTRING, pa_wstring, const wchar_t *); T (PA_POINTER, pa_pointer, void *); @@ -1726,7 +1768,7 @@ do_positional: for (; (size_t) nspecs_done < nspecs; ++nspecs_done) { #undef REF -#if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED +#ifdef SHARED # define REF(Name) &&do2_##Name - &&do_form_unknown #else # define REF(Name) &&do2_##Name @@ -1760,7 +1802,9 @@ do_positional: int use_outdigits = specs[nspecs_done].info.i18n; char pad = specs[nspecs_done].info.pad; CHAR_T spec = specs[nspecs_done].info.spec; - CHAR_T *workstart = NULL; + + workstart = NULL; + workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; /* Fill in last information. */ if (specs[nspecs_done].width_arg != -1) @@ -1856,8 +1900,7 @@ do_positional: break; } - if (__builtin_expect (workstart != NULL, 0)) - free (workstart); + free (workstart); workstart = NULL; /* Write the following constant string. */ @@ -1885,7 +1928,7 @@ printf_unknown (FILE *s, const struct printf_info *info, { int done = 0; - CHAR_T work_buffer[MAX (info->width, info->spec) + 32]; + CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3]; CHAR_T *const workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; register CHAR_T *w; @@ -2154,25 +2197,11 @@ buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format, } #undef vfprintf -#ifdef strong_alias -/* This is for glibc. */ -# ifdef COMPILE_WPRINTF +#ifdef COMPILE_WPRINTF strong_alias (_IO_vfwprintf, __vfwprintf); -weak_alias (_IO_vfwprintf, vfwprintf); -# else -strong_alias (_IO_vfprintf, vfprintf); -libc_hidden_def (vfprintf) -INTDEF(_IO_vfprintf) -# endif +ldbl_weak_alias (_IO_vfwprintf, vfwprintf); #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 +ldbl_strong_alias (_IO_vfprintf_internal, vfprintf); +ldbl_hidden_def (_IO_vfprintf_internal, vfprintf) +ldbl_strong_alias (_IO_vfprintf_internal, _IO_vfprintf); #endif |