📄 vfprintf.c
字号:
for (; t < expbuf + 40; *p++ = *t++); } else { *p++ = '0'; *p++ = to_char (exp); } return (p - p0);}#endif /* FLOATING_POINT */#ifndef _NO_POS_ARGS/* Positional argument support. Written by Jeff Johnston Copyright (c) 2002 Red Hat Incorporated. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The name of Red Hat Incorporated may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */typedef enum { ZERO, /* '0' */ DIGIT, /* '1-9' */ DOLLAR, /* '$' */ MODFR, /* spec modifier */ SPEC, /* format specifier */ DOT, /* '.' */ STAR, /* '*' */ FLAG, /* format flag */ OTHER, /* all other chars */ MAX_CH_CLASS /* place-holder */} CH_CLASS;typedef enum { START, /* start */ SFLAG, /* seen a flag */ WDIG, /* seen digits in width area */ WIDTH, /* processed width */ SMOD, /* seen spec modifier */ SDOT, /* seen dot */ VARW, /* have variable width specifier */ VARP, /* have variable precision specifier */ PREC, /* processed precision */ VWDIG, /* have digits in variable width specification */ VPDIG, /* have digits in variable precision specification */ DONE, /* done */ MAX_STATE, /* place-holder */ } STATE;typedef enum { NOOP, /* do nothing */ NUMBER, /* build a number from digits */ SKIPNUM, /* skip over digits */ GETMOD, /* get and process format modifier */ GETARG, /* get and process argument */ GETPW, /* get variable precision or width */ GETPWB, /* get variable precision or width and pushback fmt char */ GETPOS, /* get positional parameter value */ PWPOS, /* get positional parameter value for variable width or precision */} ACTION;_CONST static CH_CLASS chclass[256] = { /* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 18-1f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 20-27 */ FLAG, OTHER, OTHER, FLAG, DOLLAR, OTHER, OTHER, FLAG, /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER, /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC, /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC, /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, /* 68-6f */ MODFR, SPEC, MODFR, OTHER, MODFR, OTHER, OTHER, SPEC, /* 70-77 */ SPEC, MODFR, OTHER, SPEC, MODFR, SPEC, OTHER, OTHER, /* 78-7f */ SPEC, OTHER, MODFR, OTHER, OTHER, OTHER, OTHER, OTHER, /* 80-87 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 88-8f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 90-97 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 98-9f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* a0-a7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* a8-af */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* b0-b7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* b8-bf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* c0-c7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* c8-cf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* d0-d7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* d8-df */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* e0-e7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* e8-ef */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* f0-f7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,};_CONST static STATE state_table[MAX_STATE][MAX_CH_CLASS] = { /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ /* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, /* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, /* WDIG */ { DONE, DONE, WIDTH, SMOD, DONE, SDOT, DONE, DONE, DONE }, /* WIDTH */ { DONE, DONE, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, /* SMOD */ { DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE }, /* SDOT */ { SDOT, PREC, DONE, SMOD, DONE, DONE, VARP, DONE, DONE }, /* VARW */ { DONE, VWDIG, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, /* VARP */ { DONE, VPDIG, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, /* PREC */ { DONE, DONE, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, /* VWDIG */ { DONE, DONE, WIDTH, DONE, DONE, DONE, DONE, DONE, DONE }, /* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE },};_CONST static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = { /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ /* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* WDIG */ { NOOP, NOOP, GETPOS, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* WIDTH */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* SMOD */ { NOOP, NOOP, NOOP, NOOP, GETARG, NOOP, NOOP, NOOP, NOOP }, /* SDOT */ { NOOP, SKIPNUM, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* VARW */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, GETPW, NOOP, NOOP, NOOP }, /* VARP */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, NOOP, NOOP, NOOP, NOOP }, /* PREC */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, /* VWDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP }, /* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP },};/* function to get positional parameter N where n = N - 1 */static union arg_val *_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt), struct _reent *data _AND int n _AND char *fmt _AND va_list *ap _AND int *numargs_p _AND union arg_val *args _AND int *arg_type _AND char **last_fmt){ int ch; int number, flags; int spec_type; int numargs = *numargs_p; CH_CLASS chtype; STATE state, next_state; ACTION action; int pos, last_arg; int max_pos_arg = n; enum types { INT, LONG_INT, SHORT_INT, CHAR_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR };#ifdef _MB_CAPABLE wchar_t wc; mbstate_t wc_state; int nbytes; #endif /* if this isn't the first call, pick up where we left off last time */ if (*last_fmt != NULL) fmt = *last_fmt;#ifdef _MB_CAPABLE memset (&wc_state, '\0', sizeof (wc_state));#endif /* we need to process either to end of fmt string or until we have actually read the desired parameter from the vararg list. */ while (*fmt && n >= numargs) {#ifdef _MB_CAPABLE while ((nbytes = _mbtowc_r (data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0) { fmt += nbytes; if (wc == '%') break; } if (nbytes <= 0) break;#else while (*fmt != '\0' && *fmt != '%') fmt += 1; if (*fmt == '\0') break;#endif state = START; flags = 0; pos = -1; number = 0; spec_type = INT; /* Use state/action table to process format specifiers. We ignore invalid formats and we are only interested in information that tells us how to read the vararg list. */ while (state != DONE) { ch = *fmt++; chtype = chclass[ch]; next_state = state_table[state][chtype]; action = action_table[state][chtype]; state = next_state; switch (action) { case GETMOD: /* we have format modifier */ switch (ch) { case 'h': if (*fmt == 'h') { flags |= CHARINT; ++fmt; } else flags |= SHORTINT; break; case 'L': flags |= LONGDBL; break; case 'q': flags |= QUADINT; break; case 'j': if (sizeof (intmax_t) == sizeof (long)) flags |= LONGINT; else flags |= QUADINT; break; case 'z': if (sizeof (size_t) < sizeof (int)) /* POSIX states size_t is 16 or more bits, as is short. */ flags |= SHORTINT; else if (sizeof (size_t) == sizeof (int)) /* no flag needed */; else if (sizeof (size_t) <= sizeof (long)) flags |= LONGINT; else /* POSIX states that at least one programming environment must support size_t no wider than long, but that means other environments can have size_t as wide as long long. */ flags |= QUADINT; break; case 't': if (sizeof (ptrdiff_t) < sizeof (int)) /* POSIX states ptrdiff_t is 16 or more bits, as is short. */ flags |= SHORTINT; else if (sizeof (ptrdiff_t) == sizeof (int)) /* no flag needed */; else if (sizeof (ptrdiff_t) <= sizeof (long)) flags |= LONGINT; else /* POSIX states that at least one programming environment must support ptrdiff_t no wider than long, but that means other environments can have ptrdiff_t as wide as long long. */ flags |= QUADINT; break; case 'l': default: if (*fmt == 'l') { flags |= QUADINT; ++fmt; } else flags |= LONGINT; break; } break; case GETARG: /* we have format specifier */ { numargs &= (MAX_POS_ARGS - 1); /* process the specifier and translate it to a type to fetch from varargs */ switch (ch) { case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': if (flags & LONGINT) spec_type = LONG_INT; else if (flags & SHORTINT) spec_type = SHORT_INT; else if (flags & CHARINT) spec_type = CHAR_INT;#ifndef _NO_LONGLONG else if (flags & QUADINT) spec_type = QUAD_INT;#endif else spec_type = INT; break; case 'D': case 'U': case 'O': spec_type = LONG_INT; break; case 'f': case 'g': case 'G': case 'E': case 'e':#ifndef _NO_LONGDBL if (flags & LONGDBL) spec_type = LONG_DOUBLE; else#endif spec_type = DOUBLE; break; case 's': case 'S': case 'p': spec_type = CHAR_PTR; break; case 'c': spec_type = CHAR; break; case 'C': spec_type = WIDE_CHAR; break; } /* if we have a positional parameter, just store the type, otherwise fetch the parameter from the vararg list */ if (pos != -1) arg_type[pos] = spec_type; else { switch (spec_type) { case LONG_INT: args[numargs++].val_long = va_arg (*ap, long); break; case QUAD_INT: args[numargs++].val_quad_t = va_arg (*ap, quad_t); break; case WIDE_CHAR: args[numargs++].val_wint_t = va_arg (*ap, wint_t); break; case CHAR: case CHAR_INT: case SHORT_INT: case INT: args[numargs++].val_int = va_arg (*ap, int); break; case CHAR_PTR: args[numargs++].val_char_ptr_t = va_arg (*ap, char *); break; case DOUBLE: args[numargs++].val_double = va_arg (*ap, double); break; case LONG_DOUBLE: args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE); break; } } } break; case GETPOS: /* we have positional specifier */ if (arg_type[0] == -1) memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS); pos = number - 1; max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos); break; case PWPOS: /* we have positional specifier for width or precision */ if (arg_type[0] == -1) memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS); number -= 1; arg_type[number] = INT; max_pos_arg = (max_pos_arg > number ? max_pos_arg : number); break; case GETPWB: /* we require format pushback */ --fmt; /* fallthrough */ case GETPW: /* we have a variable precision or width to acquire */ args[numargs++].val_int = va_arg (*ap, int); break; case NUMBER: /* we have a number to process */ number = (ch - '0'); while ((ch = *fmt) != '\0' && is_digit (ch)) { number = number * 10 + (ch - '0'); ++fmt; } break; case SKIPNUM: /* we have a number to skip */ while ((ch = *fmt) != '\0' && is_digit (ch)) ++fmt; break; case NOOP: default: break; /* do nothing */ } } } /* process all arguments up to at least the one we are looking for and if we have seen the end of the string, then process up to the max argument needed */ if (*fmt == '\0') last_arg = max_pos_arg; else last_arg = n; while (numargs <= last_arg) { switch (arg_type[numargs]) { case LONG_INT: args[numargs++].val_long = va_arg (*ap, long); break; case QUAD_INT: args[numargs++].val_quad_t = va_arg (*ap, quad_t); break; case CHAR_PTR: args[numargs++].val_char_ptr_t = va_arg (*ap, char *); break; case DOUBLE: args[numargs++].val_double = va_arg (*ap, double); break; case LONG_DOUBLE: args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE); break; case WIDE_CHAR: args[numargs++].val_wint_t = va_arg (*ap, wint_t); break; case INT: case CHAR_INT: case SHORT_INT: case CHAR: default: args[numargs++].val_int = va_arg (*ap, int); break; } } /* alter the global numargs value and keep a reference to the last bit of the fmt string we processed here because the caller will continue processing where we started */ *numargs_p = numargs; *last_fmt = fmt; return &args[n];}#endif /* !_NO_POS_ARGS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -