2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
5 Function to scan a string like scanf().
11 #ifndef AROS_NO_LIMITS_H
14 # define ULONG_MAX 4294967295UL
19 #define FULL_SPECIFIERS
21 /* some macros to cut this short
22 * NEXT(c); read next character
23 * PREV(c); ungetc a character
24 * VAL(a) leads to 1 if a is true and valid
26 #define NEXT(c) ((c)=(*get_char)(data),size++,incount++)
27 #define PREV(c) do{if((c)!=EOF)(*unget_char)((c),data);size--;incount--;}while(0)
28 #define VAL(a) ((a)&&size<=width)
30 extern unsigned char *__decimalpoint
;
32 #ifdef FULL_SPECIFIERS
33 const static unsigned char undef
[3][sizeof(double)]= /* Undefined numeric values, IEEE */
35 { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
36 { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
37 { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 } /* NaN */
42 /*****************************************************************************
50 int (* get_char
)(void *),
51 int (* unget_char
)(int,void *),
56 Scan an input stream as specified in format. The result of
57 the scan will be placed in args.
60 data - This is passed to the usercallback getc and ungetc
61 get_char - This function gets called when the routine wants to
62 read the next character. It whould return EOF when
63 no more characters are available.
64 unget_char - This function gets called when the routine wants to
65 put a read character back into the stream. The next
66 call to get_char() should return this character. It is possible
67 that this function is called more than once before the
69 format - A scanf() format string.
70 args - A list of arguments in which the result of the scan should
74 The number of arguments converted.
86 ******************************************************************************/
88 size_t blocks
=0,incount
=0;
97 size_t width
=ULONG_MAX
;
98 char type
,subtype
='i',ignore
=0;
99 const unsigned char *ptr
=format
+1;
106 width
=width
*10+(*ptr
++-'0');
109 while(*ptr
=='h'||*ptr
=='l'||*ptr
=='L'||*ptr
=='*')
120 if(type
&&type
!='%'&&type
!='c'&&type
!='n'&&type
!='[')
122 do /* ignore leading whitespace characters */
126 } /* The first non-whitespace character is already read */
134 if(width
==ULONG_MAX
) /* Default */
138 bp
=va_arg(args
,char *);
140 bp
=NULL
; /* Just to get the compiler happy */
142 NEXT(c
); /* 'c' did not skip whitespace */
158 unsigned char tab
[32],a
,b
;
166 for(i
=0;i
<sizeof(tab
);i
++)
167 tab
[i
]=circflag
?255:0;
174 if(*ptr
=='-'&&ptr
[1]&&ptr
[1]!=']')
181 tab
[i
/8]&=~(1<<(i
&7));
192 bp
=va_arg(args
,char *);
194 bp
=NULL
; /* Just to get the compiler happy */
197 while(VAL(c
!=EOF
&&tab
[c
/8]&(1<<(c
&7))))
217 bp
=va_arg(args
,char *);
219 bp
=NULL
; /* Just to get the compiler happy */
221 while(VAL(c
!=EOF
&&!isspace(c
)))
236 #ifdef FULL_SPECIFIERS
243 int min
=0,mine
=0; /* This is a workaround for gcc 2.3.3: should be char */
245 do /* This is there just to be able to break out */
247 if(VAL(c
=='-'||c
=='+'))
253 if(VAL(tolower(c
)=='i')) /* +- inf */
257 if(VAL(tolower(d
)=='n'))
261 if(VAL(tolower(e
)=='f'))
263 v
=*(double *)&undef
[min
=='-'];
270 else if(VAL(toupper(c
)=='N')) /* NaN */
274 if(VAL(tolower(d
)=='a'))
278 if(VAL(toupper(e
)=='N'))
280 v
=*(double *)&undef
[2];
289 while(VAL(isdigit(c
)))
295 if(VAL(c
==__decimalpoint
[0]))
299 while(VAL(isdigit(c
)))
305 if(size
==2+(min
!=0)) /* No number read till now -> malformatted */
312 if(min
&&size
==2) /* No number read till now -> malformatted */
322 if(VAL(tolower(c
)=='e'))
326 if(VAL(d
=='-'||d
=='+'))
338 }while(VAL(isdigit(d
)&&ex
<100));
366 *va_arg(args
,double *)=v
;
369 *va_arg(args
,float *)=v
;
380 PREV(c
); /* unget non-'%' character */
384 *va_arg(args
,int *)=incount
;
385 size
=1; /* fake a valid argument */
394 ptr
--; /* unparse NUL character */
398 subtype
='l'; /* This is the same as %lx */
402 if(VAL((c
=='-'&&type
!='u')||c
=='+'))
408 if(type
=='i') /* which one to use ? */
410 if(VAL(c
=='0')) /* Could be octal or sedecimal */
413 NEXT(d
); /* Get a look at next character */
414 if(VAL(tolower(d
)=='x'))
417 NEXT(e
); /* And the next */
419 type
='x'; /* Is a valid x number with '0x?' */
426 /* deadwood: Below code is wrong and left for reference.
427 Algoritm cannot assume that string starting with A-F is
428 a hexadecimal integer. There must be '0x' sequence -
429 validated via test/clib/sscanf.c */
431 // if(VAL(!isdigit(c)&&isxdigit(c)))
432 // type='x'; /* Is a valid x number without '0x' */
435 while(type
=='x'&&VAL(c
=='0')) /* sedecimal */
439 if(VAL(tolower(d
)=='x'))
447 } /* Used while just to do this ;-) */
451 break; /* Need no loop */
454 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
455 while(VAL(isxdigit(c
)&&(base
!=10||isdigit(c
))&&(base
!=8||c
<='7')))
457 v
=v
*base
+(isdigit(c
)?c
-'0':0)+(isupper(c
)?c
-'A'+10:0)+(islower(c
)?c
-'a'+10:0);
461 if(min
&&size
==2) /* If there is no valid character after sign, unget last */
478 *va_arg(args
,unsigned long *)=v
;
481 *va_arg(args
,unsigned int *)=v
;
484 *va_arg(args
,unsigned short *)=v
;
499 *va_arg(args
,signed long *)=v2
;
502 *va_arg(args
,signed int *)=v2
;
505 *va_arg(args
,signed short *)=v2
;