2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Function to scan a string like scanf().
8 #define __vcscan __vcscan
13 #ifndef AROS_NO_LIMITS_H
16 # define ULONG_MAX 4294967295UL
22 #define FULL_SPECIFIERS
25 /* some macros to cut this short
26 * NEXT(c); read next character
27 * PREV(c); ungetc a character
28 * VAL(a) leads to 1 if a is true and valid
30 #define NEXT(c) ((c)=(*getc)(data),size++,incount++)
31 #define PREV(c) do{if((c)!=EOF)(*ungetc)((c),data);size--;incount--;}while(0)
32 #define VAL(a) ((a)&&size<=width)
34 extern unsigned char *__decimalpoint
;
36 #ifdef FULL_SPECIFIERS
37 const static unsigned char undef
[3][sizeof(double)]= /* Undefined numeric values, IEEE */
39 { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
40 { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
41 { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 } /* NaN */
48 /*****************************************************************************
57 int (* ungetc
)(int,void *),
62 Scan an input stream as specified in format. The result of
63 the scan will be placed in args.
66 data - This is passed to the usercallback getc and ungetc
67 getc - This function gets called when the routine wants to
68 read the next character. It whould return EOF when
69 no more characters are available.
70 ungetc - This function gets called when the routine wants to
71 put a read character back into the stream. The next
72 call to getc should return this character. It is possible
73 that this function is called more than once before the
75 format - A scanf() format string.
76 args - A list of arguments in which the result of the scan should
80 The number of arguments converted.
92 ******************************************************************************/
94 size_t blocks
=0,incount
=0;
103 size_t width
=ULONG_MAX
;
104 char type
,subtype
='i',ignore
=0;
105 const unsigned char *ptr
=format
+1;
112 width
=width
*10+(*ptr
++-'0');
115 while(*ptr
=='h'||*ptr
=='l'||*ptr
=='L'||*ptr
=='*')
126 if(type
&&type
!='%'&&type
!='c'&&type
!='n'&&type
!='[')
128 do /* ignore leading whitespace characters */
132 } /* The first non-whitespace character is already read */
140 if(width
==ULONG_MAX
) /* Default */
144 bp
=va_arg(args
,char *);
146 bp
=NULL
; /* Just to get the compiler happy */
148 NEXT(c
); /* 'c' did not skip whitespace */
164 unsigned char tab
[32],a
,b
;
172 for(i
=0;i
<sizeof(tab
);i
++)
173 tab
[i
]=circflag
?255:0;
180 if(*ptr
=='-'&&ptr
[1]&&ptr
[1]!=']')
187 tab
[i
/8]&=~(1<<(i
&7));
198 bp
=va_arg(args
,char *);
200 bp
=NULL
; /* Just to get the compiler happy */
203 while(VAL(c
!=EOF
&&tab
[c
/8]&(1<<(c
&7))))
223 bp
=va_arg(args
,char *);
225 bp
=NULL
; /* Just to get the compiler happy */
227 while(VAL(c
!=EOF
&&!isspace(c
)))
242 #ifdef FULL_SPECIFIERS
249 int min
=0,mine
=0; /* This is a workaround for gcc 2.3.3: should be char */
251 do /* This is there just to be able to break out */
253 if(VAL(c
=='-'||c
=='+'))
259 if(VAL(tolower(c
)=='i')) /* +- inf */
263 if(VAL(tolower(d
)=='n'))
267 if(VAL(tolower(e
)=='f'))
269 v
=*(double *)&undef
[min
=='-'];
276 else if(VAL(toupper(c
)=='N')) /* NaN */
280 if(VAL(tolower(d
)=='a'))
284 if(VAL(toupper(e
)=='N'))
286 v
=*(double *)&undef
[2];
295 while(VAL(isdigit(c
)))
301 if(VAL(c
==__decimalpoint
[0]))
305 while(VAL(isdigit(c
)))
311 if(size
==2+(min
!=0)) /* No number read till now -> malformatted */
318 if(min
&&size
==2) /* No number read till now -> malformatted */
326 if(VAL(tolower(c
)=='e'))
330 if(VAL(d
=='-'||d
=='+'))
342 }while(VAL(isdigit(d
)&&ex
<100));
370 *va_arg(args
,double *)=v
;
373 *va_arg(args
,float *)=v
;
384 PREV(c
); /* unget non-'%' character */
388 *va_arg(args
,int *)=incount
;
389 size
=1; /* fake a valid argument */
398 ptr
--; /* unparse NUL character */
402 subtype
='l'; /* This is the same as %lx */
406 if(VAL((c
=='-'&&type
!='u')||c
=='+'))
412 if(type
=='i') /* which one to use ? */
414 if(VAL(c
=='0')) /* Could be octal or sedecimal */
417 NEXT(d
); /* Get a look at next character */
418 if(VAL(tolower(d
)=='x'))
421 NEXT(e
); /* And the next */
423 type
='x'; /* Is a valid x number with '0x?' */
430 /* deadwood: Below code is wrong and left for reference.
431 Algoritm cannot assume that string starting with A-F is
432 a hexadecimal integer. There must be '0x' sequence -
433 validated via test/clib/sscanf.c */
435 // if(VAL(!isdigit(c)&&isxdigit(c)))
436 // type='x'; /* Is a valid x number without '0x' */
439 while(type
=='x'&&VAL(c
=='0')) /* sedecimal */
443 if(VAL(tolower(d
)=='x'))
451 } /* Used while just to do this ;-) */
455 break; /* Need no loop */
458 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
459 while(VAL(isxdigit(c
)&&(base
!=10||isdigit(c
))&&(base
!=8||c
<='7')))
461 v
=v
*base
+(isdigit(c
)?c
-'0':0)+(isupper(c
)?c
-'A'+10:0)+(islower(c
)?c
-'a'+10:0);
465 if(min
&&size
==2) /* If there is no valid character after sign, unget last */
482 *va_arg(args
,unsigned long *)=v
;
485 *va_arg(args
,unsigned int *)=v
;
488 *va_arg(args
,unsigned short *)=v
;
503 *va_arg(args
,signed long *)=v2
;
506 *va_arg(args
,signed int *)=v2
;
509 *va_arg(args
,signed short *)=v2
;