Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenscanf.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
1.7.6.1
|