From 8b1fadd6a89f12cbc81c5d621a75b91dd9eedec2 Mon Sep 17 00:00:00 2001 From: Pixel Date: Sat, 5 Feb 2011 11:06:07 -0800 Subject: Adding Sun's fdlibm, and libnix's scanf, tweaked to become an xscanf. Adding a few more libc inlined also. --- libc/src/xscanf.c | 402 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100755 libc/src/xscanf.c (limited to 'libc/src') diff --git a/libc/src/xscanf.c b/libc/src/xscanf.c new file mode 100755 index 0000000..ad6f190 --- /dev/null +++ b/libc/src/xscanf.c @@ -0,0 +1,402 @@ +#include +#include +#include +#include +#include +#include + +/* some macros to cut this short + * NEXT(c); read next character + * PREV(c); ungetc a character + * VAL(a) leads to 1 if a is true and valid + */ +#define NEXT(c) ((c)=xgetc(opaque),size++,incount++) +#define PREV(c) do{if((c)!=EOF)xungetc((c),opaque);size--;incount--;}while(0) +#define VAL(a) ((a)&&size<=width) + +#ifdef NOFLOATINGPOINT +#undef FULL_SPECIFIERS +#else +#define FULL_SPECIFIERS +#endif + +extern unsigned char *__decimalpoint; + +#ifdef FULL_SPECIFIERS +static const unsigned char undef[3][sizeof(double)]= /* Undefined numeric values, IEEE */ +{ { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */ + { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */ + { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 } /* NaN */ +}; +#endif + +int vxscanf(int (*xgetc)(void *),void (*xungetc)(int,void*),void *opaque,const char *format,va_list args) +{ + size_t blocks=0,incount=0; + int c=0; + + while(*format) + { + size_t size=0; + + if(*format=='%') + { + size_t width=ULONG_MAX; + char type,subtype='i',ignore=0; + const unsigned char *ptr=(const unsigned char *)format+1; + size_t i; + + if(isdigit(*ptr)) + { width=0; + while(isdigit(*ptr)) + width=width*10+(*ptr++-'0'); } + + while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*') + { if(*ptr=='*') + ignore=1; + else + subtype=*ptr; + ptr++; + } + + type=*ptr++; + + if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[') + { do /* ignore leading whitespace characters */ + NEXT(c); + while(isspace(c)); + size=1; } /* The first non-whitespace character is already read */ + + switch(type) + { case 'c': + { unsigned char *bp; + + if(width==ULONG_MAX) /* Default */ + width=1; + + if(!ignore) + bp=va_arg(args,unsigned char *); + else + bp=NULL; /* Just to get the compiler happy */ + + NEXT(c); /* 'c' did not skip whitespace */ + while(VAL(c!=EOF)) + { if(!ignore) + *bp++=c; + NEXT(c); + } + PREV(c); + + if(!ignore&&size) + blocks++; + break; + } + case '[': + { unsigned char *bp; + unsigned char tab[32],a,b; + char circflag=0; + + if(*ptr=='^') + { circflag=1; + ptr++; } + for(i=0;i malformatted */ + { PREV(c); + c=__decimalpoint[0]; } + } + + if(min&&size==2) /* No number read till now -> malformatted */ + { PREV(c); + c=min; } + if(size==1) + break; + + if(VAL(tolower(c)=='e')) + { int d; + NEXT(d); + if(VAL(d=='-'||d=='+')) + { mine=d; + NEXT(d); } + + if(VAL(isdigit(d))) + { do + { ex=ex*10+(d-'0'); + NEXT(d); + }while(VAL(isdigit(d)&&ex<100)); + c=d; + }else + { PREV(d); + if(mine) + PREV(mine); + } + } + PREV(c); + + if(mine=='-') + v=v/pow(10.0,ex); + else + v=v*pow(10.0,ex); + + if(min=='-') + v=-v; + + }while(0); + + if(!ignore&&size) + { switch(subtype) + { case 'l': + case 'L': + *va_arg(args,double *)=v; + break; + case 'i': + *va_arg(args,float *)=v; + break; + } + blocks++; + } + break; + } +#endif + case '%': + NEXT(c); + if(c!='%') + PREV(c); /* unget non-'%' character */ + break; + case 'n': + if(!ignore) + *va_arg(args,int *)=incount; + size=1; /* fake a valid argument */ + blocks++; + break; + default: + { unsigned long v=0; + int base; + int min=0; + + if(!type) + ptr--; /* unparse NUL character */ + + if(type=='p') + { subtype='l'; /* This is the same as %lx */ + type='x'; } + + if(VAL((c=='-'&&type!='u')||c=='+')) + { min=c; + NEXT(c); } + + if(type=='i') /* which one to use ? */ + { if(VAL(c=='0')) /* Could be octal or sedecimal */ + { int d; + NEXT(d); /* Get a look at next character */ + if(VAL(tolower(d)=='x')) + { int e; + NEXT(e); /* And the next */ + if(VAL(isxdigit(c))) + type='x'; /* Is a valid x number with '0x?' */ + PREV(e); + }else + type='o'; + PREV(d); + }else if(VAL(!isdigit(c)&&isxdigit(c))) + type='x'; /* Is a valid x number without '0x' */ + } + + while(type=='x'&&VAL(c=='0')) /* sedecimal */ + { int d; + NEXT(d); + if(VAL(tolower(d)=='x')) + { int e; + NEXT(e); + if(VAL(isxdigit(e))) + { c=e; + break; } /* Used while just to do this ;-) */ + PREV(e); + } + PREV(d); + break; /* Need no loop */ + } + + base=type=='x'||type=='X'?16:(type=='o'?8:10); + while(VAL(isxdigit(c)&&(base!=10||isdigit(c))&&(base!=8||c<='7'))) + { v=v*base+(isdigit(c)?c-'0':0)+(isupper(c)?c-'A'+10:0)+(islower(c)?c-'a'+10:0); + NEXT(c); + } + + if(min&&size==2) /* If there is no valid character after sign, unget last */ + { PREV(c); + c=min; } + + PREV(c); + + if(ignore||!size) + break; + + if(type=='u') + switch(subtype) + { case 'l': + case 'L': + *va_arg(args,unsigned long *)=v; + break; + case 'i': + *va_arg(args,unsigned int *)=v; + break; + case 'h': + *va_arg(args,unsigned short *)=v; + break; + } + else + { signed long v2; + if(min=='-') + v2=-v; + else + v2=v; + switch(subtype) + { case 'l': + case 'L': + *va_arg(args,signed long *)=v2; + break; + case 'i': + *va_arg(args,signed int *)=v2; + break; + case 'h': + *va_arg(args,signed short *)=v2; + break; + } + } + blocks++; + break; + } + } + format=(const char *)ptr; + }else + { if(isspace(*format)) + { do + NEXT(c); + while(isspace(c)); + PREV(c); + size=1; } + else + { NEXT(c); + if(c!=*format) + PREV(c); } + format++; + } + if(!size) + break; + } + + if(c==EOF&&!blocks) + return c; + else + return blocks; +} -- cgit v1.2.3