98 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <ctype.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
/*
 | 
						|
 *  Returns the number of input items assigned. The value EOF is returned
 | 
						|
 *  if an input failure occurs before any conversion such as an end-of-file
 | 
						|
 *  occurs. If an error or end-of-file occurs after conversion has begun,
 | 
						|
 *  the number of conversions which were successfully completed is returned.
 | 
						|
 */
 | 
						|
 | 
						|
// XXX Only %d, %s, %c, whitespace and character matching, no flags except '*'
 | 
						|
 | 
						|
int vfscanf(FILE *stream, const char *format, va_list arg)
 | 
						|
{
 | 
						|
  int r = 0;                    // Number of conversions
 | 
						|
  int c = getc(stream);         // Look-ahead
 | 
						|
  int flags;
 | 
						|
  enum { star=1 };
 | 
						|
  int sign, n;
 | 
						|
  char *s;
 | 
						|
 | 
						|
  for (; c>=0 && *format; format++) {
 | 
						|
    switch (*format) {
 | 
						|
    case ' ': case '\t':        // Whitespace is ignored
 | 
						|
      continue;
 | 
						|
    case '%':
 | 
						|
      flags = 0;
 | 
						|
      format++;
 | 
						|
      if (*format == '*') {     // Flag to suppress assignment
 | 
						|
        flags |= star;
 | 
						|
        format++;
 | 
						|
      }
 | 
						|
      switch (*format) {
 | 
						|
      case 'd':                 // Decimal %d
 | 
						|
      case 'u':                 // Unsigned works due to unchecked overflows
 | 
						|
        while (isspace(c))
 | 
						|
          c = getc(stream);
 | 
						|
        sign = c;
 | 
						|
        if (c == '-' || c == '+')
 | 
						|
          c = getc(stream);
 | 
						|
        if (!isdigit(c))
 | 
						|
          goto stop;            // Break out of switch+switch+for...
 | 
						|
        n = 0;
 | 
						|
        do {
 | 
						|
          n = n * 10 + c - '0';
 | 
						|
          c = getc(stream);
 | 
						|
        } while (isdigit(c));
 | 
						|
        if ((flags & star) == 0) {
 | 
						|
          *va_arg(arg, int*) = (sign == '-') ? -n : n;
 | 
						|
          r++;
 | 
						|
        }
 | 
						|
        continue;
 | 
						|
      case 's':                 // String %s
 | 
						|
        s = va_arg(arg, char*);
 | 
						|
        while (isspace(c))
 | 
						|
          c = getc(stream);
 | 
						|
        while (c>=0 && !isspace(c)) {
 | 
						|
          if ((flags & star) == 0)
 | 
						|
            *s++ = c;
 | 
						|
          c = getc(stream);
 | 
						|
        }
 | 
						|
        if ((flags & star) == 0) {
 | 
						|
          *s = 0;
 | 
						|
          r++;
 | 
						|
        }
 | 
						|
        continue;
 | 
						|
      case 'c':                 // Character %c
 | 
						|
        s = va_arg(arg, char*);
 | 
						|
        if ((flags & star) == 0) {
 | 
						|
          *s = c;
 | 
						|
          r++;
 | 
						|
        }
 | 
						|
        c = getc(stream);
 | 
						|
        continue;
 | 
						|
      default:                  // Also handles %% by fall through below
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      // !!! Fall through !!!
 | 
						|
    default:
 | 
						|
      while (isspace(c))
 | 
						|
        c = getc(stream);
 | 
						|
      if (c == *format) {       // Matching character
 | 
						|
        c = getc(stream);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    break; // Unable to continue processing
 | 
						|
  }
 | 
						|
 | 
						|
stop:
 | 
						|
  if (ungetc(c,stream)<0 && r==0)// Push back the look-ahead
 | 
						|
    return EOF;                 // Error before first conversion
 | 
						|
  else
 | 
						|
    return r;                   // Number of conversions
 | 
						|
}
 |