Main Page | File List | Globals

src/printf.c

Go to the documentation of this file.
00001 /*
00002      This file is part of PlibC.
00003      (C) 2005 Nils Durner (and other contributing authors)
00004 
00005            This library is free software; you can redistribute it and/or
00006            modify it under the terms of the GNU Lesser General Public
00007            License as published by the Free Software Foundation; either
00008            version 2.1 of the License, or (at your option) any later version.
00009         
00010            This library is distributed in the hope that it will be useful,
00011            but WITHOUT ANY WARRANTY; without even the implied warranty of
00012            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013            Lesser General Public License for more details.
00014         
00015            You should have received a copy of the GNU Lesser General Public
00016            License along with this library; if not, write to the Free Software
00017            Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00028 /* Stolen from Felix von Leitners "diet libc" 0.28 */
00029 
00030 #include <stdarg.h>
00031 #include <sys/types.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <limits.h>
00037 #include <ctype.h>
00038 #include <io.h>
00039 
00040 #define WANT_ERROR_PRINTF 1
00041 #define WANT_LONGLONG_PRINTF 1
00042 #define WANT_NULL_PRINTF 1
00043 #define WANT_FLOATING_POINT_IN_PRINTF 1
00044 
00045 #define WANT_FLOATING_POINT_IN_SCANF
00046 #define WANT_LONGLONG_SCANF
00047 #define WANT_CHARACTER_CLASSES_IN_SCANF
00048 
00049 struct str_data {
00050   unsigned char* str;
00051   size_t len;
00052   size_t size;
00053 };
00054 
00055 struct arg_printf {
00056   void *data;
00057   int (*put)(void*,size_t,void*);
00058 };
00059 
00060 static inline unsigned int skip_to(const unsigned char *format) {
00061   unsigned int nr;
00062   for (nr=0; format[nr] && (format[nr]!='%'); ++nr);
00063   return nr;
00064 }
00065 
00066 #define A_WRITE(fn,buf,sz)      ((fn)->put((void*)(buf),(sz),(fn)->data))
00067 
00068 static const char pad_line[2][16]= { "                ", "0000000000000000", };
00069 static inline int write_pad(struct arg_printf* fn, int len, int padwith) {
00070   int nr=0;
00071   for (;len>15;len-=16,nr+=16) {
00072     A_WRITE(fn,pad_line[(padwith=='0')?1:0],16);
00073   }
00074   if (len>0) {
00075     A_WRITE(fn,pad_line[(padwith=='0')?1:0],(unsigned int)len); nr+=len;
00076   }
00077   return nr;
00078 }
00079 
00080 int __lltostr(char *s, int size, unsigned long long i, int base, char UpCase)
00081 {
00082   char *tmp;
00083   unsigned int j=0;
00084 
00085   s[--size]=0;
00086 
00087   tmp=s+size;
00088 
00089   if ((base==0)||(base>36)) base=10;
00090 
00091   j=0;
00092   if (!i)
00093   {
00094     *(--tmp)='0';
00095     j=1;
00096   }
00097 
00098   while((tmp>s)&&(i))
00099   {
00100     tmp--;
00101     if ((*tmp=i%base+'0')>'9') *tmp+=(UpCase?'A':'a')-'9'-1;
00102     i=i/base;
00103     j++;
00104   }
00105   memmove(s,tmp,j+1);
00106 
00107   return j;
00108 }
00109 
00110 int __ltostr(char *s, unsigned int size, unsigned long i, unsigned int base, int UpCase)
00111 {
00112   char *tmp;
00113   unsigned int j=0;
00114 
00115   s[--size]=0;
00116 
00117   tmp=s+size;
00118 
00119   if ((base==0)||(base>36)) base=10;
00120 
00121   j=0;
00122   if (!i)
00123   {
00124     *(--tmp)='0';
00125     j=1;
00126   }
00127 
00128   while((tmp>s)&&(i))
00129   {
00130     tmp--;
00131     if ((*tmp=i%base+'0')>'9') *tmp+=(UpCase?'A':'a')-'9'-1;
00132     i=i/base;
00133     j++;
00134   }
00135   memmove(s,tmp,j+1);
00136 
00137   return j;
00138 }
00139 
00140 static int copystring(char* buf,int maxlen, const char* s) {
00141   int i;
00142   for (i=0; i<3&&i<maxlen; ++i)
00143     buf[i]=s[i];
00144   if (i<maxlen) { buf[i]=0; ++i; }
00145   return i;
00146 }
00147 
00148 int isinf(double d) {
00149   union {
00150     unsigned long long l;
00151     double d;
00152   } u;
00153   u.d=d;
00154   return (u.l==0x7FF0000000000000ll?1:u.l==0xFFF0000000000000ll?-1:0);
00155 }
00156 
00157 int isnan(double d) {
00158   union {
00159     unsigned long long l;
00160     double d;
00161   } u;
00162   u.d=d;
00163   return (u.l==0x7FF8000000000000ll || u.l==0x7FF0000000000000ll || u.l==0xfff8000000000000ll);
00164 }
00165 
00166 int __dtostr(double d,char *buf,unsigned int maxlen,unsigned int prec,unsigned int prec2) {
00167 #if 1
00168   union {
00169     unsigned long long l;
00170     double d;
00171   } u = { .d=d };
00172   /* step 1: extract sign, mantissa and exponent */
00173   signed long e=((u.l>>52)&((1<<11)-1))-1023;
00174 #else
00175 #if __BYTE_ORDER == __LITTLE_ENDIAN
00176   signed long e=(((((unsigned long*)&d)[1])>>20)&((1<<11)-1))-1023;
00177 #else
00178   signed long e=(((*((unsigned long*)&d))>>20)&((1<<11)-1))-1023;
00179 #endif
00180 #endif
00181 /*  unsigned long long m=u.l & ((1ull<<52)-1); */
00182   /* step 2: exponent is base 2, compute exponent for base 10 */
00183   signed long e10;
00184   /* step 3: calculate 10^e10 */
00185   unsigned int i;
00186   double backup=d;
00187   double tmp;
00188   char *oldbuf=buf;
00189 
00190   if ((i=isinf(d))) return copystring(buf,maxlen,i>0?"inf":"-inf");
00191   if (isnan(d)) return copystring(buf,maxlen,"nan");
00192   e10=1+(long)(e*0.30102999566398119802); /* log10(2) */
00193   /* Wir iterieren von Links bis wir bei 0 sind oder maxlen erreicht
00194    * ist.  Wenn maxlen erreicht ist, machen wir das nochmal in
00195    * scientific notation.  Wenn dann von prec noch was übrig ist, geben
00196    * wir einen Dezimalpunkt aus und geben prec2 Nachkommastellen aus.
00197    * Wenn prec2 Null ist, geben wir so viel Stellen aus, wie von prec
00198    * noch übrig ist. */
00199   if (d==0.0) {
00200     prec2=prec2==0?1:prec2+2;
00201     prec2=prec2>maxlen?8:prec2;
00202     i=0;
00203     if (prec2 && (long long)u.l<0) { buf[0]='-'; ++i; }
00204     for (; i<prec2; ++i) buf[i]='0';
00205     buf[buf[0]=='0'?1:2]='.'; buf[i]=0;
00206     return i;
00207   }
00208 
00209   if (d < 0.0) { d=-d; *buf='-'; --maxlen; ++buf; }
00210 
00211    /*
00212       Perform rounding. It needs to be done before we generate any
00213       digits as the carry could propagate through the whole number.
00214    */
00215 
00216   tmp = 0.5;
00217   for (i = 0; i < prec2; i++) { tmp *= 0.1; }
00218   d += tmp;
00219 
00220   if (d < 1.0) { *buf='0'; --maxlen; ++buf; }
00221 /*  printf("e=%d e10=%d prec=%d\n",e,e10,prec); */
00222   if (e10>0) {
00223     int first=1;        /* are we about to write the first digit? */
00224     tmp = 10.0;
00225     i=e10;
00226     while (i>10) { tmp=tmp*1e10; i-=10; }
00227     while (i>1) { tmp=tmp*10; --i; }
00228     /* the number is greater than 1. Iterate through digits before the
00229      * decimal point until we reach the decimal point or maxlen is
00230      * reached (in which case we switch to scientific notation). */
00231     while (tmp>0.9) {
00232       char digit;
00233       double fraction=d/tmp;
00234         digit=(int)(fraction);          /* floor() */
00235       if (!first || digit) {
00236         first=0;
00237         *buf=digit+'0'; ++buf;
00238         if (!maxlen) {
00239           /* use scientific notation */
00240           int len=__dtostr(backup/tmp,oldbuf,maxlen,prec,prec2);
00241           int initial=1;
00242           if (len==0) return 0;
00243           maxlen-=len; buf+=len;
00244           if (maxlen>0) {
00245             *buf='e';
00246             ++buf;
00247           }
00248           --maxlen;
00249           for (len=1000; len>0; len/=10) {
00250             if (e10>=len || !initial) {
00251               if (maxlen>0) {
00252                 *buf=(e10/len)+'0';
00253                 ++buf;
00254               }
00255               --maxlen;
00256               initial=0;
00257               e10=e10%len;
00258             }
00259           }
00260           if (maxlen>0) goto fini;
00261           return 0;
00262         }
00263         d-=digit*tmp;
00264         --maxlen;
00265       }
00266       tmp/=10.0;
00267     }
00268   }
00269   else
00270   {
00271      tmp = 0.1;
00272   }
00273 
00274   if (buf==oldbuf) {
00275     if (!maxlen) return 0; --maxlen;
00276     *buf='0'; ++buf;
00277   }
00278   if (prec2 || prec>(unsigned int)(buf-oldbuf)+1) {     /* more digits wanted */
00279     if (!maxlen) return 0; --maxlen;
00280     *buf='.'; ++buf;
00281     prec-=buf-oldbuf-1;
00282     if (prec2) prec=prec2;
00283     if (prec>maxlen) return 0;
00284     while (prec>0) {
00285       char digit;
00286       double fraction=d/tmp;
00287       digit=(int)(fraction);            /* floor() */
00288       *buf=digit+'0'; ++buf;
00289       d-=digit*tmp;
00290       tmp/=10.0;
00291       --prec;
00292     }
00293   }
00294 fini:
00295   *buf=0;
00296   return buf-oldbuf;
00297 }
00298 
00299 int __v_printf(struct arg_printf* fn, const unsigned char *format, va_list arg_ptr)
00300 {
00301   int len=0;
00302 #ifdef WANT_ERROR_PRINTF
00303   int _my_errno = errno;
00304 #endif
00305 
00306   while (*format) {
00307     unsigned int sz = skip_to(format);
00308     if (sz) {
00309       A_WRITE(fn,format,sz); len+=sz;
00310       format+=sz;
00311     }
00312     if (*format=='%') {
00313       char buf[128];
00314       union { char*s; } u_str;
00315 #define s u_str.s
00316 
00317       int retval;
00318       unsigned char ch, padwith=' ';
00319 
00320       char flag_in_sign=0;
00321       char flag_upcase=0;
00322       char flag_hash=0;
00323       char flag_left=0;
00324       char flag_space=0;
00325       char flag_sign=0;
00326       char flag_dot=0;
00327       signed char flag_long=0;
00328 
00329       unsigned int base;
00330       unsigned int width=0, preci=0;
00331 
00332       long number=0;
00333 #ifdef WANT_LONGLONG_PRINTF
00334       long long llnumber=0;
00335 #endif
00336 
00337       ++format;
00338 inn_printf:
00339       switch(ch=*format++) {
00340       case 0:
00341         return -1;
00342         break;
00343 
00344       /* FLAGS */
00345       case '#':
00346         flag_hash=-1;
00347       case 'z':
00348         goto inn_printf;
00349 
00350       case 'h':
00351         --flag_long;
00352         goto inn_printf;
00353       case 'q':         /* BSD ... */
00354       case 'L':
00355         ++flag_long; /* fall through */
00356       case 'l':
00357         ++flag_long;
00358         goto inn_printf;
00359 
00360       case '-':
00361         flag_left=1;
00362         goto inn_printf;
00363 
00364       case ' ':
00365         flag_space=1;
00366         goto inn_printf;
00367 
00368       case '+':
00369         flag_sign=1;
00370         goto inn_printf;
00371 
00372       case '0':
00373       case '1':
00374       case '2':
00375       case '3':
00376       case '4':
00377       case '5':
00378       case '6':
00379       case '7':
00380       case '8':
00381       case '9':
00382         if(flag_dot) return -1;
00383         width=strtoul(format-1,(char**)&s,10);
00384         if (ch=='0' && !flag_left) padwith='0';
00385         format=s;
00386         goto inn_printf;
00387 
00388       case '*':
00389         width=va_arg(arg_ptr,int);
00390         goto inn_printf;
00391 
00392       case '.':
00393         flag_dot=1;
00394         if (*format=='*') {
00395           int tmp=va_arg(arg_ptr,int);
00396           preci=tmp<0?0:tmp;
00397           ++format;
00398         } else {
00399           long int tmp=strtol(format,(char**)&s,10);
00400           preci=tmp<0?0:tmp;
00401           format=s;
00402         }
00403         goto inn_printf;
00404 
00405       /* print a char or % */
00406       case 'c':
00407         ch=(char)va_arg(arg_ptr,int);
00408       case '%':
00409         A_WRITE(fn,&ch,1); ++len;
00410         break;
00411 
00412 #ifdef WANT_ERROR_PRINTF
00413       /* print an error message */
00414       case 'm':
00415         s=strerror(_my_errno);
00416         sz=strlen(s);
00417         A_WRITE(fn,s,sz); len+=sz;
00418         break;
00419 #endif
00420       /* print a string */
00421       case 's':
00422         s=va_arg(arg_ptr,char *);
00423 #ifdef WANT_NULL_PRINTF
00424         if (!s) s="(null)";
00425 #endif
00426         sz = strlen(s);
00427         if (flag_dot && sz>preci) sz=preci;
00428         preci=0;
00429         flag_dot^=flag_dot;
00430         padwith=' ';
00431 
00432 print_out:
00433       {
00434         char *sign=s;
00435         int todo=0;
00436         int vs;
00437         
00438         if (! (width||preci) ) {
00439           A_WRITE(fn,s,sz); len+=sz;
00440           break;
00441         }
00442         
00443         if (flag_in_sign) todo=1;
00444         if (flag_hash>0)  todo=flag_hash;
00445         if (todo) {
00446           s+=todo;
00447           sz-=todo;
00448           width-=todo;
00449         }
00450         
00451         if (!flag_left) {
00452           if (flag_dot) {
00453             vs=preci>sz?preci:sz;
00454             len+=write_pad(fn,(signed int)width-(signed int)vs,' ');
00455             if (todo) {
00456               A_WRITE(fn,sign,todo);
00457               len+=todo;
00458             }
00459             len+=write_pad(fn,(signed int)preci-(signed int)sz,'0');
00460           } else {
00461             if (todo && padwith=='0') {
00462               A_WRITE(fn,sign,todo);
00463               len+=todo; todo=0;
00464             }
00465             len+=write_pad(fn,(signed int)width-(signed int)sz, padwith);
00466             if (todo) {
00467               A_WRITE(fn,sign,todo);
00468               len+=todo;
00469             }
00470           }
00471           A_WRITE(fn,s,sz); len+=sz;
00472         } else if (flag_left) {
00473           if (todo) {
00474             A_WRITE(fn,sign,todo);
00475             len+=todo;
00476           }
00477           len+=write_pad(fn,(signed int)preci-(signed int)sz, '0');
00478           A_WRITE(fn,s,sz); len+=sz;
00479           vs=preci>sz?preci:sz;
00480           len+=write_pad(fn,(signed int)width-(signed int)vs, ' ');
00481         } else {
00482           A_WRITE(fn,s,sz); len+=sz;
00483         }
00484         break;
00485       }
00486 
00487       /* print an integer value */
00488       case 'b':
00489         base=2;
00490         sz=0;
00491         goto num_printf;
00492       case 'p':
00493         flag_hash=2;
00494         flag_long=1;
00495         ch='x';
00496       case 'X':
00497         flag_upcase=(ch=='X');
00498       case 'x':
00499         base=16;
00500         sz=0;
00501         if (flag_hash) {
00502           buf[1]='0';
00503           buf[2]=ch;
00504           flag_hash=2;
00505           sz=2;
00506         }
00507         if (preci>width) width=preci;
00508         goto num_printf;
00509       case 'd':
00510       case 'i':
00511         flag_in_sign=1;
00512       case 'u':
00513         base=10;
00514         sz=0;
00515         goto num_printf;
00516       case 'o':
00517         base=8;
00518         sz=0;
00519         if (flag_hash) {
00520           buf[1]='0';
00521           flag_hash=1;
00522           ++sz;
00523         }
00524 
00525 num_printf:
00526         s=buf+1;
00527 
00528         if (flag_long>0) {
00529 #ifdef WANT_LONGLONG_PRINTF
00530           if (flag_long>1)
00531             llnumber=va_arg(arg_ptr,long long);
00532           else
00533 #endif
00534             number=va_arg(arg_ptr,long);
00535         }
00536         else
00537           number=va_arg(arg_ptr,int);
00538 
00539         if (flag_in_sign) {
00540 #ifdef WANT_LONGLONG_PRINTF
00541           if ((flag_long>1)&&(llnumber<0)) {
00542             llnumber=-llnumber;
00543             flag_in_sign=2;
00544           } else
00545 #endif
00546             if (number<0) {
00547               number=-number;
00548               flag_in_sign=2;
00549             }
00550         }
00551         if (flag_long<0) number&=0xffff;
00552         if (flag_long<-1) number&=0xff;
00553 #ifdef WANT_LONGLONG_PRINTF
00554         if (flag_long>1)
00555           retval = __lltostr(s+sz,sizeof(buf)-5,(unsigned long long) llnumber,base,flag_upcase);
00556         else
00557 #endif
00558           retval = __ltostr(s+sz,sizeof(buf)-5,(unsigned long) number,base,flag_upcase);
00559 
00560         /* When 0 is printed with an explicit precision 0, the output is empty. */
00561         if (flag_dot && retval == 1 && s[sz] == '0') {
00562           if (preci == 0||flag_hash > 0) {
00563             sz = 0;
00564           }
00565           flag_hash = 0;
00566         } else sz += retval;
00567 
00568         if (flag_in_sign==2) {
00569           *(--s)='-';
00570           ++sz;
00571         } else if ((flag_in_sign)&&(flag_sign || flag_space)) {
00572           *(--s)=(flag_sign)?'+':' ';
00573           ++sz;
00574         } else flag_in_sign=0;
00575 
00576         goto print_out;
00577 
00578 #ifdef WANT_FLOATING_POINT_IN_PRINTF
00579       /* print a floating point value */
00580       case 'f':
00581       case 'g':
00582         {
00583           int g=(ch=='g');
00584           double d=va_arg(arg_ptr,double);
00585           s=buf+1;
00586           if (width==0) width=1;
00587           if (!flag_dot) preci=6;
00588           if (flag_sign || d < +0.0) flag_in_sign=1;
00589         
00590           sz=__dtostr(d,s,sizeof(buf)-1,width,preci);
00591         
00592           if (flag_dot) {
00593             char *tmp;
00594             if ((tmp=strchr(s,'.'))) {
00595               if (preci || flag_hash) ++tmp;
00596               while (preci>0 && *++tmp) --preci;
00597               *tmp=0;
00598             } else if (flag_hash) {
00599               s[sz]='.';
00600               s[++sz]='\0';
00601             }
00602           }
00603 
00604           if (g) {
00605             char *tmp,*tmp1;    /* boy, is _this_ ugly! */
00606             if ((tmp=strchr(s,'.'))) {
00607               tmp1=strchr(tmp,'e');
00608               while (*tmp) ++tmp;
00609               if (tmp1) tmp=tmp1;
00610               while (*--tmp=='0') ;
00611               if (*tmp!='.') ++tmp;
00612               *tmp=0;
00613               if (tmp1) strcpy(tmp,tmp1);
00614             }
00615           }
00616         
00617           if ((flag_sign || flag_space) && d>=0) {
00618             *(--s)=(flag_sign)?'+':' ';
00619             ++sz;
00620           }
00621         
00622           sz=strlen(s);
00623           flag_dot=0;
00624           flag_hash=0;
00625           goto print_out;
00626         }
00627 #endif
00628 
00629       default:
00630         break;
00631       }
00632     }
00633   }
00634   return len;
00635 }
00636 
00637 #undef s
00638 
00639 static int swrite(void*ptr, size_t nmemb, struct str_data* sd) {
00640   size_t tmp=sd->size-sd->len;
00641   if (tmp>0) {
00642     size_t len=nmemb;
00643     if (len>tmp) len=tmp;
00644     if (sd->str) {
00645       memcpy(sd->str+sd->len,ptr,len);
00646       sd->str[sd->len+len]=0;
00647     }
00648     sd->len+=len;
00649   }
00650   return nmemb;
00651 }
00652 
00653 int _win_vsnprintf(char* str, size_t size, const char *format, va_list arg_ptr)
00654 {
00655   long n;
00656   struct str_data sd = { str, 0, size?size-1:0 };
00657   struct arg_printf ap = { &sd, (int(*)(void*,size_t,void*)) swrite };
00658   n=__v_printf(&ap,format,arg_ptr);
00659   if (str && size && n>=0) {
00660     if (size!=(size_t)-1 && ((size_t)n>=size)) str[size-1]=0;
00661     else str[n]=0;
00662   }
00663   return n;
00664 }
00665 
00666 int _win_vsprintf(char *dest, const char *format, va_list arg_ptr)
00667 {
00668   return _win_vsnprintf(dest,(size_t)-1,format,arg_ptr);
00669 }
00670 
00671 static int __fwrite(void*ptr, size_t nmemb, int fd) {
00672   return fwrite(ptr, 1, nmemb, fd);
00673 }
00674 
00675 int _win_vfprintf(FILE *stream, const char *format, va_list arg_ptr)
00676 {
00677   struct arg_printf ap = { stream, (int(*)(void*,size_t,void*)) __fwrite };
00678   return __v_printf(&ap,format,arg_ptr);
00679 }
00680 
00681 int __stdio_outs(const char *s, size_t len) {
00682   return (fwrite(s, 1, len, stdout)==(int)len)?1:0;
00683 }
00684 
00685 int _win_vprintf(const char *format, va_list ap)
00686 {
00687   struct arg_printf _ap = { 0, (int(*)(void*,size_t,void*)) __stdio_outs };
00688   return __v_printf(&_ap,format,ap);
00689 }
00690 
00691 int _win_fprintf(FILE *f,const char *format, ...)
00692 {
00693   int n;
00694   va_list arg_ptr;
00695   va_start(arg_ptr,format);
00696   n=_win_vfprintf(f,format,arg_ptr);
00697   va_end(arg_ptr);
00698   return n;
00699 }
00700 
00701 int _win_printf(const char *format, ...)
00702 {
00703   int n;
00704   va_list arg_ptr;
00705   va_start(arg_ptr, format);
00706   n=_win_vprintf(format, arg_ptr);
00707   va_end(arg_ptr);
00708   return n;
00709 }
00710 
00711 int _win_snprintf(char *str, size_t size, const char *format, ...)
00712 {
00713   int n;
00714   va_list arg_ptr;
00715   va_start(arg_ptr, format);
00716   n=vsnprintf(str,size,format,arg_ptr);
00717   va_end (arg_ptr);
00718   return n;
00719 }
00720 
00721 int _win_sprintf(char *dest, const char *format, ...)
00722 {
00723   int n;
00724   va_list arg_ptr;
00725   va_start(arg_ptr, format);
00726   n=vsprintf(dest,format,arg_ptr);
00727   va_end (arg_ptr);
00728   return n;
00729 }
00730 
00731 #define A_GETC(fn)  (++consumed,(fn)->getch((fn)->data))
00732 #define A_PUTC(c,fn)  (--consumed,(fn)->putch((c),(fn)->data))
00733 
00734 struct arg_scanf {
00735   void *data;
00736   int (*getch)(void*);
00737   int (*putch)(int,void*);
00738 };
00739 
00740 int __v_scanf(struct arg_scanf* fn, const unsigned char *format, va_list arg_ptr)
00741 {
00742   unsigned int ch;  /* format act. char */
00743   int n=0;
00744 
00745   /* arg_ptr tmps */
00746 #ifdef WANT_FLOATING_POINT_IN_SCANF
00747   double *pd;
00748   float  *pf;
00749 #endif
00750 #ifdef WANT_LONGLONG_SCANF
00751   long long *pll;
00752 #endif
00753   long   *pl;
00754   short  *ph;
00755   int    *pi;
00756   char    *s;
00757 
00758   unsigned int consumed=0;
00759 
00760   /* get one char */
00761   int tpch= A_GETC(fn);
00762 
00763   //while ((tpch!=-1)&&(*format))
00764   while (*format)
00765   {
00766     ch=*format++;
00767     switch (ch) {
00768     /* end of format string ?!? */
00769     case 0: return 0;
00770 
00771     /* skip spaces ... */
00772     case ' ':
00773     case '\f':
00774     case '\t':
00775     case '\v':
00776     case '\n':
00777     case '\r':
00778       while((*format)&&(isspace(*format))) ++format;
00779       while(isspace(tpch)) tpch=A_GETC(fn);
00780       break;
00781 
00782     /* format string ... */
00783     case '%':
00784       {
00785   unsigned int _div=0;
00786   int width=-1;
00787   char flag_width=0;
00788   char flag_discard=0;
00789   char flag_half=0;
00790   char flag_long=0;
00791   char flag_longlong=0;
00792 
00793 in_scan:
00794   ch=*format++;
00795   if(ch!='n' && tpch==-1) goto err_out;
00796   switch (ch) {
00797   /* end of format string ?!? */
00798   case 0: return 0;
00799 
00800   /* check for % */
00801   case '%':
00802     if ((unsigned char)tpch != ch) goto err_out;
00803     tpch=A_GETC(fn);
00804     break;
00805 
00806   /* FLAGS */
00807   case '*':
00808     flag_discard=1;
00809     goto in_scan;
00810   case 'h':
00811     flag_half=1;
00812     goto in_scan;
00813   case 'l':
00814     if (flag_long) flag_longlong=1;
00815     flag_long=1;
00816     goto in_scan;
00817   case 'q':
00818   case 'L':
00819     flag_longlong=1;
00820     goto in_scan;
00821 
00822   /* WIDTH */
00823   case '0':
00824   case '1':
00825   case '2':
00826   case '3':
00827   case '4':
00828   case '5':
00829   case '6':
00830   case '7':
00831   case '8':
00832   case '9':
00833     width=strtol(format-1,&s,10);
00834     format=s;
00835     flag_width=1;
00836     goto in_scan;
00837 
00838   /* scan for integer / strtol reimplementation ... */
00839   case 'p':
00840   case 'X':
00841   case 'x':
00842     _div+=6;
00843   case 'd':
00844     _div+=2;
00845   case 'o':
00846     _div+=8;
00847   case 'u':
00848   case 'i':
00849     {
00850 #ifdef WANT_LONGLONG_SCANF
00851       unsigned long long v=0;
00852 #else
00853       unsigned long v=0;
00854 #endif
00855       unsigned int consumedsofar;
00856       int neg=0;
00857       while(isspace(tpch)) tpch=A_GETC(fn);
00858       if (tpch=='-') {
00859         tpch=A_GETC(fn);
00860         neg=1;
00861       }
00862 
00863       if (tpch=='+') tpch=A_GETC(fn);
00864 
00865       if (tpch==-1) return n;
00866       consumedsofar=consumed;
00867 
00868       if (!flag_width) {
00869         if ((_div==16) && (tpch=='0')) goto scan_hex;
00870         if (!_div) {
00871     _div=10;
00872     if (tpch=='0') {
00873       _div=8;
00874 scan_hex:
00875       tpch=A_GETC(fn);
00876       if ((tpch|32)=='x') {
00877         tpch=A_GETC(fn);
00878         _div=16;
00879       }
00880     }
00881         }
00882       }
00883       while ((width)&&(tpch!=-1)) {
00884         register unsigned long c=tpch&0xff;
00885 #ifdef WANT_LONGLONG_SCANF
00886         register unsigned long long d=c|0x20;
00887 #else
00888         register unsigned long d=c|0x20;
00889 #endif
00890         c=(d>='a'?d-'a'+10:c<='9'?c-'0':0xff);
00891         if (c>=_div) break;
00892         d=v*_div;
00893 #ifdef WANT_LONGLONG_SCANF
00894         v=(d<v)?ULLONG_MAX:d+c;
00895 #else
00896         v=(d<v)?ULONG_MAX:d+c;
00897 #endif
00898         --width;
00899         tpch=A_GETC(fn);
00900       }
00901 
00902       if (consumedsofar==consumed) return n;
00903 
00904       if ((ch|0x20)<'p') {
00905 #ifdef WANT_LONGLONG_SCANF
00906         register long long l=v;
00907         if (v>=-((unsigned long long)LLONG_MIN)) {
00908     l=(neg)?LLONG_MIN:LLONG_MAX;
00909         }
00910         else {
00911     if (neg) v*=-1;
00912         }
00913 #else
00914         register long l=v;
00915         if (v>=-((unsigned long)LONG_MIN)) {
00916     l=(neg)?LONG_MIN:LONG_MAX;
00917         }
00918         else {
00919     if (neg) v*=-1;
00920         }
00921 #endif
00922       }
00923       if (!flag_discard) {
00924 #ifdef WANT_LONGLONG_SCANF
00925         if (flag_longlong) {
00926     pll=(long long *)va_arg(arg_ptr,long long*);
00927     *pll=v;
00928         } else
00929 #endif
00930         if (flag_long) {
00931     pl=(long *)va_arg(arg_ptr,long*);
00932     *pl=v;
00933         } else if (flag_half) {
00934     ph=(short*)va_arg(arg_ptr,short*);
00935     *ph=v;
00936         } else {
00937     pi=(int *)va_arg(arg_ptr,int*);
00938     *pi=v;
00939         }
00940         if(consumedsofar<consumed) ++n;
00941       }
00942     }
00943     break;
00944 
00945   /* FIXME: return value of *scanf with ONE float maybe -1 instead of 0 */
00946 #ifdef WANT_FLOATING_POINT_IN_SCANF
00947   /* floating point numbers */
00948   case 'e':
00949   case 'E':
00950   case 'f':
00951   case 'g':
00952     {
00953       double d=0.0;
00954       int neg=0;
00955       unsigned int consumedsofar;
00956 
00957       while(isspace(tpch)) tpch=A_GETC(fn);
00958 
00959       if (tpch=='-') {
00960         tpch=A_GETC(fn);
00961         neg=1;
00962       }
00963       if (tpch=='+') tpch=A_GETC(fn);
00964 
00965       consumedsofar=consumed;
00966 
00967       while (isdigit(tpch)) {
00968         d=d*10+(tpch-'0');
00969         tpch=A_GETC(fn);
00970       }
00971       if (tpch=='.') {
00972         double factor=.1;
00973         consumedsofar++;
00974         tpch=A_GETC(fn);
00975         while (isdigit(tpch)) {
00976     d=d+(factor*(tpch-'0'));
00977     factor/=10;
00978     tpch=A_GETC(fn);
00979         }
00980       }
00981       if (consumedsofar==consumed) return n;  /* error */
00982       if ((tpch|0x20)=='e') {
00983         int exp=0, prec=tpch;
00984         double factor=10;
00985         tpch=A_GETC(fn);
00986         if (tpch=='-') {
00987     factor=0.1;
00988     tpch=A_GETC(fn);
00989         } else if (tpch=='+') {
00990     tpch=A_GETC(fn);
00991         } else {
00992     d=0;
00993     if (tpch!=-1) A_PUTC(tpch,fn);
00994     tpch=prec;
00995     goto exp_out;
00996         }
00997         consumedsofar=consumed;
00998         while (isdigit(tpch)) {
00999     exp=exp*10+(tpch-'0');
01000     tpch=A_GETC(fn);
01001         }
01002         if (consumedsofar==consumed) return n;  /* error */
01003         while (exp) { /* as in strtod: XXX: this introduces rounding errors */
01004     d*=factor; --exp;
01005         }
01006       }
01007 exp_out:
01008       if (!flag_discard) {
01009         if (flag_long) {
01010     pd=(double *)va_arg(arg_ptr,double*);
01011     *pd=d;
01012         } else {
01013     pf=(float *)va_arg(arg_ptr,float*);
01014     *pf=d;
01015         }
01016         ++n;
01017       }
01018     }
01019     break;
01020 #endif
01021 
01022   /* char-sequences */
01023   case 'c':
01024     if (!flag_discard) {
01025       s=(char *)va_arg(arg_ptr,char*);
01026       ++n;
01027     }
01028     if (!flag_width) width=1;
01029     while (width && (tpch!=-1)) {
01030       if (!flag_discard) *(s++)=tpch;
01031       --width;
01032       tpch=A_GETC(fn);
01033     }
01034     break;
01035 
01036   /* string */
01037   case 's':
01038     if (!flag_discard) s=(char *)va_arg(arg_ptr,char*);
01039     while(isspace(tpch)) tpch=A_GETC(fn);
01040     if (tpch==-1) break;    /* end of scan -> error */
01041     while (width && (tpch!=-1) && (!isspace(tpch))) {
01042       if (!flag_discard) *s=tpch;
01043       if (tpch) ++s; else break;
01044       --width;
01045       tpch=A_GETC(fn);
01046     }
01047     if (!flag_discard) { *s=0; ++n; }
01048     break;
01049 
01050   /* consumed-count */
01051   case 'n':
01052     if (!flag_discard) {
01053       pi=(int *)va_arg(arg_ptr,int *);
01054 //      ++n;  /* in accordance to ANSI C we don't count this conversion */
01055             *pi=consumed-1;
01056     }
01057     break;
01058 
01059 #ifdef WANT_CHARACTER_CLASSES_IN_SCANF
01060   case '[':
01061     {
01062       char cset[256];
01063       int flag_not=0;
01064       int flag_dash=0;
01065       memset(cset,0,sizeof(cset));
01066       ch=*format++;
01067       /* first char specials */
01068       if (ch=='^') {
01069         flag_not=1;
01070         ch=*format++;
01071       }
01072       if ((ch=='-')||(ch==']')) {
01073         cset[ch]=1;
01074         ch=*format++;
01075       }
01076       /* almost all non special chars */
01077       for (;(*format) && (*format!=']');++format) {
01078         if (flag_dash) {
01079     register unsigned char tmp=*format;
01080     for (;ch<=tmp;++ch) cset[ch]=1;
01081     flag_dash=0;
01082     ch=*format;
01083         }
01084         else if (*format=='-') flag_dash=1;
01085         else {
01086     cset[ch]=1;
01087     ch=*format;
01088         }
01089       }
01090       /* last char specials */
01091       if (flag_dash) cset['-']=1;
01092       else cset[ch]=1;
01093 
01094       /* like %c or %s */
01095       if (!flag_discard) {
01096         s=(char *)va_arg(arg_ptr,char*);
01097         ++n;
01098       }
01099       while (width && (tpch>=0) && (cset[tpch]^flag_not)) {
01100         if (!flag_discard) *s=tpch;
01101         if (tpch) ++s; else break;
01102         --width;
01103         tpch=A_GETC(fn);
01104       }
01105       if (!flag_discard) *s=0;
01106       ++format;
01107     }
01108     break;
01109 #endif
01110   default:
01111     goto err_out;
01112   }
01113       }
01114       break;
01115 
01116     /* check if equal format string... */
01117     default:
01118       if ((unsigned char)tpch != ch) goto err_out;
01119       tpch=A_GETC(fn);
01120       break;
01121     }
01122   }
01123 
01124   /* maybe a "%n" follows */
01125   if(*format) {
01126     while(isspace(*format)) format++;
01127     if(format[0] == '%' && format[1] == 'n') {
01128       pi = (int *) va_arg(arg_ptr, int *);
01129       *pi = consumed - 1;
01130     }
01131   }
01132 
01133 err_out:
01134   if (tpch<0 && n==0) return EOF;
01135   A_PUTC(tpch,fn);
01136   return n;
01137 }
01138 
01139 struct scanf_str_data {
01140   unsigned char* str;
01141 };
01142 
01143 static int sgetc(struct scanf_str_data* sd) {
01144   register unsigned int ret = *(sd->str++);
01145   return (ret)?(int)ret:-1;
01146 }
01147 
01148 static int sputc(int c, struct scanf_str_data* sd) {
01149   return (*(--sd->str)==c)?c:-1;
01150 }
01151 
01152 int _win_vsscanf(const char* str, const char* format, va_list arg_ptr)
01153 {
01154   struct scanf_str_data  fdat = { (unsigned char*)str };
01155   struct arg_scanf farg = { (void*)&fdat, (int(*)(void*))sgetc, (int(*)(int,void*))sputc };
01156   return __v_scanf(&farg,format,arg_ptr);
01157 }
01158 
01159 int _win_sscanf(const char *str, const char *format, ...)
01160 {
01161   int n;
01162   va_list arg_ptr;
01163   va_start(arg_ptr, format);
01164   n = _win_vsscanf(str,format,arg_ptr);
01165   va_end (arg_ptr);
01166   return n;
01167 }
01168 
01169 int _win_vfscanf(FILE *stream, const char *format, va_list arg_ptr)
01170 {
01171   struct arg_scanf farg = { (void*)stream, (int(*)(void*))fgetc, (int(*)(int,void*))ungetc };
01172   return __v_scanf(&farg,format,arg_ptr);
01173 }
01174 
01175 int _win_vscanf(const char *format, va_list arg_ptr)
01176 {
01177   return _win_vfscanf(stdin,format,arg_ptr);
01178 }
01179 
01180 int _win_scanf(const char *format, ...)
01181 {
01182   int n;
01183   va_list arg_ptr;
01184   va_start(arg_ptr, format);
01185   n = _win_vfscanf(stdin,format,arg_ptr);
01186   va_end (arg_ptr);
01187   return n;
01188 }
01189 
01190 int _win_fscanf(FILE *stream, const char *format, ...)
01191 {
01192   int n;
01193   va_list arg_ptr;
01194   va_start(arg_ptr, format);
01195   n = _win_vfscanf(stream,format,arg_ptr);
01196   va_end (arg_ptr);
01197   return n;
01198 }
01199 
01200 /* end of printf.c */

Generated on Sun Sep 4 11:16:47 2005 for PlibC by  doxygen 1.4.2