1 /* 2 * general implementation of scanf used by scanf, sscanf, fscanf, 3 * _cscanf, wscanf, swscanf and fwscanf 4 * 5 * Copyright 1996,1998 Marcus Meissner 6 * Copyright 1996 Jukka Iivonen 7 * Copyright 1997,2000, 2003 Uwe Bonnes 8 * Copyright 2000 Jon Griffiths 9 * Copyright 2002 Daniel Gudbjartsson 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2.1 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 24 */ 25 26 #ifdef WIDE_SCANF 27 #define _CHAR_ wchar_t 28 #define _EOF_ WEOF 29 #define _EOF_RET (short)WEOF 30 #define _ISSPACE_(c) iswspace(c) 31 #define _ISDIGIT_(c) iswdigit(c) 32 #define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */ 33 #define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */ 34 #define _CHAR2DIGIT_(c, base) wchar2digit((c), (base)) 35 #define _BITMAPSIZE_ 256*256 36 #else /* WIDE_SCANF */ 37 #define _CHAR_ char 38 #define _EOF_ EOF 39 #define _EOF_RET EOF 40 #define _ISSPACE_(c) isspace(c) 41 #define _ISDIGIT_(c) isdigit(c) 42 #define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */ 43 #define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */ 44 #define _CHAR2DIGIT_(c, base) char2digit((c), (base)) 45 #define _BITMAPSIZE_ 256 46 #endif /* WIDE_SCANF */ 47 48 #ifdef CONSOLE 49 #define _GETC_(file) (consumed++, _getch()) 50 #define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) 51 #define _LOCK_FILE_(file) _lock_file(stdin) 52 #define _UNLOCK_FILE_(file) _unlock_file(stdin) 53 #ifdef WIDE_SCANF 54 #ifdef SECURE 55 #define _FUNCTION_ static int vcwscanf_s_l(const char *format, _locale_t locale, __ms_va_list ap) 56 #else /* SECURE */ 57 #define _FUNCTION_ static int vcwscanf_l(const char *format, _locale_t locale, __ms_va_list ap) 58 #endif /* SECURE */ 59 #else /* WIDE_SCANF */ 60 #ifdef SECURE 61 #define _FUNCTION_ static int vcscanf_s_l(const char *format, _locale_t locale, __ms_va_list ap) 62 #else /* SECURE */ 63 #define _FUNCTION_ static int vcscanf_l(const char *format, _locale_t locale, __ms_va_list ap) 64 #endif /* SECURE */ 65 #endif /* WIDE_SCANF */ 66 #else 67 #ifdef STRING 68 #undef _EOF_ 69 #define _EOF_ 0 70 #ifdef STRING_LEN 71 #define _GETC_(file) (consumed==length ? '\0' : (consumed++, *file++)) 72 #define _UNGETC_(nch, file) do { file--; consumed--; } while(0) 73 #define _LOCK_FILE_(file) do {} while(0) 74 #define _UNLOCK_FILE_(file) do {} while(0) 75 #ifdef WIDE_SCANF 76 #ifdef SECURE 77 #define _FUNCTION_ static int vsnwscanf_s_l(const wchar_t *file, size_t length, const wchar_t *format, _locale_t locale, __ms_va_list ap) 78 #else /* SECURE */ 79 #define _FUNCTION_ static int vsnwscanf_l(const wchar_t *file, size_t length, const wchar_t *format, _locale_t locale, __ms_va_list ap) 80 #endif /* SECURE */ 81 #else /* WIDE_SCANF */ 82 #ifdef SECURE 83 #define _FUNCTION_ static int vsnscanf_s_l(const char *file, size_t length, const char *format, _locale_t locale, __ms_va_list ap) 84 #else /* SECURE */ 85 #define _FUNCTION_ static int vsnscanf_l(const char *file, size_t length, const char *format, _locale_t locale, __ms_va_list ap) 86 #endif /* SECURE */ 87 #endif /* WIDE_SCANF */ 88 #else /* STRING_LEN */ 89 #define _GETC_(file) (consumed++, *file++) 90 #define _UNGETC_(nch, file) do { file--; consumed--; } while(0) 91 #define _LOCK_FILE_(file) do {} while(0) 92 #define _UNLOCK_FILE_(file) do {} while(0) 93 #ifdef WIDE_SCANF 94 #ifdef SECURE 95 #define _FUNCTION_ static int vswscanf_s_l(const wchar_t *file, const wchar_t *format, _locale_t locale, __ms_va_list ap) 96 #else /* SECURE */ 97 #define _FUNCTION_ static int vswscanf_l(const wchar_t *file, const wchar_t *format, _locale_t locale, __ms_va_list ap) 98 #endif /* SECURE */ 99 #else /* WIDE_SCANF */ 100 #ifdef SECURE 101 #define _FUNCTION_ static int vsscanf_s_l(const char *file, const char *format, _locale_t locale, __ms_va_list ap) 102 #else /* SECURE */ 103 #define _FUNCTION_ static int vsscanf_l(const char *file, const char *format, _locale_t locale, __ms_va_list ap) 104 #endif /* SECURE */ 105 #endif /* WIDE_SCANF */ 106 #endif /* STRING_LEN */ 107 #else /* STRING */ 108 #ifdef WIDE_SCANF 109 #define _GETC_(file) (consumed++, fgetwc(file)) 110 #define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) 111 #define _LOCK_FILE_(file) _lock_file(file) 112 #define _UNLOCK_FILE_(file) _unlock_file(file) 113 #ifdef SECURE 114 #define _FUNCTION_ static int vfwscanf_s_l(FILE* file, const wchar_t *format, _locale_t locale, __ms_va_list ap) 115 #else /* SECURE */ 116 #define _FUNCTION_ static int vfwscanf_l(FILE* file, const wchar_t *format, _locale_t locale, __ms_va_list ap) 117 #endif /* SECURE */ 118 #else /* WIDE_SCANF */ 119 #define _GETC_(file) (consumed++, fgetc(file)) 120 #define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) 121 #define _LOCK_FILE_(file) _lock_file(file) 122 #define _UNLOCK_FILE_(file) _unlock_file(file) 123 #ifdef SECURE 124 #define _FUNCTION_ static int vfscanf_s_l(FILE* file, const char *format, _locale_t locale, __ms_va_list ap) 125 #else /* SECURE */ 126 #define _FUNCTION_ static int vfscanf_l(FILE* file, const char *format, _locale_t locale, __ms_va_list ap) 127 #endif /* SECURE */ 128 #endif /* WIDE_SCANF */ 129 #endif /* STRING */ 130 #endif /* CONSOLE */ 131 132 _FUNCTION_ { 133 pthreadlocinfo locinfo; 134 int rd = 0, consumed = 0; 135 int nch; 136 if (!*format) return 0; 137 #ifndef WIDE_SCANF 138 #ifdef CONSOLE 139 TRACE("(%s):\n", debugstr_a(format)); 140 #else /* CONSOLE */ 141 #ifdef STRING 142 TRACE("%s (%s)\n", debugstr_a(file), debugstr_a(format)); 143 #else /* STRING */ 144 TRACE("%p (%s)\n", file, debugstr_a(format)); 145 #endif /* STRING */ 146 #endif /* CONSOLE */ 147 #endif /* WIDE_SCANF */ 148 _LOCK_FILE_(file); 149 150 nch = _GETC_(file); 151 if (nch == _EOF_) { 152 _UNLOCK_FILE_(file); 153 return _EOF_RET; 154 } 155 156 if(!locale) 157 locinfo = get_locinfo(); 158 else 159 locinfo = locale->locinfo; 160 161 while (*format) { 162 /* a whitespace character in the format string causes scanf to read, 163 * but not store, all consecutive white-space characters in the input 164 * up to the next non-white-space character. One white space character 165 * in the input matches any number (including zero) and combination of 166 * white-space characters in the input. */ 167 if (_ISSPACE_(*format)) { 168 /* skip whitespace */ 169 while ((nch!=_EOF_) && _ISSPACE_(nch)) 170 nch = _GETC_(file); 171 } 172 /* a format specification causes scanf to read and convert characters 173 * in the input into values of a specified type. The value is assigned 174 * to an argument in the argument list. Format specifications have 175 * the form %[*][width][{h | l | I64 | L}]type */ 176 else if (*format == '%') { 177 int st = 0; int suppress = 0; int width = 0; 178 int base; 179 int h_prefix = 0; 180 int l_prefix = 0; 181 int L_prefix = 0; 182 int w_prefix = 0; 183 int prefix_finished = 0; 184 int I64_prefix = 0; 185 format++; 186 /* look for leading asterisk, which means 'suppress assignment of 187 * this field'. */ 188 if (*format=='*') { 189 format++; 190 suppress=1; 191 } 192 /* look for width specification */ 193 while (_ISDIGIT_(*format)) { 194 width*=10; 195 width+=*format++ - '0'; 196 } 197 if (width==0) width=-1; /* no width spec seen */ 198 /* read prefix (if any) */ 199 while (!prefix_finished) { 200 switch(*format) { 201 case 'h': h_prefix++; break; 202 case 'l': 203 if(*(format+1) == 'l') { 204 I64_prefix = 1; 205 format++; 206 } 207 l_prefix = 1; 208 break; 209 case 'w': w_prefix = 1; break; 210 case 'L': L_prefix = 1; break; 211 case 'I': 212 if (*(format + 1) == '6' && 213 *(format + 2) == '4') { 214 I64_prefix = 1; 215 format += 2; 216 } 217 break; 218 default: 219 prefix_finished = 1; 220 } 221 if (!prefix_finished) format++; 222 } 223 /* read type */ 224 switch(*format) { 225 case 'p': 226 case 'P': /* pointer. */ 227 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1; 228 /* fall through */ 229 case 'x': 230 case 'X': /* hexadecimal integer. */ 231 base = 16; 232 goto number; 233 case 'o': /* octal integer */ 234 base = 8; 235 goto number; 236 case 'u': /* unsigned decimal integer */ 237 base = 10; 238 goto number; 239 case 'd': /* signed decimal integer */ 240 base = 10; 241 goto number; 242 case 'i': /* generic integer */ 243 base = 0; 244 number: { 245 /* read an integer */ 246 ULONGLONG cur = 0; 247 int negative = 0; 248 int seendigit=0; 249 /* skip initial whitespace */ 250 while ((nch!=_EOF_) && _ISSPACE_(nch)) 251 nch = _GETC_(file); 252 /* get sign */ 253 if (nch == '-' || nch == '+') { 254 negative = (nch=='-'); 255 nch = _GETC_(file); 256 if (width>0) width--; 257 } 258 /* look for leading indication of base */ 259 if (width!=0 && nch == '0' && *format != 'p' && *format != 'P') { 260 nch = _GETC_(file); 261 if (width>0) width--; 262 seendigit=1; 263 if (width!=0 && (nch=='x' || nch=='X')) { 264 if (base==0) 265 base=16; 266 if (base==16) { 267 nch = _GETC_(file); 268 if (width>0) width--; 269 seendigit=0; 270 } 271 } else if (base==0) 272 base = 8; 273 } 274 /* format %i without indication of base */ 275 if (base==0) 276 base = 10; 277 /* throw away leading zeros */ 278 while (width!=0 && nch=='0') { 279 nch = _GETC_(file); 280 if (width>0) width--; 281 seendigit=1; 282 } 283 if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) { 284 cur = _CHAR2DIGIT_(nch, base); 285 nch = _GETC_(file); 286 if (width>0) width--; 287 seendigit=1; 288 } 289 /* read until no more digits */ 290 while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) { 291 cur = cur*base + _CHAR2DIGIT_(nch, base); 292 nch = _GETC_(file); 293 if (width>0) width--; 294 seendigit=1; 295 } 296 /* okay, done! */ 297 if (!seendigit) break; /* not a valid number */ 298 st = 1; 299 if (!suppress) { 300 #define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -(LONGLONG)cur : cur 301 if (I64_prefix) _SET_NUMBER_(LONGLONG); 302 else if (l_prefix) _SET_NUMBER_(LONG); 303 else if (h_prefix == 1) _SET_NUMBER_(short int); 304 else _SET_NUMBER_(int); 305 } 306 } 307 break; 308 case 'e': 309 case 'E': 310 case 'f': 311 case 'g': 312 case 'G': { /* read a float */ 313 //long double cur = 1, expcnt = 10; 314 ULONGLONG d, hlp; 315 int exp = 0, negative = 0; 316 //unsigned fpcontrol; 317 //BOOL negexp; 318 319 /* skip initial whitespace */ 320 while ((nch!=_EOF_) && _ISSPACE_(nch)) 321 nch = _GETC_(file); 322 323 /* get sign. */ 324 if (nch == '-' || nch == '+') { 325 negative = (nch=='-'); 326 if (width>0) width--; 327 if (width==0) break; 328 nch = _GETC_(file); 329 } 330 331 /* get first digit. */ 332 if (*locinfo->lconv->decimal_point != nch) { 333 if (!_ISDIGIT_(nch)) break; 334 d = nch - '0'; 335 nch = _GETC_(file); 336 if (width>0) width--; 337 /* read until no more digits */ 338 while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { 339 hlp = d*10 + nch - '0'; 340 nch = _GETC_(file); 341 if (width>0) width--; 342 if(d > (ULONGLONG)-1/10 || hlp<d) { 343 exp++; 344 break; 345 } 346 else 347 d = hlp; 348 } 349 while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { 350 exp++; 351 nch = _GETC_(file); 352 if (width>0) width--; 353 } 354 } else { 355 d = 0; /* Fix: .8 -> 0.8 */ 356 } 357 358 /* handle decimals */ 359 if (width!=0 && nch == *locinfo->lconv->decimal_point) { 360 nch = _GETC_(file); 361 if (width>0) width--; 362 363 while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { 364 hlp = d*10 + nch - '0'; 365 nch = _GETC_(file); 366 if (width>0) width--; 367 if(d > (ULONGLONG)-1/10 || hlp<d) 368 break; 369 370 d = hlp; 371 exp--; 372 } 373 while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { 374 nch = _GETC_(file); 375 if (width>0) width--; 376 } 377 } 378 379 /* handle exponent */ 380 if (width!=0 && (nch == 'e' || nch == 'E')) { 381 int sign = 1, e = 0; 382 383 nch = _GETC_(file); 384 if (width>0) width--; 385 if (width!=0 && (nch=='+' || nch=='-')) { 386 if(nch == '-') 387 sign = -1; 388 nch = _GETC_(file); 389 if (width>0) width--; 390 } 391 392 /* exponent digits */ 393 while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { 394 if(e > INT_MAX/10 || (e = e*10 + nch - '0')<0) 395 e = INT_MAX; 396 nch = _GETC_(file); 397 if (width>0) width--; 398 } 399 e *= sign; 400 401 if(exp<0 && e<0 && e+exp>0) exp = INT_MIN; 402 else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX; 403 else exp += e; 404 } 405 406 #ifdef __REACTOS__ 407 /* ReactOS: don't inline float processing (kernel/freeldr don't like that! */ 408 _internal_handle_float(negative, exp, suppress, d, l_prefix || L_prefix, &ap); 409 st = 1; 410 #else 411 #ifdef _M_ARM 412 DbgBreakPoint(); 413 #else 414 fpcontrol = _control87(0, 0); 415 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE 416 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff); 417 #endif 418 negexp = (exp < 0); 419 if(negexp) 420 exp = -exp; 421 /* update 'cur' with this exponent. */ 422 while(exp) { 423 if(exp & 1) 424 cur *= expcnt; 425 exp /= 2; 426 expcnt = expcnt*expcnt; 427 } 428 cur = (negexp ? d/cur : d*cur); 429 #ifdef _M_ARM 430 DbgBreakPoint(); 431 #else 432 _control87(fpcontrol, 0xffffffff); 433 #endif 434 st = 1; 435 if (!suppress) { 436 if (L_prefix) _SET_NUMBER_(double); 437 else if (l_prefix) _SET_NUMBER_(double); 438 else _SET_NUMBER_(float); 439 } 440 #endif /* __REACTOS__ */ 441 } 442 break; 443 /* According to msdn, 444 * 's' reads a character string in a call to fscanf 445 * and 'S' a wide character string and vice versa in a 446 * call to fwscanf. The 'h', 'w' and 'l' prefixes override 447 * this behaviour. 'h' forces reading char * but 'l' and 'w' 448 * force reading WCHAR. */ 449 case 's': 450 if (w_prefix || l_prefix) goto widecharstring; 451 else if (h_prefix) goto charstring; 452 #ifdef WIDE_SCANF 453 else goto widecharstring; 454 #else /* WIDE_SCANF */ 455 else goto charstring; 456 #endif /* WIDE_SCANF */ 457 case 'S': 458 if (w_prefix || l_prefix) goto widecharstring; 459 else if (h_prefix) goto charstring; 460 #ifdef WIDE_SCANF 461 else goto charstring; 462 #else /* WIDE_SCANF */ 463 else goto widecharstring; 464 #endif /* WIDE_SCANF */ 465 charstring: { /* read a word into a char */ 466 char *sptr = suppress ? NULL : va_arg(ap, char*); 467 char *sptr_beg = sptr; 468 #ifdef SECURE 469 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned); 470 #else 471 unsigned size = UINT_MAX; 472 #endif 473 /* skip initial whitespace */ 474 while ((nch!=_EOF_) && _ISSPACE_(nch)) 475 nch = _GETC_(file); 476 /* read until whitespace */ 477 while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { 478 if (!suppress) { 479 *sptr++ = _CHAR2SUPPORTED_(nch); 480 if(size>1) size--; 481 else { 482 _UNLOCK_FILE_(file); 483 *sptr_beg = 0; 484 return rd; 485 } 486 } 487 st++; 488 nch = _GETC_(file); 489 if (width>0) width--; 490 } 491 /* terminate */ 492 if (st && !suppress) *sptr = 0; 493 } 494 break; 495 widecharstring: { /* read a word into a wchar_t* */ 496 wchar_t *sptr = suppress ? NULL : va_arg(ap, wchar_t*); 497 wchar_t *sptr_beg = sptr; 498 #ifdef SECURE 499 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned); 500 #else 501 unsigned size = UINT_MAX; 502 #endif 503 /* skip initial whitespace */ 504 while ((nch!=_EOF_) && _ISSPACE_(nch)) 505 nch = _GETC_(file); 506 /* read until whitespace */ 507 while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { 508 if (!suppress) { 509 *sptr++ = _WIDE2SUPPORTED_(nch); 510 if(size>1) size--; 511 else { 512 _UNLOCK_FILE_(file); 513 *sptr_beg = 0; 514 return rd; 515 } 516 } 517 st++; 518 nch = _GETC_(file); 519 if (width>0) width--; 520 } 521 /* terminate */ 522 if (st && !suppress) *sptr = 0; 523 } 524 break; 525 /* 'c' and 'C work analogously to 's' and 'S' as described 526 * above */ 527 case 'c': 528 if (w_prefix || l_prefix) goto widecharacter; 529 else if (h_prefix) goto character; 530 #ifdef WIDE_SCANF 531 else goto widecharacter; 532 #else /* WIDE_SCANF */ 533 else goto character; 534 #endif /* WIDE_SCANF */ 535 case 'C': 536 if (w_prefix || l_prefix) goto widecharacter; 537 else if (h_prefix) goto character; 538 #ifdef WIDE_SCANF 539 else goto character; 540 #else /* WIDE_SCANF */ 541 else goto widecharacter; 542 #endif /* WIDE_SCANF */ 543 character: { /* read single character into char */ 544 char *str = suppress ? NULL : va_arg(ap, char*); 545 char *pstr = str; 546 #ifdef SECURE 547 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned)/sizeof(char); 548 #else 549 unsigned size = UINT_MAX; 550 #endif 551 if (width == -1) width = 1; 552 while (width && (nch != _EOF_)) 553 { 554 if (!suppress) { 555 *str++ = _CHAR2SUPPORTED_(nch); 556 if(size) size--; 557 else { 558 _UNLOCK_FILE_(file); 559 *pstr = 0; 560 return rd; 561 } 562 } 563 st++; 564 width--; 565 nch = _GETC_(file); 566 } 567 } 568 break; 569 widecharacter: { /* read single character into a wchar_t */ 570 wchar_t *str = suppress ? NULL : va_arg(ap, wchar_t*); 571 wchar_t *pstr = str; 572 #ifdef SECURE 573 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned)/sizeof(wchar_t); 574 #else 575 unsigned size = UINT_MAX; 576 #endif 577 if (width == -1) width = 1; 578 while (width && (nch != _EOF_)) 579 { 580 if (!suppress) { 581 *str++ = _WIDE2SUPPORTED_(nch); 582 if(size) size--; 583 else { 584 _UNLOCK_FILE_(file); 585 *pstr = 0; 586 return rd; 587 } 588 } 589 st++; 590 width--; 591 nch = _GETC_(file); 592 } 593 } 594 break; 595 case 'n': { 596 if (!suppress) { 597 int*n = va_arg(ap, int*); 598 *n = consumed - 1; 599 } 600 /* This is an odd one: according to the standard, 601 * "Execution of a %n directive does not increment the 602 * assignment count returned at the completion of 603 * execution" even if it wasn't suppressed with the 604 * '*' flag. The Corrigendum to the standard seems 605 * to contradict this (comment out the assignment to 606 * suppress below if you want to implement these 607 * alternate semantics) but the windows program I'm 608 * looking at expects the behavior I've coded here 609 * (which happens to be what glibc does as well). 610 */ 611 suppress = 1; 612 st = 1; 613 } 614 break; 615 case '[': { 616 _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*); 617 _CHAR_ *sptr = str; 618 RTL_BITMAP bitMask; 619 ULONG *Mask; 620 int invert = 0; /* Set if we are NOT to find the chars */ 621 #ifdef SECURE 622 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned)/sizeof(_CHAR_); 623 #else 624 unsigned size = UINT_MAX; 625 #endif 626 627 /* Init our bitmap */ 628 Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); 629 RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); 630 631 /* Read the format */ 632 format++; 633 if(*format == '^') { 634 invert = 1; 635 format++; 636 } 637 if(*format == ']') { 638 RtlSetBits(&bitMask, ']', 1); 639 format++; 640 } 641 while(*format && (*format != ']')) { 642 /* According to msdn: 643 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */ 644 if((*format == '-') && (*(format + 1) != ']')) { 645 if ((*(format - 1)) < *(format + 1)) 646 RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1)); 647 else 648 RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1)); 649 format++; 650 } else 651 RtlSetBits(&bitMask, *format, 1); 652 format++; 653 } 654 /* read until char is not suitable */ 655 while ((width != 0) && (nch != _EOF_)) { 656 if(!invert) { 657 if(RtlAreBitsSet(&bitMask, nch, 1)) { 658 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); 659 } else 660 break; 661 } else { 662 if(RtlAreBitsClear(&bitMask, nch, 1)) { 663 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); 664 } else 665 break; 666 } 667 st++; 668 nch = _GETC_(file); 669 if (width>0) width--; 670 if(size>1) size--; 671 else { 672 _UNLOCK_FILE_(file); 673 *str = 0; 674 return rd; 675 } 676 } 677 /* terminate */ 678 if (!suppress) *sptr = 0; 679 HeapFree(GetProcessHeap(), 0, Mask); 680 } 681 break; 682 default: 683 /* From spec: "if a percent sign is followed by a character 684 * that has no meaning as a format-control character, that 685 * character and the following characters are treated as 686 * an ordinary sequence of characters, that is, a sequence 687 * of characters that must match the input. For example, 688 * to specify that a percent-sign character is to be input, 689 * use %%." */ 690 while ((nch!=_EOF_) && _ISSPACE_(nch)) 691 nch = _GETC_(file); 692 if (nch==*format) { 693 suppress = 1; /* whoops no field to be read */ 694 st = 1; /* but we got what we expected */ 695 nch = _GETC_(file); 696 } 697 break; 698 } 699 if (st && !suppress) rd++; 700 else if (!st) break; 701 } 702 /* a non-white-space character causes scanf to read, but not store, 703 * a matching non-white-space character. */ 704 else { 705 /* check for character match */ 706 if (nch == *format) { 707 nch = _GETC_(file); 708 } else break; 709 } 710 format++; 711 } 712 if (nch!=_EOF_) { 713 _UNGETC_(nch, file); 714 } 715 716 TRACE("returning %d\n", rd); 717 _UNLOCK_FILE_(file); 718 return rd; 719 } 720 721 #undef _CHAR_ 722 #undef _EOF_ 723 #undef _EOF_RET 724 #undef _ISSPACE_ 725 #undef _ISDIGIT_ 726 #undef _CHAR2SUPPORTED_ 727 #undef _WIDE2SUPPORTED_ 728 #undef _CHAR2DIGIT_ 729 #undef _GETC_ 730 #undef _UNGETC_ 731 #undef _LOCK_FILE_ 732 #undef _UNLOCK_FILE_ 733 #undef _FUNCTION_ 734 #undef _BITMAPSIZE_ 735