vfprintf.c

来自「用于嵌入式Linux系统的标准C的库函数」· C语言 代码 · 共 1,722 行 · 第 1/4 页

C
1,722
字号
	*p++ = fmtch;	if (exp < 0) {		exp = -exp;		*p++ = '-';	}	else		*p++ = '+';	t = expbuf + 40;	if (exp > 9) {		do {			*--t = to_char(exp % 10);		} while ((exp /= 10) > 9);		*--t = to_char(exp);		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,   OTHER,  /* 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,    OTHER,   OTHER,   MODFR,   OTHER,   OTHER,   SPEC,   /* 70-77 */  SPEC,    MODFR,   OTHER,   SPEC,    OTHER,   SPEC,    OTHER,   OTHER,  /* 78-7f */  SPEC,    OTHER,   OTHER,   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 *get_arg (struct _reent *data, int n, char *fmt, va_list *ap,          int *numargs_p, union arg_val *args, 	 int *arg_type, 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, 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':		  flags |= SHORTINT;		  break;		case 'L':		  flags |= LONGDBL;		  break;		case 'q':		  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;#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 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 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 + =
减小字号Ctrl + -
显示快捷键?