/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
   USA

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <locale.h>
#include "libp.h"
#include <limits.h>
#include <float.h>

#ifdef _i386_
#define USE_FLOAT
#endif

#define STP 1

char *__strtoone(FILE *restrict fil, const char *restrict format, void *restrict arg, int *restrict count,int *restrict chars, int *restrict ch)
{
    LLONG_TYPE max=INT_MAX,min= INT_MIN;
	int ignore = 0;
	int width = INT_MAX;
	int size = 0;
	int sgn = 0;
   int skip=0,didit = 0;
   int type ;
	unsigned cu;
   char *s;
   int i;
   int radix = 0 ;
   int lc = 0x20 ;
	long double fval;
   LLONG_TYPE c ;
   wchar_t fbuf[40];
   char _sctab[256] ;
   mbstate_t st;
	int found = 0;
	
	if (*format == '*') {
		ignore = 1;
		format++;
	}
	if (isdigit(*format))  {
      width = 0;
      while (isdigit(*format))
			width = width *10 + *format++ -'0';
    }
   if (*format == 'h' || *format == 'l') {
		size = *format++;
      if (size == 'h') {
        max = SHRT_MAX;
        min = SHRT_MIN;
        if (*format == 'h') {
            max = CHAR_MAX;
            min = CHAR_MIN;
            size = 'c';
            format++;
        }
      } else if (*format == 'l') {
         max = LLONG_MAX;
         min = LLONG_MIN;
         size = '1' ;
         format++ ;
      }
   }
   else if (*format == 'L')
    size = *format++;
   else if (*format == 'z' || *format == 't')
    format++;
   else if (*format == 'j') {
    size = '1';
    format++;
   }

   type = *format++ ;
   if (isalpha(type) && !(type & 0x20)) {
     lc = 0;
     type |= 0x20;
   }
   switch((type)) {
		case 'c':
            if (size == 'l') {
                memset(&st,0,sizeof(st));
                while (width >= 0 && *ch) {
                    int l ;
                    l = mbrtowc(fbuf,ch,1,&st);
                    width--;
                    if (l == (size_t) -1) {
                        break;
                    } else if (l > 0 && !ignore) {
                        *((wchar_t *)arg)++ = fbuf[0];
                    }
                    (*chars)++ ;
                    *ch = fgetc(fil);
                }
            }
			else {
              if (width == INT_MAX) 
                width = 1;
              while (width--) {
				(*chars)++;
                if (*ch == EOF)
					return EOF;

				if (!ignore) {
                   *((char *)arg)++ = (char)*ch;
				}		
                *ch = fgetc(fil) ;
              }
			}
         if (!ignore) {
            (*count)++;
         }     
         break ;
		case 'd':
        case 'u':
        case 'x':
        case 'o':
        case 'i':
        case 'p':
         while (*ch != EOF && isspace(*ch)) {
            *ch = fgetc(fil) ;
            (*chars)++ ;
         }
		 if (!isdigit(*ch) && *ch != '-' && *ch != '+')
			 return NULL;
         switch(type) {
            case 'd':
                 c = __xstrtoimax(fil,width,ch,chars,10,max,0, STRT_ERR_RET_SIGNED);
                 break;
            case 'i':
                 c = __xstrtoimax(fil,width,ch,chars,0,max,0, STRT_ERR_RET_SIGNED);
                 break;
            case 'u':
                 c = __xstrtoimax(fil,width,ch,chars,10,max,0, STRT_ERR_RET_UNSIGNED);
                 break;
            case 'x':
            case 'p':
                 c = __xstrtoimax(fil,width,ch,chars,16,max,0, STRT_ERR_RET_UNSIGNED);
                 break;
            case 'o':
                 c = __xstrtoimax(fil,width,ch,chars,8,max,0, STRT_ERR_RET_UNSIGNED);
                 break;
         }
            if (!ignore) {
                (*count)++;
                if (size == '1')
                   *(LLONG_TYPE *)arg = c ;
                else if (size == 'l' || size == 'L')
                   *(long *)arg = c ;
                else if (size == 'h') 
    					*(short *)arg = (short)c;
                    else if (size == 'c')
                        *(char *)arg = (char)c;
    				else
                   *(int *)arg = (int)c;
    	    }
         break ;
		case 'e':
		case 'f':
		case 'g': 
        case 'a':
#ifndef USE_FLOAT
				fprintf(stderr,"FP not linked");
#else
		         while (*ch != EOF && isspace(*ch)) {
		            *ch = fgetc(fil) ;
		            (*chars)++ ;
		         }
			 if (!isdigit(*ch) && *ch != '-' && *ch != '+' && *ch != '.')
				 return NULL;
				if (!ignore) {
					(*count)++;
               if (size == 'l') 
                  *(double *)arg = 
                        __xstrtod(fil,width,ch,chars, DBL_MAX, DBL_MAX_EXP, DBL_MAX_10_EXP,0);
               else 
                    *(float *)arg = 
                        __xstrtod(fil,width,ch,chars, FLT_MAX, FLT_MAX_EXP, FLT_MAX_10_EXP,0);
				}
#endif
			break;
		case 'n':
         if (!ignore) {
             if (size == '1') {
                *(LLONG_TYPE *)arg = (*chars) ;
             } else if (size == 'l' || size == 'L')
                *(long *)arg = (*chars) ;
             else if (size == 'h')
                *(short *)arg = (*chars) ;
             else if (size == 'c')
                *(char *)arg = (*chars) ;
             else
                *(int *)arg = (*chars);
         }
	     break;
      case '[': {
           int t = 0,c ;
           if (*format == '^') {
              t++ ;
              format++ ;
           }
           for (i=0; i < sizeof(_sctab); i++) {
              _sctab[i] =  t ? 0 : STP;
           }
           while (*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[(unsigned char)c] |= STP ;
                 else
                   _sctab[(unsigned char)c] &= ~STP ;

           }
           if ( c== 0)
             format-- ;
         }
         /* fall through */
		case 's':
         if (type == 's') {
            for (i=0; i < sizeof(_sctab); i++) {
                _sctab[i] = isspace(i) ? STP : 0;
            }
         } 
         while (type == 's' && *ch != EOF && (_sctab[*ch] & STP)) {
            *ch = fgetc(fil) ;
            (*chars)++ ;
			found=1;
         }
			s = (char *)arg;
         skip = width == INT_MAX ? 0 : 1;
         memset(&st,0,sizeof(st));
         while (*ch != EOF && !(_sctab[*ch]& STP) && (width || !skip)) {
            if (size == 'l') {
                    int l ;
                    l = mbrtowc(fbuf,ch,1,&st);
                    if (l == (size_t) -1) {
                        break;
                    } else if (l > 0 && !ignore) {
                        *((wchar_t *)arg)++ = fbuf[0];
                    }
                    width--;
                    (*chars)++;
					found=1;
                    *ch = fgetc(fil);
            } else {
               if (!ignore)
                 *s++ = *ch;
               *ch = fgetc(fil) ;
               width--;
               (*chars)++;
				found=1;
            }
         }

         if (!ignore) {
            if (size == 'l')
                *(wchar_t *)arg = L'\0';
            else
                *s = 0;
			if (found)
	           (*count) ++;
         }
         break;
		case '%':
            if (*ch != '%')
					return 0;
            *ch = fgetc(fil) ;
				break;
		default:
			format++;
	}
	return format;
}

int __scanf(FILE *restrict fil, const char *restrict format,void *restrict arglist)
{
   int i = 0,j=0;
   int ch = fgetc(fil) ;
   while (format && *format && ch != EOF) {
      while (format && *format != '%' && *format) {
        if (isspace(*format)) {
            while (ch != EOF && isspace(ch)) {
               ch = fgetc(fil) ;
               j++ ;
            }
            while (*format && isspace(*format)) format++;
		}
		else  {
            if (*format++ != ch) {
                if (ch != EOF)
                    ungetc(ch,fil);
                return i;
            }
            ch = fgetc(fil) ;
            j++;
		}
	  }
      if (*format && ch != EOF) {
	      format++;
          format = __strtoone(fil,format,((char **)arglist)[i],&i,&j,&ch);
	  }
	}
    if (ch != EOF)
        ungetc(ch,fil);
    return(i);
}


