#include "dietfeatures.h" #include #include #include #include #include #include "dietstdio.h" #include "dietwarning.h" #define A_GETC(fn) (++consumed,(fn)->getch((fn)->data)) #define A_PUTC(c,fn) (--consumed,(fn)->putch((c),(fn)->data)) int __v_scanf(struct arg_scanf* fn, const char *format, va_list arg_ptr) { unsigned int ch; /* format act. char */ int n=0; /* arg_ptr tmps */ #ifdef WANT_FLOATING_POINT_IN_SCANF double *pd; float *pf; #endif #ifdef WANT_LONGLONG_SCANF long long *pll; #endif long *pl; short *ph; int *pi; char *s; unsigned int consumed=0; /* get one char */ int tpch= A_GETC(fn); //while ((tpch!=-1)&&(*format)) while (*format) { ch=*format++; switch (ch) { /* end of format string ?!? */ case 0: return 0; /* skip spaces ... */ case ' ': case '\f': case '\t': case '\v': case '\n': case '\r': while((*format)&&(isspace(*format))) ++format; while(isspace(tpch)) tpch=A_GETC(fn); break; /* format string ... */ case '%': { unsigned int _div=0; int width=-1; char flag_width=0; char flag_discard=0; char flag_half=0; char flag_long=0; char flag_longlong=0; in_scan: ch=*format++; if(ch!='n' && tpch==-1) goto err_out; switch (ch) { /* end of format string ?!? */ case 0: return 0; /* check for % */ case '%': if ((unsigned char)tpch != ch) goto err_out; tpch=A_GETC(fn); break; /* FLAGS */ case '*': flag_discard=1; goto in_scan; case 'h': flag_half=1; goto in_scan; case 'l': if (flag_long) flag_longlong=1; flag_long=1; goto in_scan; case 'q': case 'L': flag_longlong=1; goto in_scan; /* WIDTH */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': width=strtol(format-1,&s,10); format=s; flag_width=1; goto in_scan; /* scan for integer / strtol reimplementation ... */ case 'p': case 'X': case 'x': _div+=6; case 'd': _div+=2; case 'o': _div+=8; case 'u': case 'i': { #ifdef WANT_LONGLONG_SCANF unsigned long long v=0; #else unsigned long v=0; #endif unsigned int consumedsofar; int neg=0; while(isspace(tpch)) tpch=A_GETC(fn); if (tpch=='-') { tpch=A_GETC(fn); neg=1; } if (tpch=='+') tpch=A_GETC(fn); if (tpch==-1) return n; consumedsofar=consumed; if (!flag_width) { if ((_div==16) && (tpch=='0')) goto scan_hex; if (!_div) { _div=10; if (tpch=='0') { _div=8; scan_hex: tpch=A_GETC(fn); if ((tpch|32)=='x') { tpch=A_GETC(fn); _div=16; } } } } while ((width)&&(tpch!=-1)) { register unsigned long c=tpch&0xff; #ifdef WANT_LONGLONG_SCANF register unsigned long long d=c|0x20; #else register unsigned long d=c|0x20; #endif c=(d>='a'?d-'a'+10:c<='9'?c-'0':0xff); if (c>=_div) break; d=v*_div; #ifdef WANT_LONGLONG_SCANF v=(d=-((unsigned long long)LLONG_MIN)) { l=(neg)?LLONG_MIN:LLONG_MAX; } else { if (neg) v*=-1; } #else register long l=v; if (v>=-((unsigned long)LONG_MIN)) { l=(neg)?LONG_MIN:LONG_MAX; } else { if (neg) v*=-1; } #endif } if (!flag_discard) { #ifdef WANT_LONGLONG_SCANF if (flag_longlong) { pll=(long long *)va_arg(arg_ptr,long long*); *pll=v; } else #endif if (flag_long) { pl=(long *)va_arg(arg_ptr,long*); *pl=v; } else if (flag_half) { ph=(short*)va_arg(arg_ptr,short*); *ph=v; } else { pi=(int *)va_arg(arg_ptr,int*); *pi=v; } if(consumedsofar error */ while (width && (tpch!=-1) && (!isspace(tpch))) { if (!flag_discard) *s=tpch; if (tpch) ++s; else break; --width; tpch=A_GETC(fn); } if (!flag_discard) { *s=0; ++n; } break; /* consumed-count */ case 'n': if (!flag_discard) { pi=(int *)va_arg(arg_ptr,int *); // ++n; /* in accordance to ANSI C we don't count this conversion */ *pi=consumed-1; } break; #ifdef WANT_CHARACTER_CLASSES_IN_SCANF case '[': { char cset[256]; int flag_not=0; int flag_dash=0; memset(cset,0,sizeof(cset)); ch=*format++; /* first char specials */ if (ch=='^') { flag_not=1; ch=*format++; } if ((ch=='-')||(ch==']')) { cset[ch]=1; ch=*format++; } /* almost all non special chars */ for (;(*format) && (*format!=']');++format) { if (flag_dash) { register unsigned char tmp=*format; for (;ch<=tmp;++ch) cset[ch]=1; flag_dash=0; ch=*format; } else if (*format=='-') flag_dash=1; else { cset[ch]=1; ch=*format; } } /* last char specials */ if (flag_dash) cset['-']=1; else cset[ch]=1; /* like %c or %s */ if (!flag_discard) { s=(char *)va_arg(arg_ptr,char*); ++n; } while (width && (tpch>=0) && (cset[tpch]^flag_not)) { if (!flag_discard) *s=tpch; if (tpch) ++s; else break; --width; tpch=A_GETC(fn); } if (!flag_discard) *s=0; ++format; } break; #endif default: goto err_out; } } break; /* check if equal format string... */ default: if ((unsigned char)tpch != ch) goto err_out; tpch=A_GETC(fn); break; } } /* maybe a "%n" follows */ if(*format) { while(isspace(*format)) format++; if(format[0] == '%' && format[1] == 'n') { pi = (int *) va_arg(arg_ptr, int *); *pi = consumed - 1; } } err_out: if (tpch<0 && n==0) return EOF; A_PUTC(tpch,fn); return n; } link_warning("__v_scanf","warning: the scanf functions add several kilobytes of bloat.");