⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vsscanf.c

📁 linux内核
💻 C
字号:
/* * vsscanf.c * * vsscanf(), from which the rest of the scanf() * family is built */#include <ctype.h>#include <stdarg.h>#include <stddef.h>#include <inttypes.h>#include <string.h>#include <limits.h>#include <stdio.h>#ifndef LONG_BIT#define LONG_BIT (CHAR_BIT*sizeof(long))#endifenum flags {  FL_SPLAT  = 0x01,		/* Drop the value, do not assign */  FL_INV    = 0x02,		/* Character-set with inverse */  FL_WIDTH  = 0x04,		/* Field width specified */  FL_MINUS  = 0x08,		/* Negative number */};enum ranks {  rank_char	= -2,  rank_short	= -1,  rank_int 	= 0,  rank_long	= 1,  rank_longlong	= 2,  rank_ptr      = INT_MAX	/* Special value used for pointers */};#define MIN_RANK	rank_char#define MAX_RANK	rank_longlong#define INTMAX_RANK	rank_longlong#define SIZE_T_RANK	rank_long#define PTRDIFF_T_RANK	rank_longenum bail {  bail_none = 0,		/* No error condition */  bail_eof,			/* Hit EOF */  bail_err			/* Conversion mismatch */};static inline const char *skipspace(const char *p){  while ( isspace((unsigned char)*p) ) p++;  return p;}#undef set_bitstatic inline voidset_bit(unsigned long *bitmap, unsigned int bit){  bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);}#undef test_bitstatic inline inttest_bit(unsigned long *bitmap, unsigned int bit){  return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;}int vsscanf(const char *buffer, const char *format, va_list ap){  const char *p = format;  char ch;  const char *q = buffer;  const char *qq;  uintmax_t val = 0;  int rank = rank_int;		/* Default rank */  unsigned int width = UINT_MAX;  int base;  enum flags flags = 0;  enum {    st_normal,			/* Ground state */    st_flags,			/* Special flags */    st_width,			/* Field width */    st_modifiers,		/* Length or conversion modifiers */    st_match_init,		/* Initial state of %[ sequence */    st_match,			/* Main state of %[ sequence */    st_match_range,		/* After - in a %[ sequence */  } state = st_normal;  char *sarg = NULL;		/* %s %c or %[ string argument */  enum bail bail = bail_none;  int sign;  int converted = 0;		/* Successful conversions */  unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT];  int matchinv = 0;		/* Is match map inverted? */  unsigned char range_start = 0;  while ( (ch = *p++) && !bail ) {    switch ( state ) {    case st_normal:      if ( ch == '%' ) {	state = st_flags;	flags = 0; rank = rank_int; width = UINT_MAX;      } else if ( isspace((unsigned char)ch) ) {	q = skipspace(q);      } else {	if ( *q == ch )	  q++;	else	  bail = bail_err;	/* Match failure */      }      break;    case st_flags:      switch ( ch ) {      case '*':	flags |= FL_SPLAT;	break;      case '0' ... '9':	width = (ch-'0');	state = st_width;	flags |= FL_WIDTH;	break;      default:	state = st_modifiers;	p--;			/* Process this character again */	break;      }      break;    case st_width:      if ( ch >= '0' && ch <= '9' ) {	width = width*10+(ch-'0');      } else {	state = st_modifiers;	p--;			/* Process this character again */      }      break;    case st_modifiers:      switch ( ch ) {	/* Length modifiers - nonterminal sequences */      case 'h':	rank--;			/* Shorter rank */	break;      case 'l':	rank++;			/* Longer rank */	break;      case 'j':	rank = INTMAX_RANK;	break;      case 'z':	rank = SIZE_T_RANK;	break;      case 't':	rank = PTRDIFF_T_RANK;	break;      case 'L':      case 'q':	rank = rank_longlong;	/* long double/long long */	break;      default:	/* Output modifiers - terminal sequences */	state = st_normal;	/* Next state will be normal */	if ( rank < MIN_RANK )	/* Canonicalize rank */	  rank = MIN_RANK;	else if ( rank > MAX_RANK )	  rank = MAX_RANK;	switch ( ch ) {	case 'P':		/* Upper case pointer */	case 'p':		/* Pointer */#if 0	/* Enable this to allow null pointers by name */	  q = skipspace(q);	  if ( !isdigit((unsigned char)*q) ) {	    static const char * const nullnames[] =	    { "null", "nul", "nil", "(null)", "(nul)", "(nil)", 0 };	    const char * const *np;	    /* Check to see if it's a null pointer by name */	    for ( np = nullnames ; *np ; np++ ) {	      if ( !strncasecmp(q, *np, strlen(*np)) ) {		val = (uintmax_t)((void *)NULL);		goto set_integer;	      }	    }	    /* Failure */	    bail = bail_err;	    break;	  }	  /* else */#endif	  rank = rank_ptr;	  base = 0; sign = 0;	  goto scan_int;	case 'i':		/* Base-independent integer */	  base = 0; sign = 1;	  goto scan_int;	case 'd':		/* Decimal integer */	  base = 10; sign = 1;	  goto scan_int;	case 'o':		/* Octal integer */	  base = 8; sign = 0;	  goto scan_int;	case 'u':		/* Unsigned decimal integer */	  base = 10; sign = 0;	  goto scan_int;	  	case 'x':		/* Hexadecimal integer */	case 'X':	  base = 16; sign = 0;	  goto scan_int;	case 'n':		/* Number of characters consumed */	  val = (q-buffer);	  goto set_integer;	scan_int:	  q = skipspace(q);	  if ( !*q ) {	    bail = bail_eof;	    break;	  }	  val = strntoumax(q, (char **)&qq, base, width);	  if ( qq == q ) {	    bail = bail_err;	    break;	  }	  q = qq;	  converted++;	  /* fall through */	set_integer:	  if ( !(flags & FL_SPLAT) ) {	    switch(rank) {	    case rank_char:	      *va_arg(ap, unsigned char *) = (unsigned char)val;	      break;	    case rank_short:	      *va_arg(ap, unsigned short *) = (unsigned short)val;	      break;	    case rank_int:	      *va_arg(ap, unsigned int *) = (unsigned int)val;	      break;	    case rank_long:	      *va_arg(ap, unsigned long *) = (unsigned long)val;	      break;	    case rank_longlong:	      *va_arg(ap, unsigned long long *) = (unsigned long long)val;	      break;	    case rank_ptr:	      *va_arg(ap, void **) = (void *)(uintptr_t)val;	      break;	    }	  }	  break;	  	case 'c':               /* Character */          width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */          sarg = va_arg(ap, char *);          while ( width-- ) {            if ( !*q ) {              bail = bail_eof;              break;            }            *sarg++ = *q++;          }          if ( !bail )            converted++;          break;        case 's':               /* String */	  {	    char *sp;	    sp = sarg = va_arg(ap, char *);	    while ( width-- && *q && !isspace((unsigned char)*q) ) {	      *sp++ = *q++;	    }	    if ( sarg != sp ) {	      *sp = '\0';	/* Terminate output */	      converted++;	    } else {	      bail = bail_eof;	    }	  }	  break;	  	case '[':		/* Character range */	  sarg = va_arg(ap, char *);	  state = st_match_init;	  matchinv = 0;	  memset(matchmap, 0, sizeof matchmap);	  break;	case '%':		/* %% sequence */	  if ( *q == '%' )	    q++;	  else	    bail = bail_err;	  break;	default:		/* Anything else */	  bail = bail_err;	/* Unknown sequence */	  break;	}      }      break;        case st_match_init:		/* Initial state for %[ match */      if ( ch == '^' && !(flags & FL_INV) ) {	matchinv = 1;      } else {	set_bit(matchmap, (unsigned char)ch);	state = st_match;      }      break;          case st_match:		/* Main state for %[ match */      if ( ch == ']' ) {	goto match_run;      } else if ( ch == '-' ) {	range_start = (unsigned char)ch;	state = st_match_range;      } else {	set_bit(matchmap, (unsigned char)ch);      }      break;          case st_match_range:		/* %[ match after - */      if ( ch == ']' ) {	set_bit(matchmap, (unsigned char)'-'); /* - was last character */	goto match_run;      } else {	int i;	for ( i = range_start ; i < (unsigned char)ch ; i++ )	  set_bit(matchmap, i);	state = st_match;      }      break;    match_run:			/* Match expression finished */      qq = q;      while ( width && *q && test_bit(matchmap, (unsigned char)*q)^matchinv ) {	*sarg++ = *q++;      }      if ( q != qq ) {	*sarg = '\0';	converted++;      } else {	bail = *q ? bail_err : bail_eof;      }      break;    }  }  if ( bail == bail_eof && !converted )    converted = -1;		/* Return EOF (-1) */  return converted;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -