small_vfsscanf.c

00001 /*
00002 FUNCTION
00003 <<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
00004 
00005 INDEX
00006         vscanf
00007 INDEX
00008         vfscanf
00009 INDEX
00010         vsscanf
00011 
00012 ANSI_SYNOPSIS
00013         #include <stdio.h>
00014         #include <stdarg.h>
00015         int vscanf(const char *<[fmt]>, va_list <[list]>);
00016         int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
00017         int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
00018 
00019         int _vscanf_r(void *<[reent]>, const char *<[fmt]>, 
00020                        va_list <[list]>);
00021         int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, 
00022                        va_list <[list]>);
00023         int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[fmt]>, 
00024                        va_list <[list]>);
00025 
00026 TRAD_SYNOPSIS
00027         #include <stdio.h>
00028         #include <varargs.h>
00029         int vscanf( <[fmt]>, <[ist]>)
00030         char *<[fmt]>;
00031         va_list <[list]>;
00032 
00033         int vfscanf( <[fp]>, <[fmt]>, <[list]>)
00034         FILE *<[fp]>;
00035         char *<[fmt]>;
00036         va_list <[list]>;
00037         
00038         int vsscanf( <[str]>, <[fmt]>, <[list]>)
00039         char *<[str]>;
00040         char *<[fmt]>;
00041         va_list <[list]>;
00042 
00043         int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
00044         char *<[reent]>;
00045         char *<[fmt]>;
00046         va_list <[list]>;
00047 
00048         int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
00049         char *<[reent]>;
00050         FILE *<[fp]>;
00051         char *<[fmt]>;
00052         va_list <[list]>;
00053         
00054         int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
00055         char *<[reent]>;
00056         char *<[str]>;
00057         char *<[fmt]>;
00058         va_list <[list]>;
00059 
00060 DESCRIPTION
00061 <<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
00062 of <<scanf>>, <<fscanf>>, and <<sscanf>>.  They differ only in 
00063 allowing their caller to pass the variable argument list as a 
00064 <<va_list>> object (initialized by <<va_start>>) rather than 
00065 directly accepting a variable number of arguments.
00066 
00067 RETURNS
00068 The return values are consistent with the corresponding functions:
00069 <<vscanf>> returns the number of input fields successfully scanned,
00070 converted, and stored; the return value does not include scanned
00071 fields which were not stored.  
00072 
00073 If <<vscanf>> attempts to read at end-of-file, the return value 
00074 is <<EOF>>.
00075 
00076 If no fields were stored, the return value is <<0>>.
00077 
00078 The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
00079 reentrant versions which take an additional first parameter which points to the
00080 reentrancy structure.
00081 
00082 PORTABILITY
00083 These are GNU extensions.
00084 
00085 Supporting OS subroutines required:
00086 */
00087 
00088 /*-
00089  * Copyright (c) 1990 The Regents of the University of California.
00090  * All rights reserved.
00091  *
00092  * Redistribution and use in source and binary forms are permitted
00093  * provided that the above copyright notice and this paragraph are
00094  * duplicated in all such forms and that any documentation,
00095  * advertising materials, and other materials related to such
00096  * distribution and use acknowledge that the software was developed
00097  * by the University of California, Berkeley.  The name of the
00098  * University may not be used to endorse or promote products derived
00099  * from this software without specific prior written permission.
00100  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00101  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00102  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00103  */
00104 
00105 
00106 
00107 #include <_ansi.h>
00108 //#include <ctype.h>
00109 #include <wctype.h>
00110 #include <stdio.h>
00111 #include <stdlib.h>
00112 #include <limits.h>
00113 #include <wchar.h>
00114 #include <string.h>
00115 
00116 
00117 #ifdef _HAVE_STDC
00118 #include <stdarg.h>
00119 #else
00120 #include <varargs.h>
00121 #endif
00122 
00123 #ifndef SMALL_SCANF
00124 #include "local.h"
00125 #endif
00126 
00127 
00128 #ifndef NO_FLOATING_POINT
00129 #include <float.h>
00130 #endif
00131 
00132 
00133 
00134 #ifndef NO_FLOATING_POINT
00135 #define FLOATING_POINT
00136 #endif
00137 
00138 #ifdef FLOATING_POINT
00139 #include <float.h>
00140 
00141 /* Currently a test is made to see if long double processing is warranted.
00142    This could be changed in the future should the _ldtoa_r code be
00143    preferred over _dtoa_r.  */
00144 #define _NO_LONGDBL
00145 #if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
00146 #undef _NO_LONGDBL
00147 extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
00148 #endif
00149 
00150 #define _NO_LONGLONG
00151 #if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
00152 # undef _NO_LONGLONG
00153 #endif
00154 
00155 #include "floatio.h"
00156 
00157 #if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
00158 #  define BUF (MAXEXP+MAXFRACT+3)        /* 3 = sign + decimal point + NUL */
00159 #else
00160 #  define BUF MB_LEN_MAX
00161 #endif
00162 
00163 /* An upper bound for how long a long prints in decimal.  4 / 13 approximates
00164    log (2).  Add one char for roundoff compensation and one for the sign.  */
00165 #define MAX_LONG_LEN ((CHAR_BIT * sizeof (long)  - 1) * 4 / 13 + 2)
00166 #else
00167 #define BUF     40
00168 #endif
00169 
00170 
00171 /*
00172  * Flags used during conversion.
00173  */
00174 
00175 #define LONG            0x01    /* l: long or double */
00176 #define LONGDBL         0x02    /* L/ll: long double or long long */
00177 #define SHORT           0x04    /* h: short */
00178 #define CHAR            0x08    /* hh: 8 bit integer */
00179 #define SUPPRESS        0x10    /* suppress assignment */
00180 #define POINTER         0x20    /* weird %p pointer (`fake hex') */
00181 #define NOSKIP          0x40    /* do not skip blanks */
00182 
00183 /*
00184  * The following are used in numeric conversions only:
00185  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
00186  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
00187  */
00188 
00189 #define SIGNOK          0x80    /* +/- is (still) legal */
00190 #define NDIGITS         0x100   /* no digits detected */
00191 
00192 #define DPTOK           0x200   /* (float) decimal point is still legal */
00193 #define EXPOK           0x400   /* (float) exponent (e+3, etc) still legal */
00194 
00195 #define PFXOK           0x200   /* 0x prefix is (still) legal */
00196 #define NZDIGITS        0x400   /* no zero digits detected */
00197 
00198 /*
00199  * Conversion types.
00200  */
00201 
00202 #define CT_CHAR         0       /* %c conversion */
00203 #define CT_CCL          1       /* %[...] conversion */
00204 #define CT_STRING       2       /* %s conversion */
00205 #define CT_INT          3       /* integer, i.e., strtol or strtoul */
00206 #define CT_FLOAT        4       /* floating, i.e., strtod */
00207 
00208 #if 0
00209 #define u_char unsigned char
00210 #endif
00211 #define u_char char
00212 #define u_long unsigned long
00213 
00214 #ifndef _NO_LONGLONG
00215 typedef unsigned long long u_long_long;
00216 #endif
00217 
00218 /*static*/ u_char *__sccl ();
00219 
00220 /*
00221  * vfscanf
00222  */
00223 
00224 #ifndef SMALL_SCANF
00225 #define BufferEmpty (fp->_r <= 0 && __srefill(fp))
00226 
00227 #else // SMALL_SCANF
00228 
00229 unsigned char buf_ungetc ;
00230 int flag_buf_ungetc = 0  ;
00231 #define buf_ungetc_empty 0
00232 #define buf_ungetc_full  1
00233 
00234 
00235 /*
00236         Redefinition of ungetc : store in a buffer a character 
00237         Only ONE ungetc is allowed before a getchar
00238    For each getchar, new_getchar() is called, then the buf is tested:
00239         - if flag_buf_ungetc == 0 : new_getchar call __io_getchar() 
00240         - if flag_buf_ungetc == 1 : new_getchar returns character in the buffer 
00241         
00242  */
00243    
00244 
00245 
00246 
00247 int __io_ungetc(int c){
00248 
00249 if (flag_buf_ungetc == 0){ 
00250    flag_buf_ungetc = buf_ungetc_full; //flag to 1 to indicate that a caracter is in the buffer
00251 }
00252 buf_ungetc= (unsigned char)c ;
00253 
00254 return (c);
00255 }
00256 
00257 int new_getchar() {
00258 if (flag_buf_ungetc == 0){
00259   
00260   return __io_getchar();
00261 
00262 }
00263 else {
00264    
00265         flag_buf_ungetc = buf_ungetc_empty;             
00266         return buf_ungetc;
00267 
00268 }
00269 
00270 }
00271 
00272 #endif // SMALL_SCANF
00273 
00274 #ifndef _REENT_ONLY
00275 
00276 int
00277 _DEFUN (vfscanf, (fp, fmt, ap), 
00278     register FILE *fp _AND 
00279     _CONST char *fmt _AND 
00280     va_list ap)
00281 {
00282   
00283   #ifndef SMALL_SCANF
00284   CHECK_INIT(fp);
00285   #endif
00286   
00287   return __svfscanf_r (_REENT, fp, fmt, ap);
00288 }
00289 
00290 int
00291 __svfscanf (fp, fmt0, ap)
00292      register FILE *fp;
00293      char _CONST *fmt0;
00294      va_list ap;
00295 {
00296   return __svfscanf_r (_REENT, fp, fmt0, ap);
00297 }
00298 
00299 #endif /* !_REENT_ONLY */
00300 
00301 int
00302 _DEFUN (_vfscanf_r, (data, fp, fmt, ap),
00303     struct _reent *data _AND 
00304     register FILE *fp _AND 
00305     _CONST char *fmt _AND 
00306     va_list ap)
00307 {
00308   return __svfscanf_r (data, fp, fmt, ap);
00309 }
00310 
00311 
00312 
00313 /* 
00314 
00315 
00316 For SMALL_SCANF :
00317 The use of files has been removed so as to use directly __io_getchar()
00318 Buffer_empty is not anymore tested since _io_getchar() is blocked until
00319 a character is entered.
00320 Generally each *fp->_p ++  which equal to read a character on the file 
00321 has been replaced by a new_getchar() which call __io_getchar(); 
00322 
00323 
00324 */
00325 
00326 int
00327 __svfscanf_r (rptr, fp, fmt0, ap)
00328      struct _reent *rptr;
00329      register FILE *fp;
00330      char _CONST *fmt0;
00331      va_list ap;
00332 {
00333   
00334   register char * bufread;
00335   register u_char *fmt = (u_char *) fmt0;
00336   register int c;               /* character from format, or conversion */
00337   register int car;             
00338   register size_t width;        /* field width, or 0 */
00339   register char *p;             /* points into all kinds of strings */
00340   register int n;               /* handy integer */
00341   register int flags;           /* flags as defined above */
00342   register char *p0;            /* saves original value of p when necessary */
00343   int nassigned;                /* number of fields assigned */
00344   int nread;                    /* number of characters consumed from fp */
00345   int base = 0;                 /* base argument to strtol/strtoul */
00346   int nbytes = 1;               /* number of bytes read from fmt string */
00347   wchar_t wc;                   /* wchar to use to read format string */
00348   wchar_t *wcp;                 /* handy wide character pointer */
00349   size_t mbslen;                /* length of converted multibyte sequence */
00350   mbstate_t state;              /* value to keep track of multibyte state */
00351 
00352   u_long (*ccfn) () = 0;        /* conversion function (strtol/strtoul) */
00353   char ccltab[256];             /* character class table for %[...] */
00354   char buf[BUF];                /* buffer for numeric conversions */
00355   char *lptr;                   /* literal pointer */
00356 
00357   char *cp;
00358   short *sp;
00359   int *ip;
00360   float *flp;
00361   _LONG_DOUBLE *ldp;
00362   double *dp;
00363   long *lp;
00364 #ifndef _NO_LONGLONG
00365   long long *llp;
00366 #endif
00367 
00368   /* `basefix' is used to avoid `if' tests in the integer scanner */
00369   static _CONST short basefix[17] =
00370     {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
00371 
00372   nassigned = 0;
00373   nread = 0;
00374   for (;;)
00375     {
00376 #ifndef MB_CAPABLE
00377       wc = *fmt;
00378 #else
00379       memset (&state, '\0', sizeof (state));
00380       nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
00381 #endif
00382       fmt += nbytes;
00383       if (wc == 0)
00384         return nassigned;
00385       if (nbytes == 1 && isspace (wc))
00386         {
00387           for (;;)
00388             {
00389                         #ifndef SMALL_SCANF
00390               if (BufferEmpty || !isspace (*fp->_p))
00391                 break;
00392               nread++, fp->_r--, fp->_p++;
00393              
00394               #else            
00395               if (!isspace (*fp->_p)) break;
00396               nread++, fp->_r--;
00397                 *fp->_p = new_getchar();  
00398         
00399                 #endif
00400             }
00401                 
00402           continue;
00403         }
00404       if (wc != '%')
00405         goto literal;
00406       width = 0;
00407       flags = 0;
00408 
00409       /*
00410        * switch on the format.  continue if done; break once format
00411        * type is derived.
00412        */
00413 
00414     again:
00415       c = *fmt++;
00416       switch (c)
00417         {
00418         case '%':
00419         literal:
00420           lptr = fmt - nbytes;
00421           for (n = 0; n < nbytes; ++n)
00422             {
00423          #ifndef SMALL_SCANF   
00424               if (BufferEmpty)
00425                 goto input_failure;
00426               #else
00427                 *fp->_p = new_getchar();
00428               #endif
00429               
00430               if (*fp->_p != *lptr)
00431                 goto match_failure;
00432                #ifndef SMALL_SCANF 
00433               fp->_r--, fp->_p++;
00434               nread++;
00435               #else
00436                  fp->_r--;
00437                  *fp->_p = new_getchar();
00438                  nread++;
00439               #endif
00440               ++lptr;
00441             }
00442           continue;
00443 
00444         case '*':
00445           flags |= SUPPRESS;
00446           goto again;
00447         case 'l':
00448           if (*fmt == 'l')      /* Check for 'll' = long long (SUSv3) */
00449             {
00450               ++fmt;
00451               flags |= LONGDBL;
00452             }
00453           else
00454             flags |= LONG;
00455           goto again;
00456         case 'L':
00457           flags |= LONGDBL;
00458           goto again;
00459         case 'h':
00460           if (*fmt == 'h')      /* Check for 'hh' = char int (SUSv3) */
00461             {
00462               ++fmt;
00463               flags |= CHAR;
00464             }
00465           else
00466             flags |= SHORT;
00467           goto again;
00468 
00469         case '0':
00470         case '1':
00471         case '2':
00472         case '3':
00473         case '4':
00474         case '5':
00475         case '6':
00476         case '7':
00477         case '8':
00478         case '9':
00479           width = width * 10 + c - '0';
00480           goto again;
00481 
00482           /*
00483            * Conversions. Those marked `compat' are for
00484            * 4.[123]BSD compatibility.
00485            *
00486            * (According to ANSI, E and X formats are supposed to
00487            * the same as e and x.  Sorry about that.)
00488            */
00489 
00490         case 'D':               /* compat */
00491           flags |= LONG;
00492           /* FALLTHROUGH */
00493         case 'd':
00494           c = CT_INT;
00495           ccfn = (u_long (*)())_strtol_r;
00496           base = 10;
00497           break;
00498 
00499         case 'i':
00500           c = CT_INT;
00501           ccfn = (u_long (*)())_strtol_r;
00502           base = 0;
00503           break;
00504 
00505         case 'O':               /* compat */
00506           flags |= LONG;
00507           /* FALLTHROUGH */
00508         case 'o':
00509           c = CT_INT;
00510           ccfn = _strtoul_r;
00511           base = 8;
00512           break;
00513 
00514         case 'u':
00515           c = CT_INT;
00516           ccfn = _strtoul_r;
00517           base = 10;
00518           break;
00519 
00520         case 'X':               /* compat   XXX */
00521         case 'x':
00522           flags |= PFXOK;       /* enable 0x prefixing */
00523           c = CT_INT;
00524           ccfn = _strtoul_r;
00525           base = 16;
00526           break;
00527 
00528 #ifdef FLOATING_POINT
00529         case 'E':               /* compat   XXX */
00530         case 'G':               /* compat   XXX */
00531 /* ANSI says that E,G and X behave the same way as e,g,x */
00532           /* FALLTHROUGH */
00533         case 'e':
00534         case 'f':
00535         case 'g':
00536           c = CT_FLOAT;
00537           break;
00538 #endif
00539         case 'S':
00540           flags |= LONG;
00541           /* FALLTHROUGH */
00542 
00543         case 's':
00544           c = CT_STRING;
00545           break;
00546 
00547         case '[':
00548           fmt = __sccl (ccltab, fmt);
00549           flags |= NOSKIP;
00550           c = CT_CCL;
00551           break;
00552 
00553         case 'C':
00554           flags |= LONG;
00555           /* FALLTHROUGH */
00556 
00557         case 'c':
00558           flags |= NOSKIP;
00559           c = CT_CHAR;
00560           break;
00561 
00562         case 'p':               /* pointer format is like hex */
00563           flags |= POINTER | PFXOK;
00564           c = CT_INT;
00565           ccfn = _strtoul_r;
00566           base = 16;
00567           break;
00568 
00569         case 'n':
00570           if (flags & SUPPRESS) /* ??? */
00571             continue;
00572           if (flags & CHAR)
00573             {
00574               cp = va_arg (ap, char *);
00575               *cp = nread;
00576             }
00577           else if (flags & SHORT)
00578             {
00579               sp = va_arg (ap, short *);
00580               *sp = nread;
00581             }
00582           else if (flags & LONG)
00583             {
00584               lp = va_arg (ap, long *);
00585               *lp = nread;
00586             }
00587 #ifndef _NO_LONGLONG
00588           else if (flags & LONGDBL)
00589             {
00590               llp = va_arg (ap, long long*);
00591               *llp = nread;
00592             }
00593 #endif
00594           else
00595             {
00596               ip = va_arg (ap, int *);
00597               *ip = nread;
00598             }
00599           continue;
00600 
00601           /*
00602            * Disgusting backwards compatibility hacks.  XXX
00603            */
00604         case '\0':              /* compat */
00605           return EOF;
00606 
00607         default:                /* compat */
00608           if (isupper (c))
00609             flags |= LONG;
00610           c = CT_INT;
00611           ccfn = (u_long (*)())_strtol_r;
00612           base = 10;
00613           break;
00614         }
00615 
00616       /*
00617        * We have a conversion that requires input.
00618        */
00619    #ifndef SMALL_SCANF
00620       if (BufferEmpty)
00621         goto input_failure;
00622    #else
00623       *fp->_p = new_getchar();      
00624    #endif
00625 
00626       /*
00627        * Consume leading white space, except for formats that
00628        * suppress this.
00629        */
00630 
00631       if ((flags & NOSKIP) == 0)
00632         {
00633           while (isspace (*fp->_p))
00634             {
00635               #ifndef SMALL_SCANF 
00636                 nread++;
00637               if (--fp->_r > 0)
00638                      fp->_p++;
00639               else
00640               if (__srefill (fp))
00641                    goto input_failure;
00642                    #else
00643                          *fp->_p = new_getchar();      
00644                 #endif
00645             }
00646           /*
00647            * Note that there is at least one character in the
00648            * buffer, so conversions that do not set NOSKIP ca
00649            * no longer result in an input failure.
00650            */
00651         }
00652 
00653       /*
00654        * Do the conversion.
00655        */
00656       switch (c)
00657         {
00658 
00659         case CT_CHAR:
00660           /* scan arbitrary characters (sets NOSKIP) */
00661           if (width == 0)
00662             width = 1;
00663           if (flags & LONG) 
00664             {
00665               if ((flags & SUPPRESS) == 0)
00666                 wcp = va_arg(ap, wchar_t *);
00667               else
00668                 wcp = NULL;
00669               n = 0;
00670               while (width != 0) 
00671                 {
00672                   
00673                   if (n == MB_CUR_MAX)
00674                     goto input_failure;
00675                   #ifndef SMALL_SCANF
00676                   buf[n++] = *fp->_p;
00677                   fp->_r -= 1;
00678                   fp->_p += 1;
00679                   memset((void *)&state, '\0', sizeof(mbstate_t));
00680                   if ((mbslen = _mbrtowc_r(rptr, wcp, buf, n, &state)) 
00681                                                          == (size_t)-1)
00682                     goto input_failure; /* Invalid sequence */
00683                   #else
00684                      buf[n++] = *fp->_p;
00685                         *fp->_p = new_getchar();
00686                                                                                                          
00687                                                 #endif                 
00688                   
00689                   if (mbslen == 0 && !(flags & SUPPRESS))
00690                     *wcp = L'\0';
00691                   if (mbslen != (size_t)-2) /* Incomplete sequence */
00692                     {
00693                       nread += n;
00694                       width -= 1;
00695                       if (!(flags & SUPPRESS))
00696                         wcp += 1;
00697                       n = 0;
00698                     }
00699                   #ifndef SMALL_SCANF
00700                   if (BufferEmpty) 
00701                     {
00702                       if (n != 0) 
00703                         goto input_failure;
00704                       break;
00705                     }
00706                   #endif
00707                 }
00708               if (!(flags & SUPPRESS))
00709                 nassigned++;
00710             } 
00711           else if (flags & SUPPRESS) 
00712             {
00713               size_t sum = 0;
00714               for (;;)
00715                 {
00716                   if ((n = fp->_r) < (int)width)
00717                     {
00718                       sum += n;
00719                       width -= n;       
00720                       #ifndef SMALL_SCANF          
00721                       fp->_p += n;                    
00722                       if (__srefill (fp))
00723                         {
00724                           if (sum == 0)
00725                             goto input_failure;
00726                           break;
00727                         }
00728                           #else
00729                           *fp->_p = new_getchar();                        
00730                           #endif
00731                          
00732                     }
00733                   else
00734                     {
00735                       sum += width;
00736                       fp->_r -= width;
00737                       #ifndef SMALL_SCANF
00738                       fp->_p += width;
00739                       #else
00740                       *fp->_p = new_getchar();
00741                       #endif
00742                       
00743                       break;
00744                     }
00745                 }
00746               nread += sum;
00747             }
00748           else
00749             {
00750                 
00751                         #ifndef SMALL_SCANF 
00752               size_t r = fread ((_PTR) va_arg (ap, char *), 1, width, fp);
00753               if (r == 0)
00754                    goto input_failure;
00755               nread += r;
00756               nassigned++;
00757                       
00758               #else
00759               bufread=(_PTR)va_arg(ap,char *);
00760               int r;
00761               for (r=0;r<width;r++){            
00762                 *bufread++= *fp->_p;
00763                 if ( r+1 < width){
00764                 *fp->_p = new_getchar();
00765                 }
00766                  }
00767                 #endif                            
00768             }
00769           break;
00770 
00771         case CT_CCL:
00772           /* scan a (nonempty) character class (sets NOSKIP) */
00773           if (width == 0)
00774             width = ~0;         /* `infinity' */
00775           /* take only those things in the class */
00776           if (flags & SUPPRESS)
00777             {
00778               n = 0;
00779               while (ccltab[*fp->_p])
00780                 {
00781                   #ifndef SMALL_SCANF
00782                   n++, fp->_r--, fp->_p++;
00783                   if (--width == 0)
00784                     break;
00785                   if (BufferEmpty)
00786                     {
00787                       if (n == 0)
00788                         goto input_failure;
00789                       break;
00790                     }
00791                    #else
00792                     n++;
00793                     fp->_r++;
00794                     *fp->_p = new_getchar();
00795                    #endif
00796                    
00797                 }
00798               if (n == 0)
00799                 goto match_failure;
00800             }
00801           else
00802             {
00803               p0 = p = va_arg (ap, char *);
00804               while (ccltab[*fp->_p])
00805                 {
00806                   fp->_r--;
00807                   #ifndef SMALL_SCANF
00808                   *p++ = *fp->_p++;
00809                   if (--width == 0)
00810                     break;
00811                   if (BufferEmpty)
00812                     {
00813                       if (p == p0)
00814                         goto input_failure;
00815                       break;
00816                     }
00817                   #else
00818                    *p++ = *fp->_p;
00819                         *fp->_p= new_getchar();
00820                         if (--width == 0)
00821                     break;
00822                   #endif
00823                   
00824                 }
00825               n = p - p0;
00826               if (n == 0)
00827                 goto match_failure;
00828               *p = 0;
00829               nassigned++;
00830             }
00831           nread += n;
00832           break;
00833 
00834         case CT_STRING:
00835           /* like CCL, but zero-length string OK, & no NOSKIP */
00836           
00837           if (width == 0)
00838             width = (size_t)~0;
00839           if (flags & LONG) 
00840             {
00841               /* Process %S and %ls placeholders */
00842               if ((flags & SUPPRESS) == 0)
00843                 wcp = va_arg(ap, wchar_t *);
00844               else
00845                 wcp = &wc;
00846               n = 0;
00847               while (!isspace(*fp->_p) && width != 0) 
00848                 {
00849                   if (n == MB_CUR_MAX)
00850                     goto input_failure;
00851                   buf[n++] = *fp->_p;
00852                   fp->_r -= 1;
00853                   #ifndef SMALL_SCANF
00854                   fp->_p += 1;
00855                   memset((void *)&state, '\0', sizeof(mbstate_t));
00856                   if ((mbslen = _mbrtowc_r(rptr, wcp, buf, n, &state)) 
00857                                                         == (size_t)-1)
00858                     goto input_failure;
00859                   #else
00860                   *fp->_p = new_getchar();
00861                   #endif
00862                   
00863                   if (mbslen == 0)
00864                     *wcp = L'\0';
00865                   
00866                   if (mbslen != (size_t)-2) /* Incomplete sequence */
00867                     {
00868                       if (iswspace(*wcp)) 
00869                         {
00870                           
00871                           while (n != 0)
00872                             #ifndef SMALL_SCANF
00873                             ungetc(buf[--n], fp);
00874                             #else
00875                             __io_ungetc(buf[--n]);
00876                             #endif
00877                           break;
00878                          
00879                         }
00880                         
00881                       nread += n;
00882                       width -= 1;
00883                       if ((flags & SUPPRESS) == 0)
00884                         wcp += 1;
00885                       n = 0;
00886                     }
00887                                 #ifndef SMALL_SCANF
00888                   if (BufferEmpty) 
00889                     {
00890                       if (n != 0)
00891                         goto input_failure;
00892                       break;
00893                     }
00894                  #endif
00895                 
00896                 }
00897               if (!(flags & SUPPRESS)) 
00898                 {
00899                   *wcp = L'\0';
00900                   nassigned++;
00901                 }
00902             }
00903           else if (flags & SUPPRESS) 
00904             {
00905               n = 0;
00906               while (!isspace (*fp->_p))
00907                 {
00908                   #ifndef SMALL_SCANF
00909                   n++, fp->_r--, fp->_p++;
00910                   if (--width == 0)
00911                     break;
00912                   if (BufferEmpty)
00913                     break;
00914                  #else
00915                     n++;
00916                     *fp->_p = new_getchar();                
00917                     if (*fp->_p == '\0') break;
00918                   #endif
00919                   
00920                 }
00921               nread += n;
00922             }
00923           else
00924             {
00925               p0 = p = va_arg (ap, char *);
00926               while (!isspace (*fp->_p))
00927                 {
00928                   #ifndef SMALL_SCANF
00929                   fp->_r--;
00930                   *p++ = *fp->_p++;
00931                   if (--width == 0)
00932                     break;
00933                   if (BufferEmpty)
00934                     break;
00935                   #else
00936                     *p++=*fp->_p;
00937                     *fp->_p = new_getchar();                
00938                     if (*fp->_p == '\0') break;
00939                   #endif
00940          
00941                   
00942                 }
00943               *p = 0;
00944               nread += p - p0;
00945               nassigned++;
00946             }
00947           continue;
00948 
00949         case CT_INT:
00950           /* scan an integer as if by strtol/strtoul */
00951 #ifdef hardway
00952           if (width == 0 || width > sizeof (buf) - 1)
00953             width = sizeof (buf) - 1;
00954 #else
00955           /* size_t is unsigned, hence this optimisation */
00956           if (--width > sizeof (buf) - 2)
00957             width = sizeof (buf) - 2;
00958           width++;
00959 #endif
00960           flags |= SIGNOK | NDIGITS | NZDIGITS;
00961           for (p = buf; width; width--)
00962             {     
00963               c = *fp->_p;
00964               /*
00965                * Switch on the character; `goto ok' if we
00966                * accept it as a part of number.
00967                */
00968               switch (c)
00969                 {
00970                   /*
00971                    * The digit 0 is always legal, but is special.
00972                    * For %i conversions, if no digits (zero or nonzero)
00973                    * have been scanned (only signs), we will have base==0.
00974                    * In that case, we should set it to 8 and enable 0x
00975                    * prefixing. Also, if we have not scanned zero digits
00976                    * before this, do not turn off prefixing (someone else
00977                    * will turn it off if we have scanned any nonzero digits).
00978                    */
00979                 case '0':
00980                   if (base == 0)
00981                     {
00982                       base = 8;
00983                       flags |= PFXOK;
00984                     }
00985                   if (flags & NZDIGITS)
00986                     flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
00987                   else
00988                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
00989                   goto ok;
00990 
00991                   /* 1 through 7 always legal */
00992                 case '1':
00993                 case '2':
00994                 case '3':
00995                 case '4':
00996                 case '5':
00997                 case '6':
00998                 case '7':
00999                   base = basefix[base];
01000                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
01001                   goto ok;
01002 
01003                   /* digits 8 and 9 ok iff decimal or hex */
01004                 case '8':
01005                 case '9':
01006                   base = basefix[base];
01007                   if (base <= 8)
01008                     break;      /* not legal here */
01009                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
01010                   goto ok;
01011 
01012                   /* letters ok iff hex */
01013                 case 'A':
01014                 case 'B':
01015                 case 'C':
01016                 case 'D':
01017                 case 'E':
01018                 case 'F':
01019                 case 'a':
01020                 case 'b':
01021                 case 'c':
01022                 case 'd':
01023                 case 'e':
01024                 case 'f':
01025                   /* no need to fix base here */
01026                   if (base <= 10)
01027                     break;      /* not legal here */
01028                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
01029                   goto ok;
01030 
01031                   /* sign ok only as first character */
01032                 case '+':
01033                 case '-':
01034                   if (flags & SIGNOK)
01035                     {
01036                       flags &= ~SIGNOK;
01037                       goto ok;
01038                     }
01039                   break;
01040 
01041                   /* x ok iff flag still set & 2nd char */
01042                 case 'x':
01043                 case 'X':
01044                   if (flags & PFXOK && p == buf + 1)
01045                     {
01046                       base = 16;/* if %i */
01047                       flags &= ~PFXOK;
01048                       goto ok;
01049                     }             
01050                   break;
01051                 }
01052               /*
01053                * If we got here, c is not a legal character
01054                * for a number.  Stop accumulating digits.
01055                */
01056                 
01057               break;
01058             ok:
01059               /*
01060                * c is legal: store it and look at the next.
01061                */
01062               *p++ = c;
01063               #ifndef SMALL_SCANF
01064          if (--fp->_r > 0)
01065                                 fp->_p++;
01066                else          
01067                         if (__srefill (fp))
01068                         break;          /* EOF */
01069                    #else
01070                            
01071                     *fp->_p = new_getchar();    
01072                                            
01073                    #endif
01074                              
01075         }
01076           /*
01077            * If we had only a sign, it is no good; push back the sign.
01078            * If the number ends in `x', it was [sign] '0' 'x', so push back
01079            * the x and treat it as [sign] '0'.
01080            */
01081           
01082           if (flags & NDIGITS)
01083             {
01084            if (p > buf)
01085                #ifndef SMALL_SCANF
01086                                 _CAST_VOID ungetc (*(u_char *)-- p, fp);
01087                          #else
01088                                 _CAST_VOID __io_ungetc (*(u_char *)-- p);
01089                          #endif
01090               goto match_failure;
01091 
01092             }
01093          
01094           c = ((u_char *) p)[-1];
01095           if (c == 'x' || c == 'X')
01096             {
01097               --p;
01098               #ifndef SMALL_SCANF
01099               /*(void)*/ ungetc (c, fp);
01100               #else 
01101                 __io_ungetc (c);
01102               #endif
01103           
01104             }
01105           if ((flags & SUPPRESS) == 0)
01106             {
01107               u_long res;
01108 
01109               *p = 0;
01110               res = (*ccfn) (rptr, buf, (char **) NULL, base);
01111               if (flags & POINTER)
01112                 *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
01113               else if (flags & CHAR)
01114                 {
01115                   cp = va_arg (ap, char *);
01116                   *cp = res;
01117                 }
01118               else if (flags & SHORT)
01119                 {
01120                   sp = va_arg (ap, short *);
01121                   *sp = res;
01122                 }
01123               else if (flags & LONG)
01124                 {
01125                   lp = va_arg (ap, long *);
01126                   *lp = res;
01127                 }
01128 #ifndef _NO_LONGLONG
01129               else if (flags & LONGDBL)
01130                 {
01131                   u_long_long resll;
01132                   if (ccfn == _strtoul_r)
01133                     resll = _strtoull_r (rptr, buf, (char **) NULL, base);
01134                   else
01135                     resll = _strtoll_r (rptr, buf, (char **) NULL, base);
01136                   llp = va_arg (ap, long long*);
01137                   *llp = resll;
01138                 }
01139 #endif
01140               else
01141                 {
01142                   ip = va_arg (ap, int *);
01143                   *ip = res;
01144                 }
01145               nassigned++;
01146             }
01147           nread += p - buf;
01148           break;
01149 
01150 #ifdef FLOATING_POINT
01151         case CT_FLOAT:
01152         {
01153           /* scan a floating point number as if by strtod */
01154           /* This code used to assume that the number of digits is reasonable.
01155              However, ANSI / ISO C makes no such stipulation; we have to get
01156              exact results even when there is an unreasonable amount of
01157              leading zeroes.  */
01158           long leading_zeroes = 0;
01159           long zeroes, exp_adjust;
01160           char *exp_start = NULL;
01161 #ifdef hardway
01162           if (width == 0 || width > sizeof (buf) - 1)
01163             width = sizeof (buf) - 1;
01164 #else
01165           /* size_t is unsigned, hence this optimisation */
01166           if (--width > sizeof (buf) - 2)
01167             width = sizeof (buf) - 2;
01168           width++;
01169 #endif
01170           flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
01171           zeroes = 0;
01172           exp_adjust = 0;
01173           for (p = buf; width; )
01174             {
01175               c = *fp->_p;
01176               /*
01177                * This code mimicks the integer conversion
01178                * code, but is much simpler.
01179                */
01180               switch (c)
01181                 {
01182 
01183                 case '0':
01184                   if (flags & NDIGITS)
01185                     {
01186                       flags &= ~SIGNOK;
01187                       zeroes++;
01188                       goto fskip;
01189                     }
01190                   /* Fall through.  */
01191                 case '1':
01192                 case '2':
01193                 case '3':
01194                 case '4':
01195                 case '5':
01196                 case '6':
01197                 case '7':
01198                 case '8':
01199                 case '9':
01200                   flags &= ~(SIGNOK | NDIGITS);
01201                   goto fok;
01202 
01203                 case '+':
01204                 case '-':
01205                   if (flags & SIGNOK)
01206                     {
01207                       flags &= ~SIGNOK;
01208                       goto fok;
01209                     }
01210                   break;
01211                 case '.':
01212                   if (flags & DPTOK)
01213                     {
01214                       flags &= ~(SIGNOK | DPTOK);
01215                       leading_zeroes = zeroes;
01216                       goto fok;
01217                     }
01218                   break;
01219                 case 'e':
01220                 case 'E':
01221                   /* no exponent without some digits */
01222                   if ((flags & (NDIGITS | EXPOK)) == EXPOK
01223                       || ((flags & EXPOK) && zeroes))
01224                     {
01225                       if (! (flags & DPTOK))
01226                         {
01227                           exp_adjust = zeroes - leading_zeroes;
01228                           exp_start = p;
01229                         }
01230                       flags =
01231                         (flags & ~(EXPOK | DPTOK)) |
01232                         SIGNOK | NDIGITS;
01233                       zeroes = 0;
01234                       goto fok;
01235                     }
01236                   break;
01237                 }
01238               break;
01239             fok:
01240               *p++ = c;
01241             fskip:
01242               width--;
01243               ++nread;
01244          #ifndef SMALL_SCANF
01245               if (--fp->_r > 0)
01246                 fp->_p++;
01247               else
01248               if (__srefill (fp))
01249                 break;          /* EOF */
01250                   #else
01251                      *fp->_p = new_getchar();
01252                     if ( (47<*fp->_p<58) && (64<*fp->_p < 71) && (96<*fp->_p<103) ){
01253                        ;
01254                     }
01255                     else
01256                     {
01257                        break;
01258                     }
01259                   #endif 
01260             }
01261           if (zeroes)
01262             flags &= ~NDIGITS;
01263           /*
01264            * If no digits, might be missing exponent digits
01265            * (just give back the exponent) or might be missing
01266            * regular digits, but had sign and/or decimal point.
01267            */
01268           if (flags & NDIGITS)
01269             {
01270               if (flags & EXPOK)
01271                 {
01272                   /* no digits at all */
01273                 
01274                   while (p > buf)
01275         {
01276             #ifndef SMALL_SCANF
01277                       ungetc (*(u_char *)-- p, fp);
01278                       #else
01279                       __io_ungetc(*(u_char *)-- p);
01280                       #endif
01281             --nread;
01282          }
01283                     
01284                   goto match_failure;
01285 
01286                 }
01287                   
01288               /* just a bad exponent (e and maybe sign) */
01289               c = *(u_char *)-- p;
01290               --nread;
01291               if (c != 'e' && c != 'E')
01292                 {
01293                 #ifndef SMALL_SCANF
01294                   _CAST_VOID ungetc (c, fp);    /* sign */
01295                 #else
01296                   _CAST_VOID __io_ungetc (c);
01297                 #endif
01298                   c = *(u_char *)-- p;
01299                   --nread;
01300                 }
01301                 #ifndef SMALL_SCANF
01302               _CAST_VOID ungetc (c, fp);
01303            #else
01304               _CAST_VOID __io_ungetc (c);
01305            #endif
01306           
01307             }
01308           if ((flags & SUPPRESS) == 0)
01309             {
01310               double res = 0;
01311 #ifdef _NO_LONGDBL
01312 #define QUAD_RES res;
01313 #else  /* !_NO_LONG_DBL */
01314               long double qres = 0;
01315 #define QUAD_RES qres;
01316 #endif /* !_NO_LONG_DBL */
01317               long new_exp = 0;
01318 
01319               *p = 0;
01320               if ((flags & (DPTOK | EXPOK)) == EXPOK)
01321                 {
01322                   exp_adjust = zeroes - leading_zeroes;
01323                   new_exp = -exp_adjust;
01324                   exp_start = p;
01325                 }
01326               else if (exp_adjust)
01327                 new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
01328               if (exp_adjust)
01329                 {
01330 
01331                   /* If there might not be enough space for the new exponent,
01332                      truncate some trailing digits to make room.  */
01333                   if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
01334                     exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
01335            sprintf (exp_start, "e%ld", new_exp);
01336                 }
01337 
01338               /* Current _strtold routine is markedly slower than 
01339                  _strtod_r.  Only use it if we have a long double
01340                  result.  */
01341 #ifndef _NO_LONGDBL /* !_NO_LONGDBL */
01342               if (flags & LONGDBL)
01343                 qres = _strtold (buf, NULL);
01344               else
01345 #endif
01346                 res = _strtod_r (rptr, buf, NULL);
01347               if (flags & LONG)
01348                 {
01349                   dp = va_arg (ap, double *);
01350                   *dp = res;
01351                 }
01352               else if (flags & LONGDBL)
01353                 {
01354                   ldp = va_arg (ap, _LONG_DOUBLE *);
01355                   *ldp = QUAD_RES;
01356                 }
01357               else
01358                 {
01359                   flp = va_arg (ap, float *);
01360                   *flp = res;
01361                 }
01362               nassigned++;
01363             }
01364           break;
01365         }
01366 #endif /* FLOATING_POINT */
01367 
01368         }
01369     }
01370 input_failure:
01371   return nassigned ? nassigned : -1;
01372 match_failure:
01373   return nassigned;
01374 }
01375 
01376 /*
01377  * Fill in the given table from the scanset at the given format
01378  * (just after `[').  Return a pointer to the character past the
01379  * closing `]'.  The table has a 1 wherever characters should be
01380  * considered part of the scanset.
01381  */
01382 
01383 /*static*/
01384 u_char *
01385 __sccl (tab, fmt)
01386      register char *tab;
01387      register u_char *fmt;
01388 {
01389   register int c, n, v;
01390 
01391   /* first `clear' the whole table */
01392   c = *fmt++;                   /* first char hat => negated scanset */
01393   if (c == '^')
01394     {
01395       v = 1;                    /* default => accept */
01396       c = *fmt++;               /* get new first char */
01397     }
01398   else
01399     v = 0;                      /* default => reject */
01400   /* should probably use memset here */
01401   for (n = 0; n < 256; n++)
01402     tab[n] = v;
01403   if (c == 0)
01404     return fmt - 1;             /* format ended before closing ] */
01405 
01406   /*
01407    * Now set the entries corresponding to the actual scanset to the
01408    * opposite of the above.
01409    *
01410    * The first character may be ']' (or '-') without being special; the
01411    * last character may be '-'.
01412    */
01413 
01414   v = 1 - v;
01415   for (;;)
01416     {
01417       tab[c] = v;               /* take character c */
01418     doswitch:
01419       n = *fmt++;               /* and examine the next */
01420       switch (n)
01421         {
01422 
01423         case 0:         /* format ended too soon */
01424           return fmt - 1;
01425 
01426         case '-':
01427           /*
01428            * A scanset of the form [01+-] is defined as `the digit 0, the
01429            * digit 1, the character +, the character -', but the effect of a
01430            * scanset such as [a-zA-Z0-9] is implementation defined.  The V7
01431            * Unix scanf treats `a-z' as `the letters a through z', but treats
01432            * `a-a' as `the letter a, the character -, and the letter a'.
01433            *
01434            * For compatibility, the `-' is not considerd to define a range if
01435            * the character following it is either a close bracket (required by
01436            * ANSI) or is not numerically greater than the character we just
01437            * stored in the table (c).
01438            */
01439           n = *fmt;
01440           if (n == ']' || n < c)
01441             {
01442               c = '-';
01443               break;            /* resume the for(;;) */
01444             }
01445           fmt++;
01446           do
01447             {                   /* fill in the range */
01448               tab[++c] = v;
01449             }
01450           while (c < n);
01451 #if 1                   /* XXX another disgusting compatibility hack */
01452           /*
01453            * Alas, the V7 Unix scanf also treats formats such
01454            * as [a-c-e] as `the letters a through e'. This too
01455            * is permitted by the standard....
01456            */
01457           goto doswitch;
01458 #else
01459           c = *fmt++;
01460           if (c == 0)
01461             return fmt - 1;
01462           if (c == ']')
01463             return fmt;
01464 #endif
01465 
01466           break;
01467 
01468 
01469         case ']':               /* end of scanset */
01470           return fmt;
01471 
01472         default:                /* just another character */
01473           c = n;
01474           break;
01475         }
01476     }
01477   /* NOTREACHED */
01478 }
01479 
01480 
01481 

Generated on Mon Apr 11 14:23:40 2011 for Contiki 2.5 by  doxygen 1.6.1