d3dcompiler_43/tests: Fix the spelling of a couple of ok() messages.
[wine/zf.git] / dlls / msvcrt / scanf.h
blob3b4686c11070ba98c573aaf8bffdaf90d983c335
1 /*
2 * general implementation of scanf used by scanf, sscanf, fscanf,
3 * _cscanf, wscanf, swscanf and fwscanf
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
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.
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.
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
26 #ifdef WIDE_SCANF
27 #define _CHAR_ MSVCRT_wchar_t
28 #define _EOF_ MSVCRT_WEOF
29 #define _EOF_RET (short)MSVCRT_WEOF
30 #define _ISSPACE_(c) MSVCRT_iswspace(c)
31 #define _ISDIGIT_(c) MSVCRT_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_ MSVCRT_EOF
39 #define _EOF_RET MSVCRT_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 */
48 #ifdef CONSOLE
49 #define _GETC_FUNC_(file) _getch()
50 #define _STRTOD_NAME_(func) console_ ## func
51 #define _GETC_(file) (consumed++, _getch())
52 #define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0)
53 #define _LOCK_FILE_(file) MSVCRT__lock_file(MSVCRT_stdin)
54 #define _UNLOCK_FILE_(file) MSVCRT__unlock_file(MSVCRT_stdin)
55 #ifdef WIDE_SCANF
56 #ifdef SECURE
57 #define _FUNCTION_ static int MSVCRT_vcwscanf_s_l(const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
58 #else /* SECURE */
59 #define _FUNCTION_ static int MSVCRT_vcwscanf_l(const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
60 #endif /* SECURE */
61 #else /* WIDE_SCANF */
62 #ifdef SECURE
63 #define _FUNCTION_ static int MSVCRT_vcscanf_s_l(const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
64 #else /* SECURE */
65 #define _FUNCTION_ static int MSVCRT_vcscanf_l(const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
66 #endif /* SECURE */
67 #endif /* WIDE_SCANF */
68 #else
69 #ifdef STRING
70 #undef _EOF_
71 #define _EOF_ 0
72 #define _GETC_FUNC_(file) (*file++)
73 #ifdef WIDE_SCANF
74 #define _STRTOD_NAME_(func) wstr_ ## func
75 #else
76 #define _STRTOD_NAME_(func) str_ ## func
77 #endif
78 #ifdef STRING_LEN
79 #ifdef WIDE_SCANF
80 #define _GETC_(file) (consumed++, consumed>length ? '\0' : *file++)
81 #else /* WIDE_SCANF */
82 #define _GETC_(file) (consumed++, consumed>length ? '\0' : (unsigned char)*file++)
83 #endif /* WIDE_SCANF */
84 #define _UNGETC_(nch, file) do { file--; consumed--; } while(0)
85 #define _LOCK_FILE_(file) do {} while(0)
86 #define _UNLOCK_FILE_(file) do {} while(0)
87 #ifdef WIDE_SCANF
88 #ifdef SECURE
89 #define _FUNCTION_ static int MSVCRT_vsnwscanf_s_l(const MSVCRT_wchar_t *file, MSVCRT_size_t length, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
90 #else /* SECURE */
91 #define _FUNCTION_ static int MSVCRT_vsnwscanf_l(const MSVCRT_wchar_t *file, MSVCRT_size_t length, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
92 #endif /* SECURE */
93 #else /* WIDE_SCANF */
94 #ifdef SECURE
95 #define _FUNCTION_ static int MSVCRT_vsnscanf_s_l(const char *file, MSVCRT_size_t length, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
96 #else /* SECURE */
97 #define _FUNCTION_ static int MSVCRT_vsnscanf_l(const char *file, MSVCRT_size_t length, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
98 #endif /* SECURE */
99 #endif /* WIDE_SCANF */
100 #else /* STRING_LEN */
101 #ifdef WIDE_SCANF
102 #define _GETC_(file) (consumed++, *file++)
103 #else /* WIDE_SCANF */
104 #define _GETC_(file) (consumed++, (unsigned char)*file++)
105 #endif /* WIDE_SCANF */
106 #define _UNGETC_(nch, file) do { file--; consumed--; } while(0)
107 #define _LOCK_FILE_(file) do {} while(0)
108 #define _UNLOCK_FILE_(file) do {} while(0)
109 #ifdef WIDE_SCANF
110 #ifdef SECURE
111 #define _FUNCTION_ static int MSVCRT_vswscanf_s_l(const MSVCRT_wchar_t *file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
112 #else /* SECURE */
113 #define _FUNCTION_ static int MSVCRT_vswscanf_l(const MSVCRT_wchar_t *file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
114 #endif /* SECURE */
115 #else /* WIDE_SCANF */
116 #ifdef SECURE
117 #define _FUNCTION_ static int MSVCRT_vsscanf_s_l(const char *file, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
118 #else /* SECURE */
119 #define _FUNCTION_ static int MSVCRT_vsscanf_l(const char *file, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
120 #endif /* SECURE */
121 #endif /* WIDE_SCANF */
122 #endif /* STRING_LEN */
123 #else /* STRING */
124 #ifdef WIDE_SCANF
125 #define _GETC_FUNC_(file) MSVCRT_fgetwc(file)
126 #define _STRTOD_NAME_(func) filew_ ## func
127 #define _GETC_(file) (consumed++, MSVCRT_fgetwc(file))
128 #define _UNGETC_(nch, file) do { MSVCRT_ungetwc(nch, file); consumed--; } while(0)
129 #define _LOCK_FILE_(file) MSVCRT__lock_file(file)
130 #define _UNLOCK_FILE_(file) MSVCRT__unlock_file(file)
131 #ifdef SECURE
132 #define _FUNCTION_ static int MSVCRT_vfwscanf_s_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
133 #else /* SECURE */
134 #define _FUNCTION_ static int MSVCRT_vfwscanf_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list ap)
135 #endif /* SECURE */
136 #else /* WIDE_SCANF */
137 #define _GETC_FUNC_(file) MSVCRT_fgetc(file)
138 #define _STRTOD_NAME_(func) file_ ## func
139 #define _GETC_(file) (consumed++, MSVCRT_fgetc(file))
140 #define _UNGETC_(nch, file) do { MSVCRT_ungetc(nch, file); consumed--; } while(0)
141 #define _LOCK_FILE_(file) MSVCRT__lock_file(file)
142 #define _UNLOCK_FILE_(file) MSVCRT__unlock_file(file)
143 #ifdef SECURE
144 #define _FUNCTION_ static int MSVCRT_vfscanf_s_l(MSVCRT_FILE* file, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
145 #else /* SECURE */
146 #define _FUNCTION_ static int MSVCRT_vfscanf_l(MSVCRT_FILE* file, const char *format, MSVCRT__locale_t locale, __ms_va_list ap)
147 #endif /* SECURE */
148 #endif /* WIDE_SCANF */
149 #endif /* STRING */
150 #endif /* CONSOLE */
152 #if (!defined(SECURE) && !defined(STRING_LEN) && (!defined(CONSOLE) || !defined(WIDE_SCANF)))
153 struct _STRTOD_NAME_(strtod_scanf_ctx) {
154 MSVCRT_pthreadlocinfo locinfo;
155 #ifdef STRING
156 const _CHAR_ *file;
157 #else
158 MSVCRT_FILE *file;
159 #endif
160 int length;
161 int read;
162 int cur;
163 int unget;
164 BOOL err;
167 static MSVCRT_wchar_t _STRTOD_NAME_(strtod_scanf_get)(void *ctx)
169 struct _STRTOD_NAME_(strtod_scanf_ctx) *context = ctx;
171 context->cur = _EOF_;
172 if (!context->length) return MSVCRT_WEOF;
173 if (context->unget != _EOF_) {
174 context->cur = context->unget;
175 context->unget = _EOF_;
176 } else {
177 context->cur = _GETC_FUNC_(context->file);
178 if (context->cur == _EOF_) return MSVCRT_WEOF;
181 if (context->length > 0) context->length--;
182 context->read++;
183 return context->cur;
186 static void _STRTOD_NAME_(strtod_scanf_unget)(void *ctx)
188 struct _STRTOD_NAME_(strtod_scanf_ctx) *context = ctx;
190 if (context->length >= 0) context->length++;
191 context->read--;
192 if (context->unget != _EOF_ || context->cur == _EOF_) {
193 context->err = TRUE;
194 return;
196 context->unget = context->cur;
198 #endif
200 _FUNCTION_ {
201 MSVCRT_pthreadlocinfo locinfo;
202 int rd = 0, consumed = 0;
203 int nch;
204 if (!*format) return 0;
205 #ifndef WIDE_SCANF
206 #ifdef CONSOLE
207 TRACE("(%s):\n", debugstr_a(format));
208 #else /* CONSOLE */
209 #ifdef STRING
210 TRACE("%s (%s)\n", debugstr_a(file), debugstr_a(format));
211 #else /* STRING */
212 TRACE("%p (%s)\n", file, debugstr_a(format));
213 #endif /* STRING */
214 #endif /* CONSOLE */
215 #endif /* WIDE_SCANF */
216 _LOCK_FILE_(file);
218 nch = _GETC_(file);
219 if (nch == _EOF_) {
220 _UNLOCK_FILE_(file);
221 return _EOF_RET;
224 if(!locale)
225 locinfo = get_locinfo();
226 else
227 locinfo = locale->locinfo;
229 while (*format) {
230 /* a whitespace character in the format string causes scanf to read,
231 * but not store, all consecutive white-space characters in the input
232 * up to the next non-white-space character. One white space character
233 * in the input matches any number (including zero) and combination of
234 * white-space characters in the input. */
235 if (_ISSPACE_(*format)) {
236 /* skip whitespace */
237 while ((nch!=_EOF_) && _ISSPACE_(nch))
238 nch = _GETC_(file);
240 /* a format specification causes scanf to read and convert characters
241 * in the input into values of a specified type. The value is assigned
242 * to an argument in the argument list. Format specifications have
243 * the form %[*][width][{h | l | I64 | L}]type */
244 else if (*format == '%') {
245 int st = 0; int suppress = 0; int width = 0;
246 int base;
247 int h_prefix = 0;
248 int l_prefix = 0;
249 int L_prefix = 0;
250 int w_prefix = 0;
251 int prefix_finished = 0;
252 int I64_prefix = 0;
253 format++;
254 /* look for leading asterisk, which means 'suppress assignment of
255 * this field'. */
256 if (*format=='*') {
257 format++;
258 suppress=1;
260 /* read prefix (if any) */
261 while (!prefix_finished) {
262 /* look for width specification */
263 while (_ISDIGIT_(*format)) {
264 width *= 10;
265 width += *format++ - '0';
268 switch(*format) {
269 case 'h': h_prefix++; break;
270 case 'l':
271 if(*(format+1) == 'l') {
272 I64_prefix = 1;
273 format++;
275 l_prefix = 1;
276 break;
277 case 'w': w_prefix = 1; break;
278 case 'L': L_prefix = 1; break;
279 case 'I':
280 if (*(format + 1) == '6' &&
281 *(format + 2) == '4') {
282 I64_prefix = 1;
283 format += 2;
285 break;
286 default:
287 prefix_finished = 1;
289 if (!prefix_finished) format++;
291 if (width==0) width=-1; /* no width spec seen */
292 /* read type */
293 switch(*format) {
294 case 'p':
295 case 'P': /* pointer. */
296 if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1;
297 /* fall through */
298 case 'x':
299 case 'X': /* hexadecimal integer. */
300 base = 16;
301 goto number;
302 case 'o': /* octal integer */
303 base = 8;
304 goto number;
305 case 'u': /* unsigned decimal integer */
306 base = 10;
307 goto number;
308 case 'd': /* signed decimal integer */
309 base = 10;
310 goto number;
311 case 'i': /* generic integer */
312 base = 0;
313 number: {
314 /* read an integer */
315 ULONGLONG cur = 0;
316 int negative = 0;
317 int seendigit=0;
318 /* skip initial whitespace */
319 while ((nch!=_EOF_) && _ISSPACE_(nch))
320 nch = _GETC_(file);
321 /* get sign */
322 if (nch == '-' || nch == '+') {
323 negative = (nch=='-');
324 nch = _GETC_(file);
325 if (width>0) width--;
327 /* look for leading indication of base */
328 if (width!=0 && nch == '0' && *format != 'p' && *format != 'P') {
329 nch = _GETC_(file);
330 if (width>0) width--;
331 seendigit=1;
332 if (width!=0 && (nch=='x' || nch=='X')) {
333 if (base==0)
334 base=16;
335 if (base==16) {
336 nch = _GETC_(file);
337 if (width>0) width--;
338 seendigit=0;
340 } else if (base==0)
341 base = 8;
343 /* format %i without indication of base */
344 if (base==0)
345 base = 10;
346 /* throw away leading zeros */
347 while (width!=0 && nch=='0') {
348 nch = _GETC_(file);
349 if (width>0) width--;
350 seendigit=1;
352 if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) {
353 cur = _CHAR2DIGIT_(nch, base);
354 nch = _GETC_(file);
355 if (width>0) width--;
356 seendigit=1;
358 /* read until no more digits */
359 while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) {
360 cur = cur*base + _CHAR2DIGIT_(nch, base);
361 nch = _GETC_(file);
362 if (width>0) width--;
363 seendigit=1;
365 /* okay, done! */
366 if (!seendigit) break; /* not a valid number */
367 st = 1;
368 if (!suppress) {
369 #define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur
370 if (I64_prefix) _SET_NUMBER_(LONGLONG);
371 else if (l_prefix) _SET_NUMBER_(LONG);
372 else if (h_prefix == 1) _SET_NUMBER_(short int);
373 #if _MSVCR_VER >= 140
374 else if (h_prefix == 2) _SET_NUMBER_(char);
375 #endif
376 else _SET_NUMBER_(int);
379 break;
380 case 'e':
381 case 'E':
382 case 'f':
383 case 'g':
384 case 'G': { /* read a float */
385 #ifdef CONSOLE
386 struct _STRTOD_NAME_(strtod_scanf_ctx) ctx = {locinfo, 0, width};
387 #else
388 struct _STRTOD_NAME_(strtod_scanf_ctx) ctx = {locinfo, file, width};
389 #endif
390 int negative = 0;
391 struct fpnum fp;
392 double cur;
394 /* skip initial whitespace */
395 while ((nch!=_EOF_) && _ISSPACE_(nch))
396 nch = _GETC_(file);
397 if (nch == _EOF_)
398 break;
399 ctx.unget = nch;
400 #ifdef STRING
401 ctx.file = file;
402 #endif
403 #ifdef STRING_LEN
404 if(ctx.length > length-consumed+1) ctx.length = length-consumed+1;
405 #endif
407 fp = fpnum_parse(_STRTOD_NAME_(strtod_scanf_get),
408 _STRTOD_NAME_(strtod_scanf_unget), &ctx, locinfo, FALSE);
409 fpnum_double(&fp, &cur);
410 if(!rd && ctx.err) {
411 _UNLOCK_FILE_(file);
412 return _EOF_RET;
414 if(ctx.err || !ctx.read)
415 break;
416 consumed += ctx.read;
417 #ifdef STRING
418 file = ctx.file;
419 #endif
420 nch = ctx.cur;
422 st = 1;
423 if (!suppress) {
424 if (L_prefix || l_prefix) _SET_NUMBER_(double);
425 else _SET_NUMBER_(float);
428 break;
429 /* According to msdn,
430 * 's' reads a character string in a call to fscanf
431 * and 'S' a wide character string and vice versa in a
432 * call to fwscanf. The 'h', 'w' and 'l' prefixes override
433 * this behaviour. 'h' forces reading char * but 'l' and 'w'
434 * force reading WCHAR. */
435 case 's':
436 if (w_prefix || l_prefix) goto widecharstring;
437 else if (h_prefix) goto charstring;
438 #ifdef WIDE_SCANF
439 else goto widecharstring;
440 #else /* WIDE_SCANF */
441 else goto charstring;
442 #endif /* WIDE_SCANF */
443 case 'S':
444 if (w_prefix || l_prefix) goto widecharstring;
445 else if (h_prefix) goto charstring;
446 #ifdef WIDE_SCANF
447 else goto charstring;
448 #else /* WIDE_SCANF */
449 else goto widecharstring;
450 #endif /* WIDE_SCANF */
451 charstring: { /* read a word into a char */
452 char *sptr = suppress ? NULL : va_arg(ap, char*);
453 char *sptr_beg = sptr;
454 #ifdef SECURE
455 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
456 #else
457 unsigned size = UINT_MAX;
458 #endif
459 /* skip initial whitespace */
460 while ((nch!=_EOF_) && _ISSPACE_(nch))
461 nch = _GETC_(file);
462 /* read until whitespace */
463 while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
464 if (!suppress) {
465 *sptr++ = _CHAR2SUPPORTED_(nch);
466 if(size>1) size--;
467 else {
468 _UNLOCK_FILE_(file);
469 *sptr_beg = 0;
470 return rd;
473 st++;
474 nch = _GETC_(file);
475 if (width>0) width--;
477 /* if we have reached the EOF and output nothing then report EOF */
478 if (nch==_EOF_ && rd==0 && st==0) {
479 _UNLOCK_FILE_(file);
480 return _EOF_RET;
482 /* terminate */
483 if (st && !suppress) *sptr = 0;
485 break;
486 widecharstring: { /* read a word into a wchar_t* */
487 MSVCRT_wchar_t *sptr = suppress ? NULL : va_arg(ap, MSVCRT_wchar_t*);
488 MSVCRT_wchar_t *sptr_beg = sptr;
489 #ifdef SECURE
490 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
491 #else
492 unsigned size = UINT_MAX;
493 #endif
494 /* skip initial whitespace */
495 while ((nch!=_EOF_) && _ISSPACE_(nch))
496 nch = _GETC_(file);
497 /* read until whitespace */
498 while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) {
499 if (!suppress) {
500 *sptr++ = _WIDE2SUPPORTED_(nch);
501 if(size>1) size--;
502 else {
503 _UNLOCK_FILE_(file);
504 *sptr_beg = 0;
505 return rd;
508 st++;
509 nch = _GETC_(file);
510 if (width>0) width--;
512 #if _MSVCR_VER >= 80
513 /* if we have reached the EOF and output nothing then report EOF */
514 if (nch==_EOF_ && rd==0 && st==0) {
515 _UNLOCK_FILE_(file);
516 return _EOF_RET;
518 #endif
519 /* terminate */
520 if (st && !suppress) *sptr = 0;
522 break;
523 /* 'c' and 'C work analogously to 's' and 'S' as described
524 * above */
525 case 'c':
526 if (w_prefix || l_prefix) goto widecharacter;
527 else if (h_prefix) goto character;
528 #ifdef WIDE_SCANF
529 else goto widecharacter;
530 #else /* WIDE_SCANF */
531 else goto character;
532 #endif /* WIDE_SCANF */
533 case 'C':
534 if (w_prefix || l_prefix) goto widecharacter;
535 else if (h_prefix) goto character;
536 #ifdef WIDE_SCANF
537 else goto character;
538 #else /* WIDE_SCANF */
539 else goto widecharacter;
540 #endif /* WIDE_SCANF */
541 character: { /* read single character into char */
542 char *str = suppress ? NULL : va_arg(ap, char*);
543 char *pstr = str;
544 #ifdef SECURE
545 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
546 #else
547 unsigned size = UINT_MAX;
548 #endif
549 if (width == -1) width = 1;
550 while (width && (nch != _EOF_))
552 if (!suppress) {
553 if(size) size--;
554 else {
555 _UNLOCK_FILE_(file);
556 *pstr = 0;
557 return rd;
559 *str++ = _CHAR2SUPPORTED_(nch);
561 st++;
562 width--;
563 nch = _GETC_(file);
566 break;
567 widecharacter: { /* read single character into a wchar_t */
568 MSVCRT_wchar_t *str = suppress ? NULL : va_arg(ap, MSVCRT_wchar_t*);
569 MSVCRT_wchar_t *pstr = str;
570 #ifdef SECURE
571 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
572 #else
573 unsigned size = UINT_MAX;
574 #endif
575 if (width == -1) width = 1;
576 while (width && (nch != _EOF_))
578 if (!suppress) {
579 if(size) size--;
580 else {
581 _UNLOCK_FILE_(file);
582 *pstr = 0;
583 return rd;
585 *str++ = _WIDE2SUPPORTED_(nch);
587 st++;
588 width--;
589 nch = _GETC_(file);
592 break;
593 case 'n': {
594 if (!suppress) {
595 int*n = va_arg(ap, int*);
596 *n = consumed - 1;
598 /* This is an odd one: according to the standard,
599 * "Execution of a %n directive does not increment the
600 * assignment count returned at the completion of
601 * execution" even if it wasn't suppressed with the
602 * '*' flag. The Corrigendum to the standard seems
603 * to contradict this (comment out the assignment to
604 * suppress below if you want to implement these
605 * alternate semantics) but the windows program I'm
606 * looking at expects the behavior I've coded here
607 * (which happens to be what glibc does as well).
609 suppress = 1;
610 st = 1;
612 break;
613 case '[': {
614 _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*);
615 _CHAR_ *sptr = str;
616 RTL_BITMAP bitMask;
617 ULONG *Mask;
618 int invert = 0; /* Set if we are NOT to find the chars */
619 #ifdef SECURE
620 unsigned size = suppress ? UINT_MAX : va_arg(ap, unsigned);
621 #else
622 unsigned size = UINT_MAX;
623 #endif
625 /* Init our bitmap */
626 Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8);
627 RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_);
629 /* Read the format */
630 format++;
631 if(*format == '^') {
632 invert = 1;
633 format++;
635 if(*format == ']') {
636 RtlSetBits(&bitMask, ']', 1);
637 format++;
639 while(*format && (*format != ']')) {
640 /* According to msdn:
641 * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */
642 if((*format == '-') && (*(format + 1) != ']')) {
643 if ((*(format - 1)) < *(format + 1))
644 RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1));
645 else
646 RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1));
647 format++;
648 } else
649 RtlSetBits(&bitMask, *format, 1);
650 format++;
652 /* read until char is not suitable */
653 while ((width != 0) && (nch != _EOF_)) {
654 if(!invert) {
655 if(RtlAreBitsSet(&bitMask, nch, 1)) {
656 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
657 } else
658 break;
659 } else {
660 if(RtlAreBitsClear(&bitMask, nch, 1)) {
661 if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch);
662 } else
663 break;
665 st++;
666 nch = _GETC_(file);
667 if (width>0) width--;
668 if(size>1) size--;
669 else {
670 _UNLOCK_FILE_(file);
671 *str = 0;
672 HeapFree(GetProcessHeap(), 0, Mask);
673 return rd;
676 /* terminate */
677 if (!suppress) *sptr = 0;
678 HeapFree(GetProcessHeap(), 0, Mask);
680 break;
681 default:
682 /* From spec: "if a percent sign is followed by a character
683 * that has no meaning as a format-control character, that
684 * character and the following characters are treated as
685 * an ordinary sequence of characters, that is, a sequence
686 * of characters that must match the input. For example,
687 * to specify that a percent-sign character is to be input,
688 * use %%." */
689 while ((nch!=_EOF_) && _ISSPACE_(nch))
690 nch = _GETC_(file);
691 if ((_CHAR_)nch == *format) {
692 suppress = 1; /* whoops no field to be read */
693 st = 1; /* but we got what we expected */
694 nch = _GETC_(file);
696 break;
698 if (st && !suppress) rd++;
699 else if (!st) break;
701 /* a non-white-space character causes scanf to read, but not store,
702 * a matching non-white-space character. */
703 else {
704 /* check for character match */
705 if ((_CHAR_)nch == *format) {
706 nch = _GETC_(file);
707 } else break;
709 format++;
711 if (nch!=_EOF_) {
712 _UNGETC_(nch, file);
715 TRACE("returning %d\n", rd);
716 _UNLOCK_FILE_(file);
717 return rd;
720 #undef _CHAR_
721 #undef _EOF_
722 #undef _EOF_RET
723 #undef _ISSPACE_
724 #undef _ISDIGIT_
725 #undef _CHAR2SUPPORTED_
726 #undef _WIDE2SUPPORTED_
727 #undef _CHAR2DIGIT_
728 #undef _GETC_FUNC_
729 #undef _STRTOD_NAME_
730 #undef _GETC_
731 #undef _UNGETC_
732 #undef _LOCK_FILE_
733 #undef _UNLOCK_FILE_
734 #undef _FUNCTION_
735 #undef _BITMAPSIZE_