📄 vfprintf.c
字号:
/* Copyright (C) 1991-2002, 2003, 2004 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 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 <printf.h>#include <stdarg.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <wchar.h>#include <bits/libc-lock.h>#include <sys/param.h>#include "_itoa.h"#include <locale/localeinfo.h>#include <stdio.h>/* This code is shared between the standard stdio implementation found in GNU C library and the libio implementation originally found in GNU libg++. Beside this it is also shared between the normal and wide character implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */#include <libioP.h>#define FILE _IO_FILE#undef va_list#define va_list _IO_va_list#undef BUFSIZ#define BUFSIZ _IO_BUFSIZ#define ARGCHECK(S, Format) \ do \ { \ /* Check file argument for consistence. */ \ CHECK_FILE (S, -1); \ if (S->_flags & _IO_NO_WRITES) \ { \ __set_errno (EBADF); \ return -1; \ } \ if (Format == NULL) \ { \ MAYBE_SET_EINVAL; \ return -1; \ } \ } 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) ((unsigned int) ((Ch) - '0') < 10)# define STR_LEN(Str) strlen (Str)# define PUT(F, S, N) _IO_sputn ((F), (S), (N))# define PAD(Padchar) \ if (width > 0) \ done += INTUSE(_IO_padn) (s, (Padchar), width)# define PUTC(C, F) _IO_putc_unlocked (C, F)# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\ return -1#else# 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) ((unsigned int) ((Ch) - L'0') < 10)# define STR_LEN(Str) __wcslen (Str)# include "_itowa.h"# 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, Buf, Base, Case)# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)# undef EOF# define EOF WEOF#endif#include "_i18n_number.h"/* Include the shared code for parsing the format string. */#include "printf-parse.h"#define outchar(Ch) \ do \ { \ register const INT_T outc = (Ch); \ if (PUTC (outc, s) == EOF) \ { \ done = -1; \ goto all_done; \ } \ else \ ++done; \ } \ while (0)#define outstring(String, Len) \ do \ { \ if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \ { \ done = -1; \ goto all_done; \ } \ done += (Len); \ } \ while (0)/* For handling long_double and longlong we use the same flag. If `long' and `long long' are effectively the same type define it to zero. */#if LONG_MAX == LONG_LONG_MAX# define is_longlong 0#else# define is_longlong is_long_double#endif/* If `long' and `int' is effectively the same type we don't have to handle `long separately. */#if INT_MAX == LONG_MAX# define is_long_num 0#else# define is_long_num is_long#endif/* Global variables. */static const CHAR_T null[] = L_("(null)");/* Helper function to provide temporary buffering for unbuffered streams. */static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list) __THROW __attribute__ ((noinline)) internal_function;/* Handle unknown format specifier. */static int printf_unknown (FILE *, const struct printf_info *, const void *const *) __THROW;/* Group digits of number string. */#ifdef COMPILE_WPRINTFstatic CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, wchar_t) __THROW internal_function;#elsestatic CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, const char *) __THROW internal_function;#endif/* The function itself. */intvfprintf (FILE *s, const CHAR_T *format, va_list ap){ /* The character used as thousands separator. */#ifdef COMPILE_WPRINTF wchar_t thousands_sep = L'\0';#else const char *thousands_sep = NULL;#endif /* The string describing the size of groups of digits. */ const char *grouping; /* Place to accumulate the result. */ int done; /* Current character in format string. */ const UCHAR_T *f; /* End of leading constant string. */ const UCHAR_T *lead_str_end; /* Points to next format specifier. */ const UCHAR_T *end_of_spec; /* Buffer intermediate results. */ CHAR_T work_buffer[1000]; CHAR_T *workstart = NULL; CHAR_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; /* Count number of specifiers we already processed. */ int nspecs_done; /* For the %m format we may need the current `errno' value. */ int save_errno = errno; /* 1 if format is in read-only memory, -1 if it is in writable memory, 0 if unknown. */ int readonly_format = 0; /* This table maps a character into a number representing a class. In each step there is a destination label for each class. */ static const int jump_table[] = { /* ' ' */ 1, 0, 0, /* '#' */ 4, 0, /* '%' */ 14, 0, /* '\''*/ 6, 0, 0, /* '*' */ 7, /* '+' */ 2, 0, /* '-' */ 3, /* '.' */ 9, 0, /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8, /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8, /* '8' */ 8, /* '9' */ 8, 0, 0, 0, 0, 0, 0, 0, /* 'A' */ 26, 0, /* 'C' */ 25, 0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19, 0, /* 'I' */ 29, 0, 0, /* 'L' */ 12, 0, 0, 0, 0, 0, 0, /* 'S' */ 21, 0, 0, 0, 0, /* 'X' */ 18, 0, /* 'Z' */ 13, 0, 0, 0, 0, 0, 0, /* 'a' */ 26, 0, /* 'c' */ 20, /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19, /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0, /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17, /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21, /* 't' */ 27, /* 'u' */ 16, 0, 0, /* 'x' */ 18, 0, /* 'z' */ 13 };#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 /* 'int' is enough and it saves some space on 64 bit systems. */# define JUMP_TABLE_TYPE const int# define JUMP(ChExpr, table) \ do \ { \ int offset; \ void *__unbounded ptr; \ spec = (ChExpr); \ offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ : table[CHAR_CLASS (spec)]; \ ptr = &&do_form_unknown + offset; \ goto *ptr; \ } \ while (0)#else# define JUMP_TABLE_TYPE const void *const# define JUMP(ChExpr, table) \ do \ { \ const void *__unbounded ptr; \ spec = (ChExpr); \ ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ : table[CHAR_CLASS (spec)]; \ goto *ptr; \ } \ while (0)#endif#define STEP0_3_TABLE \ /* Step 0: at the beginning. */ \ static JUMP_TABLE_TYPE step0_jumps[30] = \ { \ REF (form_unknown), \ REF (flag_space), /* for ' ' */ \ REF (flag_plus), /* for '+' */ \ REF (flag_minus), /* for '-' */ \ REF (flag_hash), /* for '<hash>' */ \ REF (flag_zero), /* for '0' */ \ REF (flag_quote), /* for '\'' */ \ REF (width_asterics), /* for '*' */ \ REF (width), /* for '1'...'9' */ \ REF (precision), /* for '.' */ \ REF (mod_half), /* for 'h' */ \ REF (mod_long), /* for 'l' */ \ REF (mod_longlong), /* for 'L', 'q' */ \ REF (mod_size_t), /* for 'z', 'Z' */ \ REF (form_percent), /* for '%' */ \ REF (form_integer), /* for 'd', 'i' */ \ REF (form_unsigned), /* for 'u' */ \ REF (form_octal), /* for 'o' */ \ REF (form_hexa), /* for 'X', 'x' */ \ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ REF (form_character), /* for 'c' */ \ REF (form_string), /* for 's', 'S' */ \ REF (form_pointer), /* for 'p' */ \ REF (form_number), /* for 'n' */ \ REF (form_strerror), /* for 'm' */ \ REF (form_wcharacter), /* for 'C' */ \ REF (form_floathex), /* for 'A', 'a' */ \ REF (mod_ptrdiff_t), /* for 't' */ \ REF (mod_intmax_t), /* for 'j' */ \ REF (flag_i18n), /* for 'I' */ \ }; \ /* Step 1: after processing width. */ \ static JUMP_TABLE_TYPE step1_jumps[30] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ REF (form_unknown), /* for '+' */ \ REF (form_unknown), /* for '-' */ \ REF (form_unknown), /* for '<hash>' */ \ REF (form_unknown), /* for '0' */ \ REF (form_unknown), /* for '\'' */ \ REF (form_unknown), /* for '*' */ \ REF (form_unknown), /* for '1'...'9' */ \ REF (precision), /* for '.' */ \ REF (mod_half), /* for 'h' */ \ REF (mod_long), /* for 'l' */ \ REF (mod_longlong), /* for 'L', 'q' */ \ REF (mod_size_t), /* for 'z', 'Z' */ \ REF (form_percent), /* for '%' */ \ REF (form_integer), /* for 'd', 'i' */ \ REF (form_unsigned), /* for 'u' */ \ REF (form_octal), /* for 'o' */ \ REF (form_hexa), /* for 'X', 'x' */ \ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ REF (form_character), /* for 'c' */ \ REF (form_string), /* for 's', 'S' */ \ REF (form_pointer), /* for 'p' */ \ REF (form_number), /* for 'n' */ \ REF (form_strerror), /* for 'm' */ \ REF (form_wcharacter), /* for 'C' */ \ REF (form_floathex), /* for 'A', 'a' */ \ REF (mod_ptrdiff_t), /* for 't' */ \ REF (mod_intmax_t), /* for 'j' */ \ REF (form_unknown) /* for 'I' */ \ }; \ /* Step 2: after processing precision. */ \ static JUMP_TABLE_TYPE step2_jumps[30] = \ { \ REF (form_unknown), \ REF (form_unknown), /* for ' ' */ \ REF (form_unknown), /* for '+' */ \ REF (form_unknown), /* for '-' */ \ REF (form_unknown), /* for '<hash>' */ \ REF (form_unknown), /* for '0' */ \ REF (form_unknown), /* for '\'' */ \ REF (form_unknown), /* for '*' */ \ REF (form_unknown), /* for '1'...'9' */ \ REF (form_unknown), /* for '.' */ \ REF (mod_half), /* for 'h' */ \ REF (mod_long), /* for 'l' */ \ REF (mod_longlong), /* for 'L', 'q' */ \ REF (mod_size_t), /* for 'z', 'Z' */ \ REF (form_percent), /* for '%' */ \ REF (form_integer), /* for 'd', 'i' */ \ REF (form_unsigned), /* for 'u' */ \ REF (form_octal), /* for 'o' */ \ REF (form_hexa), /* for 'X', 'x' */ \ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ REF (form_character), /* for 'c' */ \ REF (form_string), /* for 's', 'S' */ \ REF (form_pointer), /* for 'p' */ \ REF (form_number), /* for 'n' */ \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -