2 Copyright © 1995-2013, 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 *__stdc_char_decimalpoint
;
39 unsigned char uchar
[sizeof(double)];
43 #ifdef FULL_SPECIFIERS
44 const static struct vcs_ieeetype undef
[3] = /* Undefined numeric values, IEEE */
46 { .uchar
= { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }}, /* +inf */
47 { .uchar
= { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }}, /* -inf */
48 { .uchar
= { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 }} /* NaN */
53 /*****************************************************************************
61 int (* get_char
)(void *),
62 int (* unget_char
)(int,void *),
67 Scan an input stream as specified in format. The result of
68 the scan will be placed in args.
71 data - This is passed to the usercallback getc and ungetc
72 get_char - This function gets called when the routine wants to
73 read the next character. It whould return EOF when
74 no more characters are available.
75 unget_char - This function gets called when the routine wants to
76 put a read character back into the stream. The next
77 call to get_char() should return this character. It is possible
78 that this function is called more than once before the
80 format - A scanf() format string.
81 args - A list of arguments in which the result of the scan should
85 The number of arguments converted.
97 ******************************************************************************/
99 size_t blocks
=0,incount
=0;
108 size_t width
=ULONG_MAX
;
109 char type
,subtype
='i',ignore
=0;
110 const unsigned char *ptr
=format
+1;
117 width
=width
*10+(*ptr
++-'0');
120 while(*ptr
=='h'||*ptr
=='l'||*ptr
=='L'||*ptr
=='*')
131 if(type
&&type
!='%'&&type
!='c'&&type
!='n'&&type
!='[')
133 do /* ignore leading whitespace characters */
137 } /* The first non-whitespace character is already read */
145 if(width
==ULONG_MAX
) /* Default */
149 bp
=va_arg(args
,char *);
151 bp
=NULL
; /* Just to get the compiler happy */
153 NEXT(c
); /* 'c' did not skip whitespace */
169 unsigned char tab
[32],a
,b
;
177 for(i
=0;i
<sizeof(tab
);i
++)
178 tab
[i
]=circflag
?255:0;
185 if(*ptr
=='-'&&ptr
[1]&&ptr
[1]!=']')
192 tab
[i
/8]&=~(1<<(i
&7));
203 bp
=va_arg(args
,char *);
205 bp
=NULL
; /* Just to get the compiler happy */
208 while(VAL(c
!=EOF
&&tab
[c
/8]&(1<<(c
&7))))
228 bp
=va_arg(args
,char *);
230 bp
=NULL
; /* Just to get the compiler happy */
232 while(VAL(c
!=EOF
&&!isspace(c
)))
247 #ifdef FULL_SPECIFIERS
254 int min
=0,mine
=0; /* This is a workaround for gcc 2.3.3: should be char */
256 do /* This is there just to be able to break out */
258 if(VAL(c
=='-'||c
=='+'))
264 if(VAL(tolower(c
)=='i')) /* +- inf */
268 if(VAL(tolower(d
)=='n'))
272 if(VAL(tolower(e
)=='f'))
274 v
=*(double *)&undef
[min
=='-'];
281 else if(VAL(toupper(c
)=='N')) /* NaN */
285 if(VAL(tolower(d
)=='a'))
289 if(VAL(toupper(e
)=='N'))
291 v
=*(double *)&undef
[2];
300 while(VAL(isdigit(c
)))
306 if(VAL(c
==__stdc_char_decimalpoint
[0]))
310 while(VAL(isdigit(c
)))
316 if(size
==2+(min
!=0)) /* No number read till now -> malformatted */
319 c
=__stdc_char_decimalpoint
[0];
323 if(min
&&size
==2) /* No number read till now -> malformatted */
333 if(VAL(tolower(c
)=='e'))
337 if(VAL(d
=='-'||d
=='+'))
349 }while(VAL(isdigit(d
)&&ex
<100));
377 *va_arg(args
,double *)=v
;
380 *va_arg(args
,float *)=v
;
391 PREV(c
); /* unget non-'%' character */
395 *va_arg(args
,int *)=incount
;
396 size
=1; /* fake a valid argument */
405 ptr
--; /* unparse NUL character */
409 subtype
='l'; /* This is the same as %lx */
413 if(VAL((c
=='-'&&type
!='u')||c
=='+'))
419 if(type
=='i') /* which one to use ? */
421 if(VAL(c
=='0')) /* Could be octal or sedecimal */
424 NEXT(d
); /* Get a look at next character */
425 if(VAL(tolower(d
)=='x'))
428 NEXT(e
); /* And the next */
430 type
='x'; /* Is a valid x number with '0x?' */
437 /* deadwood: Below code is wrong and left for reference.
438 Algoritm cannot assume that string starting with A-F is
439 a hexadecimal integer. There must be '0x' sequence -
440 validated via test/clib/sscanf.c */
442 // if(VAL(!isdigit(c)&&isxdigit(c)))
443 // type='x'; /* Is a valid x number without '0x' */
446 while(type
=='x'&&VAL(c
=='0')) /* sedecimal */
450 if(VAL(tolower(d
)=='x'))
458 } /* Used while just to do this ;-) */
462 break; /* Need no loop */
465 base
=type
=='x'||type
=='X'?16:(type
=='o'?8:10);
466 while(VAL(isxdigit(c
)&&(base
!=10||isdigit(c
))&&(base
!=8||c
<='7')))
468 v
=v
*base
+(isdigit(c
)?c
-'0':0)+(isupper(c
)?c
-'A'+10:0)+(islower(c
)?c
-'a'+10:0);
472 if(min
&&size
==2) /* If there is no valid character after sign, unget last */
489 *va_arg(args
,unsigned long *)=v
;
492 *va_arg(args
,unsigned int *)=v
;
495 *va_arg(args
,unsigned short *)=v
;
510 *va_arg(args
,signed long *)=v2
;
513 *va_arg(args
,signed int *)=v2
;
516 *va_arg(args
,signed short *)=v2
;