1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	The main engine for reading formatted data
25**
26**	Written by Kiem-Phong Vo.
27*/
28
29#define MAXWIDTH	(int)(((uint)~0)>>1)	/* max amount to scan	*/
30
31/*
32 * pull in a private strtold()
33 */
34
35#include "sfstrtof.h"
36
37/* refresh stream buffer - taking care of unseekable/share streams too */
38#if __STD_C
39static void _sfbuf(Sfio_t* f, int* peek)
40#else
41static void _sfbuf(f, peek)
42Sfio_t*	f;
43int*	peek;
44#endif
45{
46	if(f->next >= f->endb)
47	{	if(*peek) 	/* try peeking for a share stream if possible */
48		{	f->mode |= SF_RV;
49			if(SFFILBUF(f,-1) > 0)
50			{	f->mode |= SF_PEEK;
51				return;
52			}
53			*peek = 0;	/* can't peek, back to normal reads */
54		}
55		(void)SFFILBUF(f,-1);
56	}
57}
58
59/* buffer used during scanning of a double value or a multi-byte
60   character. the fields mirror certain local variables in sfvscanf.  */
61typedef struct _scan_s
62{	int	error;	/* get set by _sfdscan if no value specified	*/
63	int	inp;	/* last input character read			*/
64	int	width;	/* field width					*/
65	Sfio_t	*f;	/* stream being scanned				*/
66	uchar	*d, *endd, *data;	/* local buffering system	*/
67	int	peek;	/* != 0 if unseekable/share stream		*/
68	int	n_input;/* number of input bytes processed		*/
69} Scan_t;
70
71/* ds != 0 for scanning double values */
72#define SCinit(sc,ds)	((sc)->inp = (sc)->error = -1, (sc)->f = f, \
73			 ((sc)->width = (ds) ? width : -1), \
74			 (sc)->d = d, (sc)->endd = endd, (sc)->data = data, \
75			 (sc)->peek = peek, (sc)->n_input = n_input)
76#define SCend(sc,ds)	(inp = (sc)->inp, f = (sc)->f, \
77			 (width = (ds) ? (sc)->width : width), \
78			 d = (sc)->d, endd = (sc)->endd, data = (sc)->data, \
79			 peek = (sc)->peek, n_input = (sc)->n_input)
80
81#if __STD_C
82static int _scgetc(void* arg, int flag)
83#else
84static int _scgetc(arg, flag)
85void*	arg;
86int	flag;
87#endif
88{
89	Scan_t	*sc = (Scan_t*)arg;
90
91	if (flag)
92	{	sc->error = flag;
93		return 0;
94	}
95
96	/* if width >= 0, do not allow to exceed width number of bytes */
97	if(sc->width == 0)
98	{	sc->inp = -1;
99		return 0;
100	}
101
102	if(sc->d >= sc->endd) /* refresh local buffer */
103	{	sc->n_input += sc->d - sc->data;
104		if(sc->peek)
105			SFREAD(sc->f, sc->data, sc->d - sc->data);
106		else	sc->f->next = sc->d;
107
108		_sfbuf(sc->f, &sc->peek);
109		sc->data = sc->d = sc->f->next;
110		sc->endd = sc->f->endb;
111
112		if(sc->d >= sc->endd)
113		{	sc->inp = -1;
114			return 0;
115		}
116	}
117
118	if((sc->width -= 1) >= 0) /* from _sfdscan */
119		return (sc->inp = (int)(*sc->d++));
120	else	return ((int)(*sc->d++));
121}
122
123/* structure to match characters in a character class */
124typedef struct _accept_s
125{	char	ok[SF_MAXCHAR+1];
126	int	yes;
127	char	*form, *endf;
128#if _has_multibyte
129	wchar_t	wc;
130#endif
131} Accept_t;
132
133#if __STD_C
134static char* _sfsetclass(const char* form, Accept_t* ac, int flags)
135#else
136static char* _sfsetclass(form, ac, flags)
137char*		form;	/* format string			*/
138Accept_t*	ac;	/* values of accepted characters	*/
139int		flags;	/* SFFMT_LONG for wchar_t		*/
140#endif
141{
142	int		c, endc, n;
143#if _has_multibyte
144	SFMBDCL(mbs)
145#endif
146
147	if(*form == '^') /* complementing this set */
148	{	ac->yes = 0;
149		form += 1;
150	}
151	else	ac->yes = 1;
152
153	for(c = 0; c <= SF_MAXCHAR; ++c)
154		ac->ok[c] = !ac->yes;
155
156	if(*form == ']' || *form == '-') /* special first char */
157	{	ac->ok[*form] = ac->yes;
158		form += 1;
159	}
160	ac->form = (char*)form;
161
162	if(flags&SFFMT_LONG)
163		SFMBCLR(&mbs);
164	for(n = 1; *form != ']'; form += n)
165	{	if((c = *((uchar*)form)) == 0)
166			return NIL(char*);
167
168		if(*(form+1) == '-')
169		{	endc = *((uchar*)(form+2));
170#if _has_multibyte
171			if(c >= 128 || endc >= 128 ) /* range must be ascii */
172				goto one_char;
173#endif
174			for(; c <= endc; ++c)
175				ac->ok[c] = ac->yes;
176			n = 3;
177		}
178		else
179		{ one_char:
180#if _has_multibyte /* true multi-byte chars must be checked differently */
181			if((flags&SFFMT_LONG) && (n = (int)SFMBLEN(form,&mbs)) <= 0)
182				return NIL(char*);
183			if(n == 1)
184#endif
185				ac->ok[c] = ac->yes;
186		}
187	}
188
189	ac->endf = (char*)form;
190	return (char*)(form+1);
191}
192
193#if _has_multibyte
194#if __STD_C
195static int _sfwaccept(wchar_t wc, Accept_t* ac)
196#else
197static int _sfwaccept(wc, ac)
198wchar_t		wc;
199Accept_t*	ac;
200#endif
201{
202	int		endc, c, n;
203	wchar_t		fwc;
204	char		*form = ac->form;
205	SFMBDCL(mbs)
206
207	SFMBCLR(&mbs);
208	for(n = 1; *form != ']'; form += n)
209	{	if((c = *((uchar*)form)) == 0)
210			return 0;
211
212		if(*(form+1) == '-')
213		{	endc = *((uchar*)(form+2));
214			if(c >= 128 || endc >= 128 ) /* range must be ascii */
215				goto one_char;
216			n = 3;
217		}
218		else
219		{ one_char:
220			if((n = mbrtowc(&fwc, form, ac->endf-form, &mbs)) > 1 &&
221			   wc == fwc )
222				return ac->yes;
223		}
224	}
225
226	return !ac->yes;
227}
228
229#if _has_multibyte == 1
230#define SFgetwc(sc,wc,fmt,ac,mbs)	_sfgetwc(sc,wc,fmt,ac,(Void_t*)(mbs))
231#else
232#define SFgetwc(sc,wc,fmt,ac,mbs)	_sfgetwc(sc,wc,fmt,ac,NIL(Void_t*))
233#endif
234
235#if __STD_C
236static int _sfgetwc(Scan_t* sc, wchar_t* wc, int fmt, Accept_t* ac, Void_t *mbs)
237#else
238static int _sfgetwc(sc, wc, fmt, ac, mbs)
239Scan_t*		sc;	/* the scanning handle		*/
240wchar_t*	wc;	/* to return a scanned wchar_t	*/
241int		fmt;	/* %s, %c, %[			*/
242Accept_t*	ac;	/* accept handle for %[		*/
243Void_t*		mbs;	/* multibyte parsing state	*/
244#endif
245{
246	int	n, v;
247	char	b[16]; /* assuming that SFMBMAX <= 16! */
248
249	/* shift left data so that there will be more room to back up on error.
250	   this won't help streams with small buffers - c'est la vie! */
251	if(sc->d > sc->f->data && (n = sc->endd - sc->d) > 0 && n < SFMBMAX)
252	{	memcpy(sc->f->data, sc->d, n);
253		if(sc->f->endr == sc->f->endb)
254			sc->f->endr = sc->f->data+n;
255		if(sc->f->endw == sc->f->endb)
256			sc->f->endw = sc->f->data+n;
257		sc->f->endb = sc->f->data+n;
258		sc->d = sc->data = sc->f->data;
259		sc->endd = sc->f->endb;
260		if(!mbs) sc->f->endb = sc->endd; /* stop cc's "unused mbs" warning */
261	}
262
263	for(n = 0; n < SFMBMAX; )
264	{	if((v = _scgetc((Void_t*)sc, 0)) <= 0)
265			goto no_match;
266		else	b[n++] = v;
267
268		if(mbrtowc(wc, b, n, (mbstate_t*)mbs) == (size_t)(-1))
269			goto no_match;  /* malformed multi-byte char */
270		else
271		{	/* multi-byte char converted successfully */
272			if(fmt == 'c')
273				return 1;
274			else if(fmt == 's')
275			{	if(n > 1 || (n == 1 && !isspace(b[0]) ) )
276					return 1;
277				else	goto no_match;
278			}
279			else if(fmt == '[')
280			{	if((n == 1 && ac->ok[b[0]]) ||
281				   (n  > 1 && _sfwaccept(*wc,ac)) )
282					return 1;
283				else	goto no_match;
284			}
285			else /* if(fmt == '1') match a single wchar_t */
286			{	if(*wc == ac->wc)
287					return 1;
288				else	goto no_match;
289			}
290		}
291	}
292
293no_match: /* this unget is lossy on a stream with small buffer */
294	if((sc->d -= n) < sc->data)
295		sc->d = sc->data;
296	return 0;
297}
298#endif /*_has_multibyte*/
299
300
301#if __STD_C
302int sfvscanf(Sfio_t* f, reg const char* form, va_list args)
303#else
304int sfvscanf(f,form,args)
305Sfio_t*		f;		/* file to be scanned */
306reg char*	form;		/* scanning format */
307va_list		args;
308#endif
309{
310	reg int		inp, shift, base, width;
311	ssize_t		size;
312	int		fmt, flags, dot, n_assign, v, n, n_input;
313	char		*sp;
314
315	Accept_t	acc;
316
317	Argv_t		argv;
318	Sffmt_t		*ft;
319	Fmt_t		*fm, *fmstk;
320
321	Fmtpos_t*	fp;
322	char		*oform;
323	va_list		oargs;
324	int		argp, argn;
325
326	int		decimal = 0, thousand = 0;
327
328#if _has_multibyte
329	wchar_t		wc;
330	SFMBDCL(fmbs)
331	SFMBDCL(mbs)
332#endif
333
334	Void_t*		value;	/* location to assign scanned value */
335	char*		t_str;
336	ssize_t		n_str;
337
338	/* local buffering system */
339	Scan_t		scd;
340	uchar		*d, *endd, *data;
341	int		peek;
342#define SFbuf(f)	(_sfbuf(f,&peek), (data = d = f->next), (endd = f->endb) )
343#define SFlen(f)	(d - data)
344#define SFinit(f)	((peek = f->extent < 0 && (f->flags&SF_SHARE)), SFbuf(f) )
345#define SFend(f)	((n_input += SFlen(f)), \
346			 (peek ? SFREAD(f,(Void_t*)data,SFlen(f)) : ((f->next = d),0)) )
347#define SFgetc(f,c)	((c) = (d < endd || (SFend(f), SFbuf(f), d < endd)) ? \
348				(int)(*d++) : -1 )
349#define SFungetc(f,c)	(d -= 1)
350
351	SFMTXDECL(f);
352
353	SFCVINIT();	/* initialize conversion tables */
354
355	SFMTXENTER(f,-1);
356
357	if(!form || f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0)
358		SFMTXRETURN(f, -1);
359	SFLOCK(f,0);
360
361	SFinit(f); /* initialize local buffering system */
362
363	n_assign = n_input = 0; inp = -1;
364
365	fmstk = NIL(Fmt_t*);
366	ft = NIL(Sffmt_t*);
367
368	fp = NIL(Fmtpos_t*);
369	argn = -1;
370	oform = (char*)form;
371	va_copy(oargs,args);
372
373	SFSETLOCALE(&decimal, &thousand);
374
375loop_fmt:
376	SFMBCLR(&fmbs);
377	while((fmt = *form++))
378	{	if(fmt != '%')
379		{	if(isspace(fmt))
380			{	if(fmt != '\n' || !(f->flags&SF_LINE))
381					fmt = -1;
382				for(;;)
383				{	if(SFgetc(f,inp) < 0 || inp == fmt)
384						goto loop_fmt;
385					else if(!isspace(inp))
386					{	SFungetc(f,inp);
387						goto loop_fmt;
388					}
389				}
390			}
391			else
392			{ match_1:
393#if _has_multibyte
394				if((n = (int)mbrtowc(&wc,form-1,SFMBMAX,&fmbs)) <= 0)
395					goto pop_fmt;
396				if(n > 1)
397				{	acc.wc = wc;
398					SCinit(&scd,0); SFMBCLR(&mbs);
399					v = SFgetwc(&scd, &wc, '1', &acc, &mbs);
400					SCend(&scd,0);
401					if(v == 0)
402						goto pop_fmt;
403					form += n-1;
404				}
405				else
406#endif
407				if(SFgetc(f,inp) != fmt)
408				{	if(inp < 0)
409						goto done;
410					SFungetc(f,inp);
411					goto pop_fmt;
412				}
413			}
414			continue;
415		}
416
417		if(*form == '%')
418		{	form += 1;
419			do SFgetc(f,inp); while(isspace(inp)); /* skip starting blanks */
420			SFungetc(f,inp);
421			goto match_1;
422		}
423
424		if(*form == '\0')
425			goto pop_fmt;
426
427		if(*form == '*')
428		{	flags = SFFMT_SKIP;
429			form += 1;
430		}
431		else	flags = 0;
432
433		/* matching some pattern */
434		base = 10; size = -1;
435		width = dot = 0;
436		t_str = NIL(char*); n_str = 0;
437		value = NIL(Void_t*);
438		argp = -1;
439
440	loop_flags:	/* LOOP FOR FLAGS, WIDTH, BASE, TYPE */
441		switch((fmt = *form++) )
442		{
443		case LEFTP : /* get the type which is enclosed in balanced () */
444			t_str = (char*)form;
445			for(v = 1;;)
446			{	switch(*form++)
447				{
448				case 0 :	/* not balanceable, retract */
449					form = t_str;
450					t_str = NIL(char*);
451					n_str = 0;
452					goto loop_flags;
453				case LEFTP :	/* increasing nested level */
454					v += 1;
455					continue;
456				case RIGHTP :	/* decreasing nested level */
457					if((v -= 1) != 0)
458						continue;
459					if(*t_str != '*' )
460						n_str = (form-1) - t_str;
461					else
462					{	t_str = (*_Sffmtintf)(t_str+1,&n);
463						if(*t_str == '$')
464						{	if(!fp &&
465							   !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
466								goto pop_fmt;
467							n = FP_SET(n,argn);
468						}
469						else	n = FP_SET(-1,argn);
470
471						if(fp)
472						{	t_str = fp[n].argv.s;
473							n_str = fp[n].ft.size;
474						}
475						else if(ft && ft->extf )
476						{	FMTSET(ft, form,args,
477								LEFTP, 0, 0, 0,0,0,
478								NIL(char*),0);
479							n = (*ft->extf)
480							      (f,(Void_t*)&argv,ft);
481							if(n < 0)
482								goto pop_fmt;
483							if(!(ft->flags&SFFMT_VALUE) )
484								goto t_arg;
485							if((t_str = argv.s) &&
486							   (n_str = (int)ft->size) < 0)
487								n_str = strlen(t_str);
488						}
489						else
490						{ t_arg:
491							if((t_str = va_arg(args,char*)) )
492								n_str = strlen(t_str);
493						}
494					}
495					goto loop_flags;
496				}
497			}
498
499		case '#' : /* alternative format */
500			flags |= SFFMT_ALTER;
501			goto loop_flags;
502
503		case '.' : /* width & base */
504			dot += 1;
505			if(isdigit(*form))
506			{	fmt = *form++;
507				goto dot_size;
508			}
509			else if(*form == '*')
510			{	form = (*_Sffmtintf)(form+1,&n);
511				if(*form == '$')
512				{	form += 1;
513					if(!fp &&
514					   !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
515						goto pop_fmt;
516					n = FP_SET(n,argn);
517				}
518				else	n = FP_SET(-1,argn);
519
520				if(fp)
521					v = fp[n].argv.i;
522				else if(ft && ft->extf )
523				{	FMTSET(ft, form,args, '.',dot, 0, 0,0,0,
524						NIL(char*), 0);
525					if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0)
526						goto pop_fmt;
527					if(ft->flags&SFFMT_VALUE)
528						v = argv.i;
529					else	v = (dot <= 2) ? va_arg(args,int) : 0;
530				}
531				else	v = (dot <= 2) ? va_arg(args,int) : 0;
532				if(v < 0)
533					v = 0;
534				goto dot_set;
535			}
536			else	goto loop_flags;
537
538		case '0' : case '1' : case '2' : case '3' : case '4' :
539		case '5' : case '6' : case '7' : case '8' : case '9' :
540		dot_size :
541			for(v = fmt-'0'; isdigit(*form); ++form)
542				v = v*10 + (*form - '0');
543
544			if(*form == '$')
545			{	form += 1;
546				if(!fp && !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)) )
547					goto pop_fmt;
548				argp = v-1;
549				goto loop_flags;
550			}
551
552		dot_set :
553			if(dot == 0 || dot == 1)
554				width = v;
555			else if(dot == 2)
556				base = v;
557			goto loop_flags;
558
559		case 'I' : /* object size */
560			size = -1; flags = (flags & ~SFFMT_TYPES) | SFFMT_IFLAG;
561			if(isdigit(*form))
562			{	for(size = 0, n = *form; isdigit(n); n = *++form)
563					size = size*10 + (n - '0');
564			}
565			else if(*form == '*')
566			{	form = (*_Sffmtintf)(form+1,&n);
567				if(*form == '$')
568				{	form += 1;
569					if(!fp &&
570					   !(fp = (*_Sffmtposf)(f,oform,oargs,ft,1)))
571						goto pop_fmt;
572					n = FP_SET(n,argn);
573				}
574				else	n = FP_SET(-1,argn);
575
576				if(fp)	/* use position list */
577					size = fp[n].argv.i;
578				else if(ft && ft->extf )
579				{	FMTSET(ft, form,args, 'I',sizeof(int), 0, 0,0,0,
580						NIL(char*), 0);
581					if((*ft->extf)(f, (Void_t*)(&argv), ft) < 0)
582						goto pop_fmt;
583					if(ft->flags&SFFMT_VALUE)
584						size = argv.i;
585					else	size = va_arg(args,int);
586				}
587				else	size = va_arg(args,int);
588			}
589			goto loop_flags;
590
591		case 'l' :
592			size = -1; flags &= ~SFFMT_TYPES;
593			if(*form == 'l')
594			{	form += 1;
595				flags |= SFFMT_LLONG;
596			}
597			else	flags |= SFFMT_LONG;
598			goto loop_flags;
599		case 'h' :
600			size = -1; flags &= ~SFFMT_TYPES;
601			if(*form == 'h')
602			{	form += 1;
603				flags |= SFFMT_SSHORT;
604			}
605			else	flags |= SFFMT_SHORT;
606			goto loop_flags;
607		case 'L' :
608			size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_LDOUBLE;
609			goto loop_flags;
610		case 'j' :
611			size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_JFLAG;
612			goto loop_flags;
613		case 'z' :
614			size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_ZFLAG;
615			goto loop_flags;
616		case 't' :
617			size = -1; flags = (flags&~SFFMT_TYPES) | SFFMT_TFLAG;
618			goto loop_flags;
619		case QUOTE :
620			if(thousand > 0)
621				flags |= SFFMT_THOUSAND;
622			goto loop_flags;
623		}
624
625		/* set object size for scalars */
626		if(flags & SFFMT_TYPES)
627		{	if((_Sftype[fmt]&(SFFMT_INT|SFFMT_UINT)) || fmt == 'n')
628			{	if(flags&SFFMT_LONG)
629					size = sizeof(long);
630				else if(flags&SFFMT_SHORT)
631					size = sizeof(short);
632				else if(flags&SFFMT_SSHORT)
633					size = sizeof(char);
634				else if(flags&SFFMT_TFLAG)
635					size = sizeof(ptrdiff_t);
636				else if(flags&SFFMT_ZFLAG)
637					size = sizeof(size_t);
638				else if(flags&(SFFMT_LLONG|SFFMT_JFLAG) )
639					size = sizeof(Sflong_t);
640				else if(flags&SFFMT_IFLAG)
641				{	if(size <= 0 ||
642					   size == sizeof(Sflong_t)*CHAR_BIT )
643						size = sizeof(Sflong_t);
644				}
645				else if(size < 0)
646					size = sizeof(int);
647			}
648			else if(_Sftype[fmt]&SFFMT_FLOAT)
649			{	if(flags&(SFFMT_LONG|SFFMT_LLONG))
650					size = sizeof(double);
651				else if(flags&SFFMT_LDOUBLE)
652					size = sizeof(Sfdouble_t);
653				else if(flags&SFFMT_IFLAG)
654				{	if(size <= 0)
655						size = sizeof(Sfdouble_t);
656				}
657				else if(size < 0)
658					size = sizeof(float);
659			}
660			else if(_Sftype[fmt]&SFFMT_CHAR)
661			{
662#if _has_multibyte
663				if((flags&SFFMT_LONG) || fmt == 'C')
664				{	size = sizeof(wchar_t) > sizeof(int) ?
665						sizeof(wchar_t) : sizeof(int);
666				} else
667#endif
668				if(size < 0)
669					size = sizeof(int);
670			}
671		}
672
673		argp = FP_SET(argp,argn);
674		if(fp)
675		{	if(!(fp[argp].ft.flags&SFFMT_SKIP) )
676			{	n_assign += 1;
677				value = fp[argp].argv.vp;
678				size = fp[argp].ft.size;
679				if(ft && ft->extf && fp[argp].ft.fmt != fp[argp].fmt)
680					fmt = fp[argp].ft.fmt;
681			}
682			else	flags |= SFFMT_SKIP;
683		}
684		else if(ft && ft->extf)
685		{	FMTSET(ft, form,args, fmt, size,flags, width,0,base, t_str,n_str);
686			SFend(f); SFOPEN(f,0);
687			v = (*ft->extf)(f, (Void_t*)&argv, ft);
688			SFLOCK(f,0); SFbuf(f);
689
690			if(v < 0)
691				goto pop_fmt;
692			else if(v > 0) /* extf comsumed v input bytes */
693			{	n_input += v;
694				if(!(ft->flags&SFFMT_SKIP) )
695					n_assign += 1;
696				continue;
697			}
698			else /* if(v == 0): extf did not use input stream */
699			{	FMTGET(ft, form,args, fmt, size, flags, width,n,base);
700
701				if((ft->flags&SFFMT_VALUE) && !(ft->flags&SFFMT_SKIP) )
702					value = argv.vp;
703			}
704		}
705
706		if(_Sftype[fmt] == 0) /* unknown pattern */
707			goto pop_fmt;
708
709		if(fmt == '!')
710		{	if(!fp)
711				fp = (*_Sffmtposf)(f,oform,oargs,ft,1);
712			else	goto pop_fmt;
713
714			if(!(argv.ft = va_arg(args,Sffmt_t*)) )
715				continue;
716			if(!argv.ft->form && ft ) /* change extension functions */
717			{	if(ft->eventf &&
718				   (*ft->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0)
719					continue;
720				fmstk->ft = ft = argv.ft;
721			}
722			else			/* stack a new environment */
723			{	if(!(fm = (Fmt_t*)malloc(sizeof(Fmt_t))) )
724					goto done;
725
726				ft = fm->ft = argv.ft;
727				SFMBSET(ft->mbs, &fmbs);
728				if(ft->form)
729				{	fm->form = (char*)form; SFMBCPY(&fm->mbs,&fmbs);
730					va_copy(fm->args,args);
731
732					fm->oform = oform;
733					va_copy(fm->oargs,oargs);
734					fm->argn = argn;
735					fm->fp = fp;
736
737					form = ft->form; SFMBCLR(ft->mbs);
738					va_copy(args,ft->args);
739					argn = -1;
740					fp = NIL(Fmtpos_t*);
741					oform = (char*)form;
742					va_copy(oargs,args);
743				}
744				else	fm->form = NIL(char*);
745
746				fm->eventf = ft->eventf;
747				fm->next = fmstk;
748				fmstk = fm;
749			}
750			continue;
751		}
752
753		/* get the address to assign value */
754		if(!value && !(flags&SFFMT_SKIP) )
755			value = va_arg(args,Void_t*);
756
757		if(fmt == 'n') /* return length of consumed input */
758		{
759#if !_ast_intmax_long
760			if(size == sizeof(Sflong_t) )
761				*((Sflong_t*)value) = (Sflong_t)(n_input+SFlen(f));
762			else
763#endif
764			if(size == sizeof(long) )
765				*((long*)value) = (long)(n_input+SFlen(f));
766			else if(size == sizeof(short) )
767				*((short*)value) = (short)(n_input+SFlen(f));
768			else if(size == sizeof(uchar))
769				*((uchar*)value) = (uchar)(n_input+SFlen(f));
770			else	*((int*)value) = (int)(n_input+SFlen(f));
771			continue;
772		}
773
774		/* if get here, start scanning input */
775		if(width == 0)
776			width = fmt == 'c' ? 1 : MAXWIDTH;
777
778		/* define the first input character */
779		if(fmt == 'c' || fmt == '[' || fmt == 'C' )
780			SFgetc(f,inp);
781		else
782		{	do	{ SFgetc(f,inp); }
783			while(isspace(inp)); /* skip starting blanks */
784		}
785		if(inp < 0)
786			goto done;
787
788		if(_Sftype[fmt] == SFFMT_FLOAT)
789		{	SFungetc(f,inp); SCinit(&scd,1);
790			argv.ld = _sfdscan((Void_t*)(&scd), _scgetc);
791			SCend(&scd,1);
792
793			if(scd.error >= 0)
794			{	if(inp >= 0)
795					SFungetc(f, inp);
796				goto pop_fmt;
797			}
798
799			if(value)
800			{
801#if !_ast_fltmax_double
802				if(size == sizeof(Sfdouble_t))
803					*((Sfdouble_t*)value) = argv.ld;
804				else
805#endif
806				if(size == sizeof(double))
807					*((double*)value) = (double)argv.ld;
808				else	*((float*)value) = (float)argv.ld;
809
810				n_assign += 1;
811			}
812		}
813		else if(_Sftype[fmt] == SFFMT_UINT || fmt == 'p')
814		{	if(inp == '-')
815			{	SFungetc(f,inp);
816				goto pop_fmt;
817			}
818			else	goto int_cvt;
819		}
820		else if(_Sftype[fmt] == SFFMT_INT)
821		{ int_cvt:
822			if(inp == '-' || inp == '+')
823			{	if(inp == '-')
824					flags |= SFFMT_MINUS;
825				while(--width > 0 && SFgetc(f,inp) >= 0)
826					if(!isspace(inp))
827						break;
828			}
829			if(inp < 0)
830				goto done;
831
832			if(fmt == 'o')
833				base = 8;
834			else if(fmt == 'x' || fmt == 'X' || fmt == 'p')
835				base = 16;
836			else if(fmt == 'i' && inp == '0') /* self-described data */
837			{	base = 8;
838				if(width > 1) /* peek to see if it's a base-16 */
839				{	if(SFgetc(f,inp) >= 0)
840					{	if(inp == 'x' || inp == 'X')
841							base = 16;
842						SFungetc(f,inp);
843					}
844					inp = '0';
845				}
846			}
847
848			/* now convert */
849			argv.lu = 0;
850			if(base == 16)
851			{	sp = (char*)_Sfcv36;
852				shift = 4;
853				if(sp[inp] >= 16)
854				{	SFungetc(f,inp);
855					goto pop_fmt;
856				}
857				if(inp == '0' && --width > 0)
858				{	/* skip leading 0x or 0X */
859					if(SFgetc(f,inp) >= 0 &&
860					   (inp == 'x' || inp == 'X') && --width > 0)
861						SFgetc(f,inp);
862				}
863				if(inp >= 0 && sp[inp] < 16)
864					goto base_shift;
865			}
866			else if(base == 10)
867			{	for(n = v = 0;; )
868				{	/* fast base 10 conversion */
869#define TEN(x) (((x) << 3) + ((x) << 1) )
870					if (inp >= '0' && inp <= '9')
871					{	argv.lu = TEN(argv.lu) + (inp-'0');
872						n += 1;
873					}
874					else if(inp == thousand)
875					{	if((v && n != 3) || (!v && n > 3) )
876							break;
877						v = 1; n = 0;
878					}
879					else	break;
880					if((width -= 1) <= 0 || SFgetc(f,inp) < 0)
881						break;
882				}
883				if (!n && !v)
884				{	SFungetc(f,inp);
885					goto pop_fmt;
886				}
887
888				if(fmt == 'i' && inp == '#' && !(flags&SFFMT_ALTER) )
889				{	base = (int)argv.lu;
890					if(base < 2 || base > SF_RADIX)
891						goto pop_fmt;
892					argv.lu = 0;
893					sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64);
894					if(--width > 0 &&
895					   SFgetc(f,inp) >= 0 && sp[inp] < base)
896						goto base_conv;
897				}
898			}
899			else
900			{	/* other bases */
901				sp = (char*)(base <= 36 ? _Sfcv36 : _Sfcv64);
902				if(base < 2 || base > SF_RADIX || sp[inp] >= base)
903				{	SFungetc(f,inp);
904					goto pop_fmt;
905				}
906
907			base_conv: /* check for power of 2 conversions */
908				if((base & ~(base-1)) == base)
909				{	if(base < 8)
910						shift = base <  4 ? 1 : 2;
911					else if(base < 32)
912						shift = base < 16 ? 3 : 4;
913					else	shift = base < 64 ? 5 : 6;
914
915			base_shift:	do
916					{ argv.lu = (argv.lu << shift) + sp[inp];
917					} while(--width > 0 &&
918					        SFgetc(f,inp) >= 0 && sp[inp] < base);
919				}
920				else
921				{	do
922					{ argv.lu = (argv.lu * base) + sp[inp];
923					} while(--width > 0 &&
924						SFgetc(f,inp) >= 0 && sp[inp] < base);
925				}
926			}
927
928			if(flags&SFFMT_MINUS)
929				argv.ll = -argv.ll;
930
931			if(value)
932			{	n_assign += 1;
933
934				if(fmt == 'p')
935#if _more_void_int
936					*((Void_t**)value) = (Void_t*)((ulong)argv.lu);
937#else
938					*((Void_t**)value) = (Void_t*)((uint)argv.lu);
939#endif
940#if !_ast_intmax_long
941				else if(size == sizeof(Sflong_t))
942					*((Sflong_t*)value) = argv.ll;
943#endif
944				else if(size == sizeof(long))
945				{	if(fmt == 'd' || fmt == 'i')
946						*((long*)value) = (long)argv.ll;
947					else	*((ulong*)value) = (ulong)argv.lu;
948				}
949				else if(size == sizeof(short))
950				{	if(fmt == 'd' || fmt == 'i')
951						*((short*)value) = (short)argv.ll;
952					else	*((ushort*)value) = (ushort)argv.lu;
953				}
954				else if(size == sizeof(char) )
955				{	if(fmt == 'd' || fmt == 'i')
956						*((char*)value) = (char)argv.ll;
957					else	*((uchar*)value) = (uchar)argv.lu;
958				}
959				else
960				{	if(fmt == 'd' || fmt == 'i')
961						*((int*)value) = (int)argv.ll;
962					else	*((uint*)value) = (uint)argv.lu;
963				}
964			}
965		}
966		else if(fmt == 'C' || fmt == 'S')
967		{	fmt = fmt == 'C' ? 'c' : 's';
968			flags = (flags & ~SFFMT_TYPES) | SFFMT_LONG;
969			goto do_string;
970		}
971		else if(fmt == 's' || fmt == 'c' || fmt == '[' )
972		{ do_string:
973			if(value)
974			{	if(size < 0)
975					size = MAXWIDTH;
976				if(fmt != 'c')
977					size -= 1;
978#if _has_multibyte
979				if(flags&SFFMT_LONG)
980					argv.ws = (wchar_t*)value;
981				else
982#endif
983					argv.s = (char*)value;
984			}
985			else	size = 0;
986
987			if(fmt == '[' && !(form = _sfsetclass(form,&acc,flags)) )
988			{	SFungetc(f,inp);
989				goto pop_fmt;
990			}
991
992			n = 0; /* count number of scanned characters */
993#if _has_multibyte
994			if(flags&SFFMT_LONG)
995			{	SFungetc(f,inp); SCinit(&scd,0); SFMBCLR(&mbs);
996				for(; width > 0; --width)
997				{	if(SFgetwc(&scd,&wc,fmt,&acc,&mbs) == 0)
998						break;
999					if((n += 1) <= size)
1000						*argv.ws++ = wc;
1001				}
1002				SCend(&scd,0);
1003			}
1004			else
1005#endif
1006
1007			if(fmt == 's')
1008			{	do
1009				{	if(isspace(inp))
1010						break;
1011					if((n += 1) <= size)
1012						*argv.s++ = inp;
1013				} while(--width > 0 && SFgetc(f,inp) >= 0);
1014			}
1015			else if(fmt == 'c')
1016			{	do
1017			 	{	if((n += 1) <= size)
1018						*argv.s++ = inp;
1019				} while(--width > 0 && SFgetc(f,inp) >= 0);
1020			}
1021			else /* if(fmt == '[') */
1022			{	do
1023				{	if(!acc.ok[inp])
1024					{	if(n > 0 || (flags&SFFMT_ALTER) )
1025							break;
1026						else
1027						{	SFungetc(f,inp);
1028							goto pop_fmt;
1029						}
1030					}
1031					if((n += 1) <= size)
1032						*argv.s++ = inp;
1033				} while(--width > 0 && SFgetc(f,inp) >= 0);
1034			}
1035
1036			if(value && (n > 0 || fmt == '[') )
1037			{	n_assign += 1;
1038				if(fmt != 'c' && size >= 0)
1039				{
1040#if _has_multibyte
1041					if(flags&SFFMT_LONG)
1042						*argv.ws = 0;
1043					else
1044#endif
1045						*argv.s = 0;
1046				}
1047			}
1048		}
1049
1050		if(width > 0 && inp >= 0)
1051			SFungetc(f,inp);
1052	}
1053
1054pop_fmt:
1055	if(fp)
1056	{	free(fp);
1057		fp = NIL(Fmtpos_t*);
1058	}
1059	while((fm = fmstk) ) /* pop the format stack and continue */
1060	{	if(fm->eventf)
1061		{	if(!form || !form[0])
1062				(*fm->eventf)(f,SF_FINAL,NIL(Void_t*),ft);
1063			else if((*fm->eventf)(f,SF_DPOP,(Void_t*)form,ft) < 0)
1064				goto loop_fmt;
1065		}
1066
1067		fmstk = fm->next;
1068		if((form = fm->form) )
1069		{	SFMBCPY(&fmbs,&fm->mbs);
1070			va_copy(args, fm->args);
1071			oform = fm->oform;
1072			va_copy(oargs,fm->oargs);
1073			argn = fm->argn;
1074			fp = fm->fp;
1075		}
1076		ft = fm->ft;
1077		free(fm);
1078		if(form && form[0])
1079			goto loop_fmt;
1080	}
1081
1082done:
1083	if(fp)
1084		free(fp);
1085	while((fm = fmstk) )
1086	{	if(fm->eventf)
1087			(*fm->eventf)(f,SF_FINAL,NIL(Void_t*),fm->ft);
1088		fmstk = fm->next;
1089		free(fm);
1090	}
1091
1092	SFend(f);
1093
1094	SFOPEN(f,0);
1095
1096	if(n_assign == 0 && inp < 0)
1097		n_assign = -1;
1098
1099	SFMTXRETURN(f,n_assign);
1100}
1101