arch/m68k-amiga: Define the gcc symbol 'start' instead of using .bss
[AROS.git] / compiler / clib / __vcscan.c
blob3ffd4ef6e57bfa61394befc72475f80a15172dc8
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Function to scan a string like scanf().
6 */
8 #define __vcscan __vcscan
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdarg.h>
13 #ifndef AROS_NO_LIMITS_H
14 # include <limits.h>
15 #else
16 # define ULONG_MAX 4294967295UL
17 #endif
18 #include <ctype.h>
19 #include <math.h>
21 #ifndef AROSC_ROM
22 #define FULL_SPECIFIERS
23 #endif
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 */
43 #endif
45 #undef getc
46 #undef ungetc
48 /*****************************************************************************
50 NAME */
52 int __vcscan (
54 /* SYNOPSIS */
55 void * data,
56 int (* getc)(void *),
57 int (* ungetc)(int,void *),
58 const char * format,
59 va_list args)
61 /* FUNCTION
62 Scan an input stream as specified in format. The result of
63 the scan will be placed in args.
65 INPUTS
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
74 next getc.
75 format - A scanf() format string.
76 args - A list of arguments in which the result of the scan should
77 be placed.
79 RESULT
80 The number of arguments converted.
82 NOTES
84 EXAMPLE
86 BUGS
88 SEE ALSO
90 INTERNALS
92 ******************************************************************************/
94 size_t blocks=0,incount=0;
95 int c=0;
97 while(*format)
99 size_t size=0;
101 if(*format=='%')
103 size_t width=ULONG_MAX;
104 char type,subtype='i',ignore=0;
105 const unsigned char *ptr=format+1;
106 size_t i;
108 if(isdigit(*ptr))
110 width=0;
111 while(isdigit(*ptr))
112 width=width*10+(*ptr++-'0');
115 while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*')
117 if(*ptr=='*')
118 ignore=1;
119 else
120 subtype=*ptr;
121 ptr++;
124 type=*ptr++;
126 if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[')
128 do /* ignore leading whitespace characters */
129 NEXT(c);
130 while(isspace(c));
131 size=1;
132 } /* The first non-whitespace character is already read */
134 switch(type)
136 case 'c':
138 unsigned char *bp;
140 if(width==ULONG_MAX) /* Default */
141 width=1;
143 if(!ignore)
144 bp=va_arg(args,char *);
145 else
146 bp=NULL; /* Just to get the compiler happy */
148 NEXT(c); /* 'c' did not skip whitespace */
149 while(VAL(c!=EOF))
151 if(!ignore)
152 *bp++=c;
153 NEXT(c);
155 PREV(c);
157 if(!ignore&&size)
158 blocks++;
159 break;
161 case '[':
163 unsigned char *bp;
164 unsigned char tab[32],a,b;
165 char circflag=0;
167 if(*ptr=='^')
169 circflag=1;
170 ptr++;
172 for(i=0;i<sizeof(tab);i++)
173 tab[i]=circflag?255:0;
175 for(;;)
177 if(!*ptr)
178 break;
179 a=b=*ptr++;
180 if(*ptr=='-'&&ptr[1]&&ptr[1]!=']')
182 ptr++;
183 b=*ptr++;
185 for(i=a;i<=b;i++)
186 if(circflag)
187 tab[i/8]&=~(1<<(i&7));
188 else
189 tab[i/8]|=1<<(i&7);
190 if(*ptr==']')
192 ptr++;
193 break;
197 if(!ignore)
198 bp=va_arg(args,char *);
199 else
200 bp=NULL; /* Just to get the compiler happy */
202 NEXT(c);
203 while(VAL(c!=EOF&&tab[c/8]&(1<<(c&7))))
205 if(!ignore)
206 *bp++=c;
207 NEXT(c);
209 PREV(c);
211 if(!ignore&&size)
213 *bp++='\0';
214 blocks++;
216 break;
218 case 's':
220 unsigned char *bp;
222 if(!ignore)
223 bp=va_arg(args,char *);
224 else
225 bp=NULL; /* Just to get the compiler happy */
227 while(VAL(c!=EOF&&!isspace(c)))
229 if(!ignore)
230 *bp++=c;
231 NEXT(c);
233 PREV(c);
235 if(!ignore&&size)
237 *bp++='\0';
238 blocks++;
240 break;
242 #ifdef FULL_SPECIFIERS
243 case 'e':
244 case 'f':
245 case 'g':
247 double v;
248 int ex=0;
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=='+'))
255 min=c;
256 NEXT(c);
259 if(VAL(tolower(c)=='i')) /* +- inf */
261 int d;
262 NEXT(d);
263 if(VAL(tolower(d)=='n'))
265 int e;
266 NEXT(e);
267 if(VAL(tolower(e)=='f'))
269 v=*(double *)&undef[min=='-'];
270 break;
271 } /* break out */
272 PREV(e);
274 PREV(d);
276 else if(VAL(toupper(c)=='N')) /* NaN */
278 int d;
279 NEXT(d);
280 if(VAL(tolower(d)=='a'))
282 int e;
283 NEXT(e);
284 if(VAL(toupper(e)=='N'))
286 v=*(double *)&undef[2];
287 break;
289 PREV(e);
291 PREV(d);
294 v=0.0;
295 while(VAL(isdigit(c)))
297 v=v*10.0+(c-'0');
298 NEXT(c);
301 if(VAL(c==__decimalpoint[0]))
303 double dp=0.1;
304 NEXT(c);
305 while(VAL(isdigit(c)))
307 v=v+dp*(c-'0');
308 dp=dp/10.0;
309 NEXT(c);
311 if(size==2+(min!=0)) /* No number read till now -> malformatted */
313 PREV(c);
314 c=__decimalpoint[0];
318 if(min&&size==2) /* No number read till now -> malformatted */
320 PREV(c);
321 c=min;
323 if(size==1)
324 break;
326 if(VAL(tolower(c)=='e'))
328 int d;
329 NEXT(d);
330 if(VAL(d=='-'||d=='+'))
332 mine=d;
333 NEXT(d);
336 if(VAL(isdigit(d)))
340 ex=ex*10+(d-'0');
341 NEXT(d);
342 }while(VAL(isdigit(d)&&ex<100));
343 c=d;
345 else
347 PREV(d);
348 if(mine)
349 PREV(mine);
352 PREV(c);
354 if(mine=='-')
355 v=v/pow(10.0,ex);
356 else
357 v=v*pow(10.0,ex);
359 if(min=='-')
360 v=-v;
362 }while(0);
364 if(!ignore&&size)
366 switch(subtype)
368 case 'l':
369 case 'L':
370 *va_arg(args,double *)=v;
371 break;
372 case 'i':
373 *va_arg(args,float *)=v;
374 break;
376 blocks++;
378 break;
380 #endif
381 case '%':
382 NEXT(c);
383 if(c!='%')
384 PREV(c); /* unget non-'%' character */
385 break;
386 case 'n':
387 if(!ignore)
388 *va_arg(args,int *)=incount;
389 size=1; /* fake a valid argument */
390 break;
391 default:
393 unsigned long v=0;
394 int base;
395 int min=0;
397 if(!type)
398 ptr--; /* unparse NUL character */
400 if(type=='p')
402 subtype='l'; /* This is the same as %lx */
403 type='x';
406 if(VAL((c=='-'&&type!='u')||c=='+'))
408 min=c;
409 NEXT(c);
412 if(type=='i') /* which one to use ? */
414 if(VAL(c=='0')) /* Could be octal or sedecimal */
416 int d;
417 NEXT(d); /* Get a look at next character */
418 if(VAL(tolower(d)=='x'))
420 int e;
421 NEXT(e); /* And the next */
422 if(VAL(isxdigit(c)))
423 type='x'; /* Is a valid x number with '0x?' */
424 PREV(e);
426 else
427 type='o';
428 PREV(d);
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 */
434 //else
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 */
441 int d;
442 NEXT(d);
443 if(VAL(tolower(d)=='x'))
445 int e;
446 NEXT(e);
447 if(VAL(isxdigit(e)))
449 c=e;
450 break;
451 } /* Used while just to do this ;-) */
452 PREV(e);
454 PREV(d);
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);
462 NEXT(c);
465 if(min&&size==2) /* If there is no valid character after sign, unget last */
467 PREV(c);
468 c=min;
471 PREV(c);
473 if(ignore||!size)
474 break;
476 if(type=='u')
478 switch(subtype)
480 case 'l':
481 case 'L':
482 *va_arg(args,unsigned long *)=v;
483 break;
484 case 'i':
485 *va_arg(args,unsigned int *)=v;
486 break;
487 case 'h':
488 *va_arg(args,unsigned short *)=v;
489 break;
492 else
494 signed long v2;
495 if(min=='-')
496 v2=-v;
497 else
498 v2=v;
499 switch(subtype)
501 case 'l':
502 case 'L':
503 *va_arg(args,signed long *)=v2;
504 break;
505 case 'i':
506 *va_arg(args,signed int *)=v2;
507 break;
508 case 'h':
509 *va_arg(args,signed short *)=v2;
510 break;
513 blocks++;
514 break;
517 format=ptr;
519 else
521 if(isspace(*format))
524 NEXT(c);
525 while(isspace(c));
526 PREV(c);
527 size=1;
529 else
531 NEXT(c);
532 if(c!=*format)
533 PREV(c);
536 format++;
538 if(!size)
539 break;
542 if(c==EOF&&!blocks)
543 return c;
544 else
545 return blocks;