ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

scanf.h
Go to the documentation of this file.
00001 /*
00002  * general implementation of scanf used by scanf, sscanf, fscanf,
00003  * _cscanf, wscanf, swscanf and fwscanf
00004  *
00005  * Copyright 1996,1998 Marcus Meissner
00006  * Copyright 1996 Jukka Iivonen
00007  * Copyright 1997,2000, 2003 Uwe Bonnes
00008  * Copyright 2000 Jon Griffiths
00009  * Copyright 2002 Daniel Gudbjartsson
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00024  */
00025 
00026 #ifdef WIDE_SCANF
00027 #define _CHAR_ wchar_t
00028 #define _EOF_ WEOF
00029 #define _EOF_RET WEOF
00030 #define _ISSPACE_(c) iswspace(c)
00031 #define _ISDIGIT_(c) iswdigit(c)
00032 #define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */
00033 #define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */
00034 #define _CHAR2DIGIT_(c, base) wchar2digit((c), (base))
00035 #define _BITMAPSIZE_ 256*256
00036 #else /* WIDE_SCANF */
00037 #define _CHAR_ char
00038 #define _EOF_ EOF
00039 #define _EOF_RET EOF
00040 #define _ISSPACE_(c) isspace(c)
00041 #define _ISDIGIT_(c) isdigit(c)
00042 #define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */
00043 #define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */
00044 #define _CHAR2DIGIT_(c, base) char2digit((c), (base))
00045 #define _BITMAPSIZE_ 256
00046 #endif /* WIDE_SCANF */
00047 
00048 #ifdef CONSOLE
00049 #define _GETC_(file) (consumed++, _getch())
00050 #define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0)
00051 #define _FUNCTION_ int vcscanf(const char *format, va_list ap)
00052 #else
00053 #ifdef STRING
00054 #undef _EOF_
00055 #define _EOF_ 0
00056 #define _GETC_(file) (consumed++, *file++)
00057 #define _UNGETC_(nch, file) do { file--; consumed--; } while(0)
00058 #ifdef WIDE_SCANF
00059 #define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap)
00060 #else /* WIDE_SCANF */
00061 #define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap)
00062 #endif /* WIDE_SCANF */
00063 #else /* STRING */
00064 #ifdef WIDE_SCANF
00065 #define _GETC_(file) (consumed++, fgetwc(file))
00066 #define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0)
00067 #define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap)
00068 #else /* WIDE_SCANF */
00069 #define _GETC_(file) (consumed++, fgetc(file))
00070 #define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0)
00071 #define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap)
00072 #endif /* WIDE_SCANF */
00073 #endif /* STRING */
00074 #endif /* CONSOLE */
00075 
00076 _FUNCTION_ {
00077     int rd = 0, consumed = 0;
00078     int nch;
00079     if (!*format) return 0;
00080 #ifndef WIDE_SCANF
00081 #ifdef CONSOLE
00082     TRACE("(%s):\n", debugstr_a(format));
00083 #else /* CONSOLE */
00084 #ifdef STRING
00085     TRACE("%s (%s)\n", file, debugstr_a(format));
00086 #else /* STRING */
00087     TRACE("%p (%s)\n", file, debugstr_a(format));
00088 #endif /* STRING */
00089 #endif /* CONSOLE */
00090 #endif /* WIDE_SCANF */
00091     nch = _GETC_(file);
00092     if (nch == _EOF_) return _EOF_RET;
00093 
00094     while (*format) {
00095     /* a whitespace character in the format string causes scanf to read,
00096      * but not store, all consecutive white-space characters in the input
00097      * up to the next non-white-space character.  One white space character
00098      * in the input matches any number (including zero) and combination of
00099      * white-space characters in the input. */
00100     if (_ISSPACE_(*format)) {
00101             /* skip whitespace */
00102             while ((nch!=_EOF_) && _ISSPACE_(nch))
00103                 nch = _GETC_(file);
00104         }
00105     /* a format specification causes scanf to read and convert characters
00106      * in the input into values of a specified type.  The value is assigned
00107      * to an argument in the argument list.  Format specifications have
00108      * the form %[*][width][{h | l | I64 | L}]type */
00109         else if (*format == '%') {
00110             int st = 0; int suppress = 0; int width = 0;
00111         int base;
00112         int h_prefix = 0;
00113         int l_prefix = 0;
00114         int L_prefix = 0;
00115         int w_prefix = 0;
00116         int prefix_finished = 0;
00117         int I64_prefix = 0;
00118             format++;
00119         /* look for leading asterisk, which means 'suppress assignment of
00120          * this field'. */
00121         if (*format=='*') {
00122         format++;
00123         suppress=1;
00124         }
00125         /* look for width specification */
00126         while (_ISDIGIT_(*format)) {
00127         width*=10;
00128         width+=*format++ - '0';
00129         }
00130         if (width==0) width=-1; /* no width spec seen */
00131         /* read prefix (if any) */
00132         while (!prefix_finished) {
00133         switch(*format) {
00134         case 'h': h_prefix = 1; break;
00135         case 'l': l_prefix = 1; break;
00136         case 'w': w_prefix = 1; break;
00137         case 'L': L_prefix = 1; break;
00138         case 'I':
00139             if (*(format + 1) == '6' &&
00140             *(format + 2) == '4') {
00141             I64_prefix = 1;
00142             format += 2;
00143             }
00144             break;
00145         default:
00146             prefix_finished = 1;
00147         }
00148         if (!prefix_finished) format++;
00149         }
00150         /* read type */
00151             switch(*format) {
00152         case 'p':
00153         case 'P': /* pointer. */
00154                 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1;
00155                 /* fall through */
00156         case 'x':
00157         case 'X': /* hexadecimal integer. */
00158         base = 16;
00159         goto number;
00160         case 'o': /* octal integer */
00161         base = 8;
00162         goto number;
00163         case 'u': /* unsigned decimal integer */
00164         base = 10;
00165         goto number;
00166         case 'd': /* signed decimal integer */
00167         base = 10;
00168         goto number;
00169         case 'i': /* generic integer */
00170         base = 0;
00171         number: {
00172             /* read an integer */
00173             __int64 cur = 0;
00174             int negative = 0;
00175             int seendigit=0;
00176                     /* skip initial whitespace */
00177                     while ((nch!=_EOF_) && _ISSPACE_(nch))
00178                         nch = _GETC_(file);
00179                     /* get sign */
00180                     if (nch == '-' || nch == '+') {
00181             negative = (nch=='-');
00182                         nch = _GETC_(file);
00183             if (width>0) width--;
00184                     }
00185             /* look for leading indication of base */
00186             if (width!=0 && nch == '0' && *format != 'p' && *format != 'P') {
00187                         nch = _GETC_(file);
00188             if (width>0) width--;
00189             seendigit=1;
00190             if (width!=0 && (nch=='x' || nch=='X')) {
00191                 if (base==0)
00192                 base=16;
00193                 if (base==16) {
00194                 nch = _GETC_(file);
00195                 if (width>0) width--;
00196                 seendigit=0;
00197                 }
00198             } else if (base==0)
00199                 base = 8;
00200             }
00201             /* format %i without indication of base */
00202             if (base==0)
00203             base = 10;
00204             /* throw away leading zeros */
00205             while (width!=0 && nch=='0') {
00206                         nch = _GETC_(file);
00207             if (width>0) width--;
00208             seendigit=1;
00209             }
00210             if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) {
00211             cur = _CHAR2DIGIT_(nch, base);
00212             nch = _GETC_(file);
00213             if (width>0) width--;
00214             seendigit=1;
00215             }
00216                     /* read until no more digits */
00217                     while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) {
00218                         cur = cur*base + _CHAR2DIGIT_(nch, base);
00219                         nch = _GETC_(file);
00220             if (width>0) width--;
00221             seendigit=1;
00222                     }
00223             /* okay, done! */
00224             if (!seendigit) break; /* not a valid number */
00225                     st = 1;
00226                     if (!suppress) {
00227 #define _SET_NUMBER_(type) *va_arg(ap, type*) = (type)(negative ? -cur : cur)
00228             if (I64_prefix) _SET_NUMBER_(LONGLONG);
00229             else if (l_prefix) _SET_NUMBER_(LONG);
00230             else if (h_prefix) _SET_NUMBER_(short int);
00231             else _SET_NUMBER_(int);
00232             }
00233                 }
00234                 break;
00235         case 'e':
00236         case 'E':
00237         case 'f':
00238         case 'g':
00239             case 'G': { /* read a float */
00240                     long double cur = 0;
00241             int negative = 0;
00242                     /* skip initial whitespace */
00243                     while ((nch!=_EOF_) && _ISSPACE_(nch))
00244                         nch = _GETC_(file);
00245             /* get sign. */
00246                     if (nch == '-' || nch == '+') {
00247             negative = (nch=='-');
00248             if (width>0) width--;
00249             if (width==0) break;
00250                         nch = _GETC_(file);
00251                     }
00252             /* get first digit. */
00253             if ('.' != nch) {
00254               if (!_ISDIGIT_(nch)) break;
00255               cur = (nch - '0');
00256               nch = _GETC_(file);
00257               if (width>0) width--;
00258               /* read until no more digits */
00259               while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
00260                         cur = cur*10 + (nch - '0');
00261                         nch = _GETC_(file);
00262             if (width>0) width--;
00263               }
00264             } else {
00265               cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */
00266             }
00267             /* handle decimals */
00268                     if (width!=0 && nch == '.') {
00269                         long double dec = 1;
00270                         nch = _GETC_(file);
00271             if (width>0) width--;
00272                         while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
00273                             dec /= 10;
00274                             cur += dec * (nch - '0');
00275                             nch = _GETC_(file);
00276                 if (width>0) width--;
00277                         }
00278                     }
00279             /* handle exponent */
00280             if (width!=0 && (nch == 'e' || nch == 'E')) {
00281             int exponent = 0, negexp = 0;
00282             float expcnt;
00283                         nch = _GETC_(file);
00284             if (width>0) width--;
00285             /* possible sign on the exponent */
00286             if (width!=0 && (nch=='+' || nch=='-')) {
00287                 negexp = (nch=='-');
00288                             nch = _GETC_(file);
00289                 if (width>0) width--;
00290             }
00291             /* exponent digits */
00292             while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) {
00293                 exponent *= 10;
00294                 exponent += (nch - '0');
00295                             nch = _GETC_(file);
00296                 if (width>0) width--;
00297                         }
00298             /* update 'cur' with this exponent. */
00299             expcnt =  negexp ? 0.1f : 10.0f;
00300             while (exponent!=0) {
00301                 if (exponent&1)
00302                 cur*=expcnt;
00303                 exponent/=2;
00304                 expcnt=expcnt*expcnt;
00305             }
00306             }
00307                     st = 1;
00308                     if (!suppress) {
00309             if (L_prefix) _SET_NUMBER_(long double);
00310             else if (l_prefix) _SET_NUMBER_(double);
00311             else _SET_NUMBER_(float);
00312             }
00313                 }
00314                 break;
00315         /* According to msdn,
00316          * 's' reads a character string in a call to fscanf
00317          * and 'S' a wide character string and vice versa in a
00318          * call to fwscanf. The 'h', 'w' and 'l' prefixes override
00319          * this behaviour. 'h' forces reading char * but 'l' and 'w'
00320          * force reading WCHAR. */
00321         case 's':
00322             if (w_prefix || l_prefix) goto widecharstring;
00323             else if (h_prefix) goto charstring;
00324 #ifdef WIDE_SCANF
00325             else goto widecharstring;
00326 #else /* WIDE_SCANF */
00327             else goto charstring;
00328 #endif /* WIDE_SCANF */
00329         case 'S':
00330             if (w_prefix || l_prefix) goto widecharstring;
00331             else if (h_prefix) goto charstring;
00332 #ifdef WIDE_SCANF
00333             else goto charstring;
00334 #else /* WIDE_SCANF */
00335             else goto widecharstring;
00336 #endif /* WIDE_SCANF */
00337         charstring: { /* read a word into a char */
00338             char *sptr = suppress ? NULL : va_arg(ap, char*);
00339                     /* skip initial whitespace */
00340                     while ((nch!=_EOF_) && _ISSPACE_(nch))
00341                         nch = _GETC_(file);
00342                     /* read until whitespace */
00343                     while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
00344                         if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
00345             st++;
00346                         nch = _GETC_(file);
00347             if (width>0) width--;
00348                     }
00349                     /* terminate */
00350                     if (!suppress) *sptr = 0;
00351                 }
00352                 break;
00353         widecharstring: { /* read a word into a wchar_t* */
00354             wchar_t *sptr = suppress ? NULL : va_arg(ap, wchar_t*);
00355                     /* skip initial whitespace */
00356                     while ((nch!=_EOF_) && _ISSPACE_(nch))
00357                         nch = _GETC_(file);
00358                     /* read until whitespace */
00359                     while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
00360                         if (!suppress) *sptr++ = _WIDE2SUPPORTED_(nch);
00361             st++;
00362                         nch = _GETC_(file);
00363             if (width>0) width--;
00364                     }
00365                     /* terminate */
00366                     if (!suppress) *sptr = 0;
00367                 }
00368                 break;
00369             /* 'c' and 'C work analogously to 's' and 'S' as described
00370          * above */
00371         case 'c':
00372             if (w_prefix || l_prefix) goto widecharacter;
00373             else if (h_prefix) goto character;
00374 #ifdef WIDE_SCANF
00375             else goto widecharacter;
00376 #else /* WIDE_SCANF */
00377             else goto character;
00378 #endif /* WIDE_SCANF */
00379         case 'C':
00380             if (w_prefix || l_prefix) goto widecharacter;
00381             else if (h_prefix) goto character;
00382 #ifdef WIDE_SCANF
00383             else goto character;
00384 #else /* WIDE_SCANF */
00385             else goto widecharacter;
00386 #endif /* WIDE_SCANF */
00387       character: { /* read single character into char */
00388                     char *str = suppress ? NULL : va_arg(ap, char*);
00389                     if (width == -1) width = 1;
00390                     while ((width != 0) && (nch != _EOF_))
00391                     {
00392                         if (!suppress) *str++ = _CHAR2SUPPORTED_(nch);
00393                         st++;
00394                         width--;
00395                         nch = _GETC_(file);
00396                     }
00397                 }
00398         break;
00399       widecharacter: { /* read single character into a wchar_t */
00400                     wchar_t *str = suppress ? NULL : va_arg(ap, wchar_t*);
00401                     if (width == -1) width = 1;
00402                     while ((width != 0) && (nch != _EOF_))
00403                     {
00404                         if (!suppress) *str++ = _WIDE2SUPPORTED_(nch);
00405                         st++;
00406                         width--;
00407                         nch = _GETC_(file);
00408                     }
00409             }
00410         break;
00411         case 'n': {
00412             if (!suppress) {
00413             int*n = va_arg(ap, int*);
00414             *n = consumed - 1;
00415             }
00416             /* This is an odd one: according to the standard,
00417              * "Execution of a %n directive does not increment the
00418              * assignment count returned at the completion of
00419              * execution" even if it wasn't suppressed with the
00420              * '*' flag.  The Corrigendum to the standard seems
00421              * to contradict this (comment out the assignment to
00422              * suppress below if you want to implement these
00423              * alternate semantics) but the windows program I'm
00424              * looking at expects the behavior I've coded here
00425              * (which happens to be what glibc does as well).
00426              */
00427             suppress = 1;
00428             st = 1;
00429             }
00430         break;
00431         case '[': {
00432                     _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*);
00433                     _CHAR_ *sptr = str;
00434             RTL_BITMAP bitMask;
00435                     ULONG *Mask;
00436             int invert = 0; /* Set if we are NOT to find the chars */
00437 
00438             /* Init our bitmap */
00439 #ifdef _LIBCNT_
00440             Mask = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8);
00441 #else
00442             Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8);
00443 #endif
00444             RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_);
00445 
00446             /* Read the format */
00447             format++;
00448             if(*format == '^') {
00449             invert = 1;
00450             format++;
00451             }
00452             if(*format == ']') {
00453             RtlSetBits(&bitMask, ']', 1);
00454             format++;
00455             }
00456                     while(*format && (*format != ']')) {
00457             /* According to msdn:
00458              * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
00459             if((*format == '-') && (*(format + 1) != ']')) {
00460                 if ((*(format - 1)) < *(format + 1))
00461                 RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1));
00462                 else
00463                 RtlSetBits(&bitMask, *(format + 1)    , *(format - 1) - *(format + 1));
00464                 format++;
00465             } else
00466                 RtlSetBits(&bitMask, *format, 1);
00467             format++;
00468             }
00469                     /* read until char is not suitable */
00470                     while ((width != 0) && (nch != _EOF_)) {
00471             if(!invert) {
00472                 if(RtlAreBitsSet(&bitMask, nch, 1)) {
00473                 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
00474                 } else
00475                 break;
00476             } else {
00477                 if(RtlAreBitsClear(&bitMask, nch, 1)) {
00478                 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
00479                 } else
00480                 break;
00481             }
00482                         st++;
00483                         nch = _GETC_(file);
00484                         if (width>0) width--;
00485                     }
00486                     /* terminate */
00487                     if (!suppress) *sptr = 0;
00488 #ifdef _LIBCNT_
00489             RtlFreeHeap(RtlGetProcessHeap(), 0, Mask);
00490 #else
00491             HeapFree(GetProcessHeap(), 0, Mask);
00492 #endif
00493                 }
00494                 break;
00495             default:
00496         /* From spec: "if a percent sign is followed by a character
00497          * that has no meaning as a format-control character, that
00498          * character and the following characters are treated as
00499          * an ordinary sequence of characters, that is, a sequence
00500          * of characters that must match the input.  For example,
00501          * to specify that a percent-sign character is to be input,
00502          * use %%." */
00503                 while ((nch!=_EOF_) && _ISSPACE_(nch))
00504                     nch = _GETC_(file);
00505                 if (nch==*format) {
00506                     suppress = 1; /* whoops no field to be read */
00507                     st = 1; /* but we got what we expected */
00508                     nch = _GETC_(file);
00509                 }
00510                 break;
00511             }
00512             if (st && !suppress) rd++;
00513             else if (!st) break;
00514         }
00515     /* a non-white-space character causes scanf to read, but not store,
00516      * a matching non-white-space character. */
00517         else {
00518             /* check for character match */
00519             if (nch == *format) {
00520         nch = _GETC_(file);
00521             } else break;
00522         }
00523         format++;
00524     }
00525     if (nch!=_EOF_) {
00526     _UNGETC_(nch, file);
00527     }
00528     TRACE("returning %d\n", rd);
00529     return rd;
00530 }
00531 
00532 #undef _CHAR_
00533 #undef _EOF_
00534 #undef _EOF_RET
00535 #undef _ISSPACE_
00536 #undef _ISDIGIT_
00537 #undef _CHAR2SUPPORTED_
00538 #undef _WIDE2SUPPORTED_
00539 #undef _CHAR2DIGIT_
00540 #undef _GETC_
00541 #undef _UNGETC_
00542 #undef _FUNCTION_
00543 #undef _BITMAPSIZE_

Generated on Sat May 26 2012 04:35:35 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.