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
20 #define FULL_SPECIFIERS
23 /* some macros to cut this short
24 * NEXT(c); read next character
25 * PREV(c); ungetc a character
26 * VAL(a) leads to 1 if a is true and valid
28 #define NEXT(c) ((c)=(*get_char)(data),size++,incount++)
29 #define PREV(c) do{if((c)!=EOF)(*unget_char)((c),data);size--;incount--;}while(0)
30 #define VAL(a) ((a)&&size<=width)
32 extern unsigned char *__decimalpoint
;
34 #ifdef FULL_SPECIFIERS
35 const static unsigned char undef
[3][sizeof(double)]= /* Undefined numeric values, IEEE */
37 { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
38 { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
39 { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 } /* NaN */
44 /*****************************************************************************
52 int (* get_char
)(void *),
53 int (* unget_char
)(int,void *),
58 Scan an input stream as specified in format. The result of
59 the scan will be placed in args.
62 data - This is passed to the usercallback getc and ungetc
63 get_char - This function gets called when the routine wants to
64 read the next character. It whould return EOF when
65 no more characters are available.
66 unget_char - This function gets called when the routine wants to
67 put a read character back into the stream. The next
68 call to get_char() should return this character. It is possible
69 that this function is called more than once before the
71 format - A scanf() format string.
72 args - A list of arguments in which the result of the scan should
76 The number of arguments converted.
88 ******************************************************************************/
90 size_t blocks
=0,incount
=0;
99 size_t width
=ULONG_MAX
;
100 char type
,subtype
='i',ignore
=0;
101 const unsigned char *ptr
=format
+1;
108 width
=width
*10+(*ptr
++-'0');
111 while(*ptr
=='h'||*ptr
=='l'||*ptr
=='L'||*ptr
=='*')
122 if(type
&&type
!='%'&&type
!='c'&&type
!='n'&&type
!='[')
124 do /* ignore leading whitespace characters */
128 } /* The first non-whitespace character is already read */
136 if(width
==ULONG_MAX
) /* Default */
140 bp
=va_arg(args
,char *);
142 bp
=NULL
; /* Just to get the compiler happy */
144 NEXT(c
); /* 'c' did not skip whitespace */
160 unsigned char tab
[32],a
,b
;
168 for(i
=0;i
<sizeof(tab
);i
++)
169 tab
[i
]=circflag
?255:0;
176 if(*ptr
=='-'&&ptr
[1]&&ptr
[1]!=']')
183 tab
[i
/8]&=~(1<<(i
&7));
194 bp
=va_arg(args
,char *);
196 bp
=NULL
; /* Just to get the compiler happy */
199 while(VAL(c
!=EOF
&&tab
[c
/8]&(1<<(c
&7))))
219 bp
=va_arg(args
,char *);
221 bp
=NULL
; /* Just to get the compiler happy */
223 while(VAL(c
!=EOF
&&!isspace(c
)))
238 #ifdef FULL_SPECIFIERS
245 int min
=0,mine
=0; /* This is a workaround for gcc 2.3.3: should be char */
247 do /* This is there just to be able to break out */
249 if(VAL(c
=='-'||c
=='+'))
255 if(VAL(tolower(c
)=='i')) /* +- inf */
259 if(VAL(tolower(d
)=='n'))
263 if(VAL(tolower(e
)=='f'))
265 v
=*(double *)&undef
[min
=='-'];
272 else if(VAL(toupper(c
)=='N')) /* NaN */
276 if(VAL(tolower(d
)=='a'))
280 if(VAL(toupper(e
)=='N'))
282 v
=*(double *)&undef
[2];
291 while(VAL(isdigit(c
)))
297 if(VAL(c
==__decimalpoint
[0]))
301 while(VAL(isdigit(c
)))
307 if(size
==2+(min
!=0)) /* No number read till now -> malformatted */
314 if(min
&&size
==2) /* No number read till now -> malformatted */
324 if(VAL(tolower(c
)=='e'))
328 if(VAL(d
=='-'||d
=='+'))
340 }while(VAL(isdigit(d
)&&ex
<100));
368 *va_arg(args
,double *)=v
;
371 *va_arg(args
,float *)=v
;
382 PREV(c
); /* unget non-'%' character */
386 *va_arg(args
,int *)=incount
;
387 size
=1; /* fake a valid argument */
396 ptr
--; /* unparse NUL character */
400 subtype
='l'; /* This is the same as %lx */
404 if(VAL((c
=='-'&&type
!='u')||c
=='+'))
410 if(type
=='i') /* which one to use ? */
412 if(VAL(c
=='0')) /* Could be octal or sedecimal */
415 NEXT(d
); /* Get a look at next character */
416 if(VAL(tolower(d
)=='x'))
419 NEXT(e
); /* And the next */
421 type
='x'; /* Is a valid x number with '0x?' */
428 /* deadwood: Below code is wrong and left for reference.
429 Algoritm cannot assume that string starting with A-F is
430 a hexadecimal integer. There must be '0x' sequence -
431 validated via test/clib/sscanf.c */
433 // if(VAL(!isdigit(c)&&isxdigit(c)))
434 // type='x'; /* Is a valid x number without '0x' */
437 while(type
=='x'&&VAL(c
=='0')) /* sedecimal */
441 if(VAL(tolower(d
)=='x'))
449 } /* Used while just to do this ;-) */
453 break; /* Need no loop */
456 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
457 while(VAL(isxdigit(c
)&&(base
!=10||isdigit(c
))&&(base
!=8||c
<='7')))
459 v
=v
*base
+(isdigit(c
)?c
-'0':0)+(isupper(c
)?c
-'A'+10:0)+(islower(c
)?c
-'a'+10:0);
463 if(min
&&size
==2) /* If there is no valid character after sign, unget last */
480 *va_arg(args
,unsigned long *)=v
;
483 *va_arg(args
,unsigned int *)=v
;
486 *va_arg(args
,unsigned short *)=v
;
501 *va_arg(args
,signed long *)=v2
;
504 *va_arg(args
,signed int *)=v2
;
507 *va_arg(args
,signed short *)=v2
;