#include <stdio.h>
#include <ctype.h>
#include <string.h>

#ifdef _i386_
#define USE_FLOAT
#endif

#define SPC 1
#define STP 2
char _sctab[256] = {
	0,0,0,0,0,0,0,0,
	0,SPC,SPC,SPC,SPC,SPC,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	SPC,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
};

long double __xstrtod(FILE *fil, int count, int *ch) ;

char *__strtoone(FILE *fil, const char *format, void *arg, int *count,int *chars, int *ch)
{
	int ignore = 0;
	int width = 0;
	int size = 0;
	int sgn = 0;
   int skip=0,didit = 0;
   int type ;
	unsigned cu;
   char *s;
   int i,stop;
   int radix = 0 ;
	long double fval;
   long c ;

	if (*format == '*') {
		ignore = 1;
		format++;
	}
	if (isdigit(*format)) 
		while (isdigit(*format))
			width = width *10 + *format++ -'0';
   if (width == 0 )
      width = 30000 ;
   if (*format == 'h' || *format == 'l' || *format == 'L')
		size = *format++;
   type = *format++ ;
   if (type == 'D' || type == 'X' || type == 'I' || type == 'O' || type == 'U') {
     type |= 32 ;
     if (type != 'x' && size == 'l')
        size = 'L' ;
     else if (size != 'L')
        size = 'l' ;
   }
   switch((type)) {
		case 'c':
         if (width ==30000) width = 1;
         while(*ch != EOF && (_sctab[*ch] & SPC)) {
            (*chars)++;
            *ch = fgetc(fil) ;
         }
			while (width--) {
				(*chars)++;
            if (*ch == EOF)
					return 0;

				if (!ignore) {
               *((char *)arg)++ = (char)*ch;
				}		
            *ch = fgetc(fil) ;
			}
         if (!ignore) {
            (*count)++;
         }     
         break ;
		case 'd':
		case 'i':
      case 'u':
      case 'x':
      case 'p':
      case 'o':
			c = 0;
         while (*ch != EOF && (_sctab[*ch] & SPC)) {
            *ch = fgetc(fil) ;
            (*chars)++ ;
         }
         switch (type) {
            case 'd':
            case 'i':
            case 'u':
            default:
               radix = 0 ;
               break ;
            case 'x':
            case 'p':
               radix = 16 ;
               break ;
            case 'o':
               radix = 8 ;
               break ;
         }

			if (!skip) {
            if (*ch == '-') {
					sgn = 1;
					if (width)
						width--;
               *ch = fgetc(fil) ;
					(*chars)++;
				}
				else {
               if (*ch == '+') {
                  *ch = fgetc(fil) ;
						if (width)
                    width--;
						(*chars)++;
					}
				}
            if (*ch == '0') {
               *ch = fgetc(fil) ;
               if (width)
                  width-- ;
               if (!radix) {
                 radix = 8;
                 if (*ch == 'x' || *ch == 'X') {
                    radix = 16;
                    *ch = fgetc(fil) ;
                    if (width)
                      width-- ;
                 } else {
                  ungetc(*ch,fil) ;
                  *ch = '0' ;
                 }
               } else if (radix == 16 && (*ch == 'x' || *ch == 'X')) {
                  *ch = fgetc(fil) ;
                  if (width)
                    width-- ;
               } else {
                  ungetc(*ch,fil) ;
                  *ch = '0' ;
               }
            }
            if (!radix)
               radix = 10 ;
            while(width>0 && isxdigit(*ch)) {
               if (*ch >= 'a')
                  *ch -= 0x20 ;
               if (*ch >= 'A')
                  *ch = *ch - 'A' + 10 ;
               else
                  *ch = *ch - '0' ;
               if (*ch >= radix)
                  break ;
               didit = 1;
               width--;
               (*chars)++;
               c*=radix;
               c+= *ch;
               *ch = fgetc(fil) ;
            }
				if (sgn)
					c = -c;
			}
			if (!ignore) {
				(*count)+=didit;
            if (size == 'l' || size == 'L')
               *(long *)arg = c ;
            else if (size == 'h') 
					*(short *)arg = (short)c;
				else
               *(int *)arg = (int)c;
			}
			break;
		case 'e':
		case 'f':
		case 'g': 
#ifndef USE_FLOAT
				fprintf(stderr,"FP not linked");
#else
            fval = __xstrtod(fil,width,ch);
				if (!ignore) {
					(*count)++;
               if (size == 'L') 
                  *(long double *)arg = (long double) fval;
               else if (size == 'l')
                  *(double *)arg = (double)fval ;
					else
						*(float *)arg = (float) fval;
				}
#endif
			break;
		case 'n':
         if (size == 'l' || size == 'L')
            *(long *)arg = (*count)++ ;
         else if (size == 'h')
            *(short *)arg = (*count)++ ;
         else
            *(int *)arg = (*count)++;
			break;
      case '[': {
           int t = 0,c ;
           if (*format == '^') {
              t++ ;
              format++ ;
           }
           for (i=0; i < sizeof(_sctab); i++)
              if (t)
                 _sctab[i] &= ~STP ;
              else
                 _sctab[i] |= STP ;
           if (*format == ']' || *format == '-')
              _sctab[*format++] ^= STP ;
           while ((c = *format++) != ']' && c)  {
              if (c == '-' && *format != ']') {
                 for (i= *(format-2) ; i <= (*format); i++)
                    if (t)
                      _sctab[i] |= STP ;
                    else
                      _sctab[i] &= ~STP ;
                 format++ ;
              } else
                 if (t)
                   _sctab[c] |= STP ;
                 else
                   _sctab[c] &= ~STP ;

           }
         }
         if ( c== 0)
           format-- ;
         /* fall through */
		case 's':
         if (type == 's')
            stop = SPC ;
         else
            stop = STP ;
         while (*ch != EOF && (_sctab[*ch] & stop)) {
            *ch = fgetc(fil) ;
            (*chars)++ ;
         }
			s = (char *)arg;
         skip = width == 30000 ? 0 : 1;
         while (*ch != EOF && !(_sctab[*ch]& stop) && (width || !skip)) {
           if (!ignore)
             *s++ = *ch;
           *ch = fgetc(fil) ;
           width--;
           (*chars)++;
         }

         if (!ignore) {
           *s = 0;
           (*count) ++;
         }
         break;
		case '%':
            if (*ch != '%')
					return 0;
            *ch = fgetc(fil) ;
				break;
		default:
			format++;
	}
	return format;
}

int _scanf(FILE *fil, const char *xformat,void *arglist)
{
	int i = 0,j=0;
   int ch = fgetc(fil) ;
   while (xformat && *xformat && ch != EOF) {
      while (*xformat != '%' && *xformat) {
         if (_sctab[*xformat] & SPC) {
            while (ch != EOF && (_sctab[ch] & SPC))
               ch = fgetc(fil) ;
            while (*xformat && (_sctab[*++xformat] & SPC));
			}
			else  {
            if (*xformat++ != ch)
					return i;
            ch = fgetc(fil) ;
			}
		}
      if (*xformat && ch != EOF) {
         xformat++;
         xformat = __strtoone(fil,xformat,((char **)arglist)[i],&i,&j,&ch);
		}
	}
	return(i);
}
/* should have a const but const isn't working right... */

int scanf(const char *format, ...)
{
   return _scanf(stdin,format,((char *)&format+sizeof(char *)));
}

int vsscanf(char *buf, const char *format, void *list)
{
   int rv ;
   FILE fil ;
   memset(&fil,0,sizeof(fil)) ;
   fil.level = strlen(buf)+1 ;
   fil.flags = _F_IN | _F_READ | _F_BUFFEREDSTRING ;
   fil.bsize = strlen(buf) ;
   fil.buffer = fil.curp = buf ;
   fil.token = FILTOK ;
   return _scanf(&fil,format,list);
}
int sscanf(char *buf, const char *format, ...)
{
   return vsscanf(buf,format,(((char *)&format)+sizeof(char *)));
}
int fscanf(FILE *fil, const char *format, ...)
{
   return _scanf(fil,format,((char *)&format+sizeof(char *)));
}