1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/***
6*input.c - C formatted input, used by scanf, etc.
7*
8
9*
10*Purpose:
11* defines _input() to do formatted input; called from scanf(),
12* etc. functions. This module defines _cscanf() instead when
13* CPRFLAG is defined. The file cscanf.c defines that symbol
14* and then includes this file in order to implement _cscanf().
15*
16*Note:
17* this file is included in safecrt.lib build directly, plese refer
18* to safecrt_[w]input_s.c
19*
20*******************************************************************************/
21
22
23#define ALLOW_RANGE /* enable "%[a-z]"-style scansets */
24
25
26/* temporary work-around for compiler without 64-bit support */
27
28#ifndef _INTEGRAL_MAX_BITS
29#define _INTEGRAL_MAX_BITS 64
30#endif /* _INTEGRAL_MAX_BITS */
31
32// typedef __int64_t __int64;
33
34#ifndef FALSE
35#define FALSE 0
36#endif
37
38#ifndef TRUE
39#define TRUE 1
40#endif
41
42#define UNALIGNED
43
44#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
45#define _END_SECURE_CRT_DEPRECATION_DISABLE
46
47#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
48
49//#include <cruntime.h>
50//#include <stdio.h>
51//#include <ctype.h>
52//#include <cvt.h>
53//#include <conio.h>
54//#include <stdarg.h>
55//#include <string.h>
56//#include <internal.h>
57//#include <fltintrn.h>
58//#include <malloc.h>
59//#include <locale.h>
60//#include <mtdll.h>
61//#include <stdlib.h>
62//#include <setlocal.h>
63//#include <dbgint.h>
64
65//#ifndef _INC_INTERNAL_SAFECRT
66//#include <internal_securecrt.h>
67//#endif /* _INC_INTERNAL_SAFECRT */
68
69//#ifdef _MBCS
70//#undef _MBCS
71//#endif /* _MBCS */
72//#include <tchar.h>
73
74#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
75
76#define _istspace(x) isspace((unsigned char)x)
77
78#define _malloc_crt PAL_malloc
79#define _realloc_crt PAL_realloc
80#define _free_crt PAL_free
81
82#define _FASSIGN(flag, argument, number, dec_point, locale) _safecrt_fassign((flag), (argument), (number))
83#define _WFASSIGN(flag, argument, number, dec_point, locale) _safecrt_wfassign((flag), (argument), (number))
84
85#if defined (UNICODE)
86#define ALLOC_TABLE 1
87#else /* defined (UNICODE) */
88#define ALLOC_TABLE 0
89#endif /* defined (UNICODE) */
90
91#define HEXTODEC(chr) _hextodec(chr)
92
93#define LEFT_BRACKET ('[' | ('a' - 'A')) /* 'lowercase' version */
94
95static int __cdecl _hextodec(_TCHAR);
96#ifdef CPRFLAG
97
98#define INC() (++charcount, _inc())
99#define UN_INC(chr) (--charcount, _un_inc(chr))
100#define EAT_WHITE() _whiteout(&charcount)
101
102static int __cdecl _inc(void);
103static void __cdecl _un_inc(int);
104static int __cdecl _whiteout(int *);
105
106#else /* CPRFLAG */
107
108#define INC() (++charcount, _inc(stream))
109#define UN_INC(chr) (--charcount, _un_inc(chr, stream))
110#define EAT_WHITE() _whiteout(&charcount, stream)
111
112static int __cdecl _inc(miniFILE *);
113static void __cdecl _un_inc(int, miniFILE *);
114static int __cdecl _whiteout(int *, miniFILE *);
115
116#endif /* CPRFLAG */
117
118#ifndef _UNICODE
119#define _ISDIGIT(chr) isdigit((unsigned char)chr)
120#define _ISXDIGIT(chr) isxdigit((unsigned char)chr)
121#else /* _UNICODE */
122#define _ISDIGIT(chr) ( !(chr & 0xff00) && isdigit( ((chr) & 0x00ff) ) )
123#define _ISXDIGIT(chr) ( !(chr & 0xff00) && isxdigit( ((chr) & 0x00ff) ) )
124#endif /* _UNICODE */
125
126#define MUL10(x) ( (((x)<<2) + (x))<<1 )
127
128
129#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64
130 0 means long long is same as long */
131
132/***
133* int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*)
134*
135* Purpose:
136* Check if there is enough space insert onemore character in the given
137* block, if not then allocate more memory.
138*
139* Return:
140* FALSE if more memory needed and the reallocation failed.
141*
142*******************************************************************************/
143
144static int __check_float_string(size_t nFloatStrUsed,
145 size_t *pnFloatStrSz,
146 _TCHAR **pFloatStr,
147 _TCHAR *floatstring,
148 int *pmalloc_FloatStrFlag)
149{
150 void *tmpPointer;
151 _ASSERTE(nFloatStrUsed<=(*pnFloatStrSz));
152 if (nFloatStrUsed==(*pnFloatStrSz))
153 {
154 size_t newSize;
155
156 // Will (*pnFloatStrSz) * 2 * sizeof(_TCHAR) overflow?
157 if ( *pnFloatStrSz > (SIZE_T_MAX / 2 / sizeof(_TCHAR)))
158 {
159 return FALSE;
160 }
161
162 newSize = *pnFloatStrSz * 2 * sizeof(_TCHAR);
163
164 if ((*pFloatStr)==floatstring)
165 {
166 if (((*pFloatStr)=(_TCHAR *)_malloc_crt(newSize))==NULL)
167 {
168 return FALSE;
169 }
170
171 (*pmalloc_FloatStrFlag)=1;
172
173 memcpy((*pFloatStr),floatstring,(*pnFloatStrSz)*sizeof(_TCHAR));
174 (*pnFloatStrSz)*=2;
175 }
176 else
177 {
178 if ((tmpPointer=(_TCHAR *)_realloc_crt((*pFloatStr), newSize))==NULL)
179 {
180 return FALSE;
181 }
182 (*pFloatStr)=(_TCHAR *)(tmpPointer);
183 (*pnFloatStrSz)*=2;
184 }
185 }
186 return TRUE;
187}
188
189
190#define ASCII 32 /* # of bytes needed to hold 256 bits */
191
192#define SCAN_SHORT 0 /* also for FLOAT */
193#define SCAN_LONG 1 /* also for DOUBLE */
194#define SCAN_L_DOUBLE 2 /* only for LONG DOUBLE */
195
196#define SCAN_NEAR 0
197#define SCAN_FAR 1
198
199#ifndef _UNICODE
200#define TABLESIZE ASCII
201#else /* _UNICODE */
202#define TABLESIZE (ASCII * 256)
203#endif /* _UNICODE */
204
205
206/***
207*int _input(stream, format, arglist), static int input(format, arglist)
208*
209*Purpose:
210* get input items (data items or literal matches) from the input stream
211* and assign them if appropriate to the items thru the arglist. this
212* function is intended for internal library use only, not for the user
213*
214* The _input entry point is for the normal scanf() functions
215* The input entry point is used when compiling for _cscanf() [CPRFLAF
216* defined] and is a static function called only by _cscanf() -- reads from
217* console.
218*
219* This code also defines _input_s, which works differently for %c, %s & %[.
220* For these, _input_s first picks up the next argument from the variable
221* argument list & uses it as the maximum size of the character array pointed
222* to by the next argument in the list.
223*
224*Entry:
225* FILE *stream - file to read from
226* char *format - format string to determine the data to read
227* arglist - list of pointer to data items
228*
229*Exit:
230* returns number of items assigned and fills in data items
231* returns EOF if error or EOF found on stream before 1st data item matched
232*
233*Exceptions:
234*
235*******************************************************************************/
236
237 #define _INTRN_LOCALE_CONV( x ) localeconv()
238
239#ifndef _UNICODE
240 int __cdecl __tinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
241#else
242 int __cdecl __twinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
243#endif /* _UNICODE */
244{
245 _TCHAR floatstring[_CVTBUFSIZE + 1];
246 _TCHAR *pFloatStr=floatstring;
247 size_t nFloatStrUsed=0;
248 size_t nFloatStrSz=sizeof(floatstring)/sizeof(floatstring[0]);
249 int malloc_FloatStrFlag=0;
250
251 unsigned long number; /* temp hold-value */
252#if ALLOC_TABLE
253 char *table = NULL; /* which chars allowed for %[] */
254 int malloc_flag = 0; /* is "table" allocated on the heap? */
255#else /* ALLOC_TABLE */
256 char AsciiTable[TABLESIZE];
257 char *table = AsciiTable;
258#endif /* ALLOC_TABLE */
259
260#if _INTEGRAL_MAX_BITS >= 64
261 uint64_t num64 = 0LL; /* temp for 64-bit integers */
262#endif /* _INTEGRAL_MAX_BITS >= 64 */
263 void *pointer=NULL; /* points to user data receptacle */
264 void *start; /* indicate non-empty string */
265
266
267#ifndef _UNICODE
268 wchar_t wctemp=L'\0';
269#endif /* _UNICODE */
270 _TUCHAR *scanptr; /* for building "table" data */
271 int ch = 0;
272 int charcount; /* total number of chars read */
273 int comchr; /* holds designator type */
274 int count; /* return value. # of assignments */
275
276 int started; /* indicate good number */
277 int width; /* width of field */
278 int widthset; /* user has specified width */
279#ifdef _SECURE_SCANF
280 size_t array_width = 0;
281 size_t original_array_width = 0;
282 int enomem = 0;
283 int format_error = FALSE;
284#endif /* _SECURE_SCANF */
285
286/* Neither coerceshort nor farone are need for the 386 */
287
288
289 char done_flag; /* general purpose loop monitor */
290 char longone; /* 0 = SHORT, 1 = LONG, 2 = L_DOUBLE */
291#if _INTEGRAL_MAX_BITS >= 64
292 int integer64; /* 1 for 64-bit integer, 0 otherwise */
293#endif /* _INTEGRAL_MAX_BITS >= 64 */
294 signed char widechar; /* -1 = char, 0 = ????, 1 = wchar_t */
295 char reject; /* %[^ABC] instead of %[ABC] */
296 char negative; /* flag for '-' detected */
297 char suppress; /* don't assign anything */
298 char match; /* flag: !0 if any fields matched */
299 va_list arglistsave; /* save arglist value */
300
301 char fl_wchar_arg; /* flags wide char/string argument */
302
303 _TCHAR decimal;
304
305
306 _TUCHAR rngch;
307 _TUCHAR last;
308 _TUCHAR prevchar;
309 _TCHAR tch;
310
311 _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
312
313#ifndef CPRFLAG
314 _VALIDATE_RETURN( (stream != NULL), EINVAL, EOF);
315#endif /* CPRFLAG */
316
317 /*
318 count = # fields assigned
319 charcount = # chars read
320 match = flag indicating if any fields were matched
321
322 [Note that we need both count and match. For example, a field
323 may match a format but have assignments suppressed. In this case,
324 match will get set, but 'count' will still equal 0. We need to
325 distinguish 'match vs no-match' when terminating due to EOF.]
326 */
327
328 count = charcount = match = 0;
329
330 while (*format) {
331
332 if (_istspace((_TUCHAR)*format)) {
333
334 UN_INC(EAT_WHITE()); /* put first non-space char back */
335
336 do {
337 tch = *++format;
338 } while (_istspace((_TUCHAR)tch));
339
340 continue;
341
342 }
343
344 if (_T('%') == *format) {
345
346 number = 0;
347 prevchar = 0;
348 width = widthset = started = 0;
349#ifdef _SECURE_SCANF
350 original_array_width = array_width = 0;
351 enomem = 0;
352#endif /* _SECURE_SCANF */
353 fl_wchar_arg = done_flag = suppress = negative = reject = 0;
354 widechar = 0;
355
356 longone = 1;
357
358#if _INTEGRAL_MAX_BITS >= 64
359 integer64 = 0;
360#endif /* _INTEGRAL_MAX_BITS >= 64 */
361
362 while (!done_flag) {
363
364 comchr = *++format;
365 if (_ISDIGIT((_TUCHAR)comchr)) {
366 ++widthset;
367 width = MUL10(width) + (comchr - _T('0'));
368 } else
369 switch (comchr) {
370 case _T('F') :
371 case _T('N') : /* no way to push NEAR in large model */
372 break; /* NEAR is default in small model */
373 case _T('h') :
374 /* set longone to 0 */
375 --longone;
376 --widechar; /* set widechar = -1 */
377 break;
378
379#if _INTEGRAL_MAX_BITS >= 64
380 case _T('I'):
381 if ( (*(format + 1) == _T('6')) &&
382 (*(format + 2) == _T('4')) )
383 {
384 format += 2;
385 ++integer64;
386 num64 = 0;
387 break;
388 }
389 else if ( (*(format + 1) == _T('3')) &&
390 (*(format + 2) == _T('2')) )
391 {
392 format += 2;
393 break;
394 }
395 else if ( (*(format + 1) == _T('d')) ||
396 (*(format + 1) == _T('i')) ||
397 (*(format + 1) == _T('o')) ||
398 (*(format + 1) == _T('x')) ||
399 (*(format + 1) == _T('X')) )
400 {
401 if (sizeof(void*) == sizeof(__int64))
402 {
403 ++integer64;
404 num64 = 0;
405 }
406 break;
407 }
408 if (sizeof(void*) == sizeof(__int64))
409 {
410 ++integer64;
411 num64 = 0;
412 }
413 goto DEFAULT_LABEL;
414#endif /* _INTEGRAL_MAX_BITS >= 64 */
415
416 case _T('L') :
417 /* ++longone; */
418 ++longone;
419 break;
420
421 case _T('q'):
422 ++integer64;
423 num64 = 0;
424 break;
425
426 case _T('l') :
427 if (*(format + 1) == _T('l'))
428 {
429 ++format;
430#ifdef LONGLONG_IS_INT64
431 ++integer64;
432 num64 = 0;
433 break;
434#else /* LONGLONG_IS_INT64 */
435 ++longone;
436 /* NOBREAK */
437#endif /* LONGLONG_IS_INT64 */
438 }
439 else
440 {
441 ++longone;
442 /* NOBREAK */
443 }
444 case _T('w') :
445 ++widechar; /* set widechar = 1 */
446 break;
447
448 case _T('*') :
449 ++suppress;
450 break;
451
452 default:
453DEFAULT_LABEL:
454 ++done_flag;
455 break;
456 }
457 }
458
459 if (!suppress) {
460 va_copy(arglistsave, arglist);
461 pointer = va_arg(arglist,void *);
462 } else {
463 pointer = NULL; // doesn't matter what value we use here - we're only using it as a flag
464 }
465
466 done_flag = 0;
467
468 if (!widechar) { /* use case if not explicitly specified */
469 if ((*format == _T('S')) || (*format == _T('C')))
470#ifdef _UNICODE
471 --widechar;
472 else
473 ++widechar;
474#else /* _UNICODE */
475 ++widechar;
476 else
477 --widechar;
478#endif /* _UNICODE */
479 }
480
481 /* switch to lowercase to allow %E,%G, and to
482 keep the switch table small */
483
484 comchr = *format | (_T('a') - _T('A'));
485
486 if (_T('n') != comchr)
487 {
488 if (_T('c') != comchr && LEFT_BRACKET != comchr)
489 ch = EAT_WHITE();
490 else
491 ch = INC();
492 }
493
494 if (_T('n') != comchr)
495 {
496 if (_TEOF == ch)
497 goto error_return;
498 }
499
500 if (!widthset || width) {
501
502#ifdef _SECURE_SCANF
503 if(!suppress && (comchr == _T('c') || comchr == _T('s') || comchr == LEFT_BRACKET)) {
504
505 va_copy(arglist, arglistsave);
506
507 /* Reinitialize pointer to point to the array to which we write the input */
508 pointer = va_arg(arglist, void*);
509
510 va_copy(arglistsave, arglist);
511
512 /* Get the next argument - size of the array in characters */
513#ifdef _WIN64
514 original_array_width = array_width = (size_t)(va_arg(arglist, unsigned int));
515#else /* _WIN64 */
516 original_array_width = array_width = va_arg(arglist, size_t);
517#endif /* _WIN64 */
518
519 if(array_width < 1) {
520 if (widechar > 0)
521 *(wchar_t UNALIGNED *)pointer = L'\0';
522 else
523 *(char *)pointer = '\0';
524
525 errno = ENOMEM;
526
527 goto error_return;
528 }
529 }
530#endif /* _SECURE_SCANF */
531 switch(comchr) {
532
533 case _T('c'):
534 /* case _T('C'): */
535 if (!widthset) {
536 ++widthset;
537 ++width;
538 }
539 if (widechar > 0)
540 fl_wchar_arg++;
541 goto scanit;
542
543
544 case _T('s'):
545 /* case _T('S'): */
546 if(widechar > 0)
547 fl_wchar_arg++;
548 goto scanit;
549
550
551 case LEFT_BRACKET : /* scanset */
552 if (widechar>0)
553 fl_wchar_arg++;
554 scanptr = (_TUCHAR *)(++format);
555
556 if (_T('^') == *scanptr) {
557 ++scanptr;
558 --reject; /* set reject to 255 */
559 }
560
561 /* Allocate "table" on first %[] spec */
562#if ALLOC_TABLE
563 if (table == NULL) {
564 table = (char*)_malloc_crt(TABLESIZE);
565 if ( table == NULL)
566 goto error_return;
567 malloc_flag = 1;
568 }
569#endif /* ALLOC_TABLE */
570 memset(table, 0, TABLESIZE);
571
572
573 if (LEFT_BRACKET == comchr)
574 if (_T(']') == *scanptr) {
575 prevchar = _T(']');
576 ++scanptr;
577
578 table[ _T(']') >> 3] = 1 << (_T(']') & 7);
579
580 }
581
582 while (_T(']') != *scanptr) {
583
584 rngch = *scanptr++;
585
586 if (_T('-') != rngch ||
587 !prevchar || /* first char */
588 _T(']') == *scanptr) /* last char */
589
590 table[(prevchar = rngch) >> 3] |= 1 << (rngch & 7);
591
592 else { /* handle a-z type set */
593
594 rngch = *scanptr++; /* get end of range */
595
596 if (prevchar < rngch) /* %[a-z] */
597 last = rngch;
598 else { /* %[z-a] */
599 last = prevchar;
600 prevchar = rngch;
601 }
602 for (rngch = prevchar; rngch <= last; ++rngch)
603 table[rngch >> 3] |= 1 << (rngch & 7);
604
605 prevchar = 0;
606
607 }
608 }
609
610
611 if (!*scanptr)
612 goto error_return; /* trunc'd format string */
613
614 /* scanset completed. Now read string */
615
616 if (LEFT_BRACKET == comchr)
617 format = scanptr;
618
619scanit:
620 start = pointer;
621
622 /*
623 * execute the format directive. that is, scan input
624 * characters until the directive is fulfilled, eof
625 * is reached, or a non-matching character is
626 * encountered.
627 *
628 * it is important not to get the next character
629 * unless that character needs to be tested! other-
630 * wise, reads from line-buffered devices (e.g.,
631 * scanf()) would require an extra, spurious, newline
632 * if the first newline completes the current format
633 * directive.
634 */
635 UN_INC(ch);
636
637#ifdef _SECURE_SCANF
638 /* One element is needed for '\0' for %s & %[ */
639 if(comchr != _T('c')) {
640 --array_width;
641 }
642#endif /* _SECURE_SCANF */
643 while ( !widthset || width-- ) {
644
645 ch = INC();
646 if (
647#ifndef CPRFLAG
648 (_TEOF != ch) &&
649#endif /* CPRFLAG */
650 // char conditions
651 ( ( comchr == _T('c')) ||
652 // string conditions !isspace()
653 ( ( comchr == _T('s') &&
654 (!(ch >= _T('\t') && ch <= _T('\r')) &&
655 ch != _T(' ')))) ||
656 // BRACKET conditions
657 ( (comchr == LEFT_BRACKET) &&
658 ((table[ch >> 3] ^ reject) & (1 << (ch & 7)))
659 )
660 )
661 )
662 {
663 if (!suppress) {
664#ifdef _SECURE_SCANF
665 if(!array_width) {
666 /* We have exhausted the user's buffer */
667
668 enomem = 1;
669 break;
670 }
671#endif /* _SECURE_SCANF */
672#ifndef _UNICODE
673 if (fl_wchar_arg) {
674 wctemp = W('?');
675 char temp[2];
676 temp[0] = (char) ch;
677#if 0 // we are not supporting multibyte input strings
678 if (isleadbyte((unsigned char)ch))
679 {
680 temp[1] = (char) INC();
681 }
682#endif /* 0 */
683 _MBTOWC(&wctemp, temp, MB_CUR_MAX);
684 *(wchar_t UNALIGNED *)pointer = wctemp;
685 /* just copy W('?') if mbtowc fails, errno is set by mbtowc */
686 pointer = (wchar_t *)pointer + 1;
687#ifdef _SECURE_SCANF
688 --array_width;
689#endif /* _SECURE_SCANF */
690 } else
691#else /* _UNICODE */
692 if (fl_wchar_arg) {
693 *(wchar_t UNALIGNED *)pointer = ch;
694 pointer = (wchar_t *)pointer + 1;
695#ifdef _SECURE_SCANF
696 --array_width;
697#endif /* _SECURE_SCANF */
698 } else
699#endif /* _UNICODE */
700 {
701#ifndef _UNICODE
702 *(char *)pointer = (char)ch;
703 pointer = (char *)pointer + 1;
704#ifdef _SECURE_SCANF
705 --array_width;
706#endif /* _SECURE_SCANF */
707#else /* _UNICODE */
708 int temp = 0;
709#ifndef _SECURE_SCANF
710 /* convert wide to multibyte */
711 if (_ERRCHECK_EINVAL_ERANGE(wctomb_s(&temp, (char *)pointer, MB_LEN_MAX, ch)) == 0)
712 {
713 /* do nothing if wctomb fails, errno will be set to EILSEQ */
714 pointer = (char *)pointer + temp;
715 }
716#else /* _SECURE_SCANF */
717 /* convert wide to multibyte */
718 if (array_width >= ((size_t)MB_CUR_MAX))
719 {
720_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
721 temp = wctomb((char *)pointer, ch);
722_END_SECURE_CRT_DEPRECATION_DISABLE
723 }
724 else
725 {
726 char tmpbuf[MB_LEN_MAX];
727_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
728 temp = wctomb(tmpbuf, ch);
729_END_SECURE_CRT_DEPRECATION_DISABLE
730 if (temp > 0 && ((size_t)temp) > array_width)
731 {
732 /* We have exhausted the user's buffer */
733 enomem = 1;
734 break;
735 }
736 memcpy(pointer, tmpbuf, temp);
737 }
738 if (temp > 0)
739 {
740 /* do nothing if wctomb fails, errno will be set to EILSEQ */
741 pointer = (char *)pointer + temp;
742 array_width -= temp;
743 }
744#endif /* _SECURE_SCANF */
745#endif /* _UNICODE */
746 }
747 } /* suppress */
748 else {
749 /* just indicate a match */
750 start = (_TCHAR *)start + 1;
751 }
752 }
753 else {
754 UN_INC(ch);
755 break;
756 }
757 }
758
759 /* make sure something has been matched and, if
760 assignment is not suppressed, null-terminate
761 output string if comchr != c */
762
763#ifdef _SECURE_SCANF
764 if(enomem) {
765 errno = ENOMEM;
766 /* In case of error, blank out the input buffer */
767 if (fl_wchar_arg)
768 {
769 _RESET_STRING(((wchar_t UNALIGNED *)start), original_array_width);
770 }
771 else
772 {
773 _RESET_STRING(((char *)start), original_array_width);
774 }
775
776 goto error_return;
777 }
778#endif /* _SECURE_SCANF */
779
780 if (start != pointer) {
781 if (!suppress) {
782 ++count;
783 if ('c' != comchr) /* null-terminate strings */
784 {
785 if (fl_wchar_arg)
786 {
787 *(wchar_t UNALIGNED *)pointer = L'\0';
788#ifdef _SECURE_SCANF
789 _FILL_STRING(((wchar_t UNALIGNED *)start), original_array_width,
790 ((wchar_t UNALIGNED *)pointer - (wchar_t UNALIGNED *)start + 1))
791#endif /* _SECURE_SCANF */
792 }
793 else
794 {
795 *(char *)pointer = '\0';
796#ifdef _SECURE_SCANF
797 _FILL_STRING(((char *)start), original_array_width,
798 ((char *)pointer - (char *)start + 1))
799#endif /* _SECURE_SCANF */
800 }
801 }
802 }
803 else
804 {
805 // supress set, do nothing
806 }
807 }
808 else
809 goto error_return;
810
811 break;
812
813 case _T('i') : /* could be d, o, or x */
814
815 comchr = _T('d'); /* use as default */
816
817 case _T('x'):
818
819 if (_T('-') == ch) {
820 ++negative;
821
822 goto x_incwidth;
823
824 } else if (_T('+') == ch) {
825x_incwidth:
826 if (!--width && widthset)
827 ++done_flag;
828 else
829 ch = INC();
830 }
831
832 if (_T('0') == ch) {
833
834 if (_T('x') == (_TCHAR)(ch = INC()) || _T('X') == (_TCHAR)ch) {
835 ch = INC();
836 if (widthset) {
837 width -= 2;
838 if (width < 1)
839 ++done_flag;
840 }
841 comchr = _T('x');
842 } else {
843 ++started;
844 if (_T('x') != comchr) {
845 if (widthset && !--width)
846 ++done_flag;
847 comchr = _T('o');
848 }
849 else {
850 /* scanning a hex number that starts */
851 /* with a 0. push back the character */
852 /* currently in ch and restore the 0 */
853 UN_INC(ch);
854 ch = _T('0');
855 }
856 }
857 }
858 goto getnum;
859
860 /* NOTREACHED */
861
862 case _T('p') :
863 /* force %hp to be treated as %p */
864 longone = 1;
865#ifdef _WIN64
866 /* force %p to be 64 bit in WIN64 */
867 ++integer64;
868 num64 = 0;
869#endif /* _WIN64 */
870 case _T('o') :
871 case _T('u') :
872 case _T('d') :
873
874 if (_T('-') == ch) {
875 ++negative;
876
877 goto d_incwidth;
878
879 } else if (_T('+') == ch) {
880d_incwidth:
881 if (!--width && widthset)
882 ++done_flag;
883 else
884 ch = INC();
885 }
886
887getnum:
888#if _INTEGRAL_MAX_BITS >= 64
889 if ( integer64 ) {
890
891 while (!done_flag) {
892
893 if (_T('x') == comchr || _T('p') == comchr)
894
895 if (_ISXDIGIT(ch)) {
896 num64 <<= 4;
897 ch = _hextodec(ch);
898 }
899 else
900 ++done_flag;
901
902 else if (_ISDIGIT(ch))
903
904 if (_T('o') == comchr)
905 if (_T('8') > ch)
906 num64 <<= 3;
907 else {
908 ++done_flag;
909 }
910 else /* _T('d') == comchr */
911 num64 = MUL10(num64);
912
913 else
914 ++done_flag;
915
916 if (!done_flag) {
917 ++started;
918 num64 += ch - _T('0');
919
920 if (widthset && !--width)
921 ++done_flag;
922 else
923 ch = INC();
924 } else
925 UN_INC(ch);
926
927 } /* end of WHILE loop */
928
929 if (negative)
930 num64 = (uint64_t )(-(__int64)num64);
931 }
932 else {
933#endif /* _INTEGRAL_MAX_BITS >= 64 */
934 while (!done_flag) {
935
936 if (_T('x') == comchr || _T('p') == comchr)
937
938 if (_ISXDIGIT(ch)) {
939 number = (number << 4);
940 ch = _hextodec(ch);
941 }
942 else
943 ++done_flag;
944
945 else if (_ISDIGIT(ch))
946
947 if (_T('o') == comchr)
948 if (_T('8') > ch)
949 number = (number << 3);
950 else {
951 ++done_flag;
952 }
953 else /* _T('d') == comchr */
954 number = MUL10(number);
955
956 else
957 ++done_flag;
958
959 if (!done_flag) {
960 ++started;
961 number += ch - _T('0');
962
963 if (widthset && !--width)
964 ++done_flag;
965 else
966 ch = INC();
967 } else
968 UN_INC(ch);
969
970 } /* end of WHILE loop */
971
972 if (negative)
973 number = (unsigned long)(-(long)number);
974#if _INTEGRAL_MAX_BITS >= 64
975 }
976#endif /* _INTEGRAL_MAX_BITS >= 64 */
977 if (_T('F')==comchr) /* expected ':' in long pointer */
978 started = 0;
979
980 if (started)
981 if (!suppress) {
982
983 ++count;
984assign_num:
985#if _INTEGRAL_MAX_BITS >= 64
986 if ( integer64 )
987 *(__int64 UNALIGNED *)pointer = ( uint64_t )num64;
988 else
989#endif /* _INTEGRAL_MAX_BITS >= 64 */
990 if (longone)
991 *(int UNALIGNED *)pointer = (unsigned int)number;
992 else
993 *(short UNALIGNED *)pointer = (unsigned short)number;
994
995 } else /*NULL*/;
996 else
997 goto error_return;
998
999 break;
1000
1001 case _T('n') : /* char count, don't inc return value */
1002 number = charcount;
1003 if(!suppress)
1004 goto assign_num; /* found in number code above */
1005 break;
1006
1007
1008 case _T('e') :
1009 /* case _T('E') : */
1010 case _T('f') :
1011 case _T('g') : /* scan a float */
1012 /* case _T('G') : */
1013 nFloatStrUsed=0;
1014
1015 if (_T('-') == ch) {
1016 pFloatStr[nFloatStrUsed++] = _T('-');
1017 goto f_incwidth;
1018
1019 } else if (_T('+') == ch) {
1020f_incwidth:
1021 --width;
1022 ch = INC();
1023 }
1024
1025 if (!widthset) /* must watch width */
1026 width = -1;
1027
1028
1029 /* now get integral part */
1030
1031 while (_ISDIGIT(ch) && width--) {
1032 ++started;
1033 pFloatStr[nFloatStrUsed++] = (char)ch;
1034 if (__check_float_string(nFloatStrUsed,
1035 &nFloatStrSz,
1036 &pFloatStr,
1037 floatstring,
1038 &malloc_FloatStrFlag
1039 )==FALSE) {
1040 goto error_return;
1041 }
1042 ch = INC();
1043 }
1044
1045#ifdef _UNICODE
1046 /* convert decimal point to wide-char */
1047 /* if mbtowc fails (should never happen), we use L'.' */
1048 decimal = L'.';
1049 _MBTOWC(&decimal, _INTRN_LOCALE_CONV(_loc_update)->decimal_point, MB_CUR_MAX);
1050#else /* _UNICODE */
1051
1052 decimal=*((_INTRN_LOCALE_CONV(_loc_update))->decimal_point);
1053#endif /* _UNICODE */
1054
1055 /* now check for decimal */
1056 if (decimal == (char)ch && width--) {
1057 ch = INC();
1058 pFloatStr[nFloatStrUsed++] = decimal;
1059 if (__check_float_string(nFloatStrUsed,
1060 &nFloatStrSz,
1061 &pFloatStr,
1062 floatstring,
1063 &malloc_FloatStrFlag
1064 )==FALSE) {
1065 goto error_return;
1066 }
1067
1068 while (_ISDIGIT(ch) && width--) {
1069 ++started;
1070 pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
1071 if (__check_float_string(nFloatStrUsed,
1072 &nFloatStrSz,
1073 &pFloatStr,
1074 floatstring,
1075 &malloc_FloatStrFlag
1076 )==FALSE) {
1077 goto error_return;
1078 }
1079 ch = INC();
1080 }
1081 }
1082
1083 /* now check for exponent */
1084
1085 if (started && (_T('e') == ch || _T('E') == ch) && width--) {
1086 pFloatStr[nFloatStrUsed++] = _T('e');
1087 if (__check_float_string(nFloatStrUsed,
1088 &nFloatStrSz,
1089 &pFloatStr,
1090 floatstring,
1091 &malloc_FloatStrFlag
1092 )==FALSE) {
1093 goto error_return;
1094 }
1095
1096 if (_T('-') == (ch = INC())) {
1097
1098 pFloatStr[nFloatStrUsed++] = _T('-');
1099 if (__check_float_string(nFloatStrUsed,
1100 &nFloatStrSz,
1101 &pFloatStr,
1102 floatstring,
1103 &malloc_FloatStrFlag
1104 )==FALSE) {
1105 goto error_return;
1106 }
1107 goto f_incwidth2;
1108
1109 } else if (_T('+') == ch) {
1110f_incwidth2:
1111 if (!width--)
1112 ++width;
1113 else
1114 ch = INC();
1115 }
1116
1117
1118 while (_ISDIGIT(ch) && width--) {
1119 ++started;
1120 pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
1121 if (__check_float_string(nFloatStrUsed,
1122 &nFloatStrSz,
1123 &pFloatStr,
1124 floatstring,
1125 &malloc_FloatStrFlag
1126 )==FALSE) {
1127 goto error_return;
1128 }
1129 ch = INC();
1130 }
1131
1132 }
1133
1134 UN_INC(ch);
1135
1136 if (started)
1137 if (!suppress) {
1138 ++count;
1139 pFloatStr[nFloatStrUsed]= _T('\0');
1140#ifdef _UNICODE
1141 _WFASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
1142#else /* _UNICODE */
1143 _FASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
1144#endif /* _UNICODE */
1145 } else /*NULL */;
1146 else
1147 goto error_return;
1148
1149 break;
1150
1151
1152 default: /* either found '%' or something else */
1153
1154 if ((int)*format != (int)ch) {
1155 UN_INC(ch);
1156#ifdef _SECURE_SCANF
1157 /* error_return ASSERT's if format_error is true */
1158 format_error = TRUE;
1159#endif /* _SECURE_SCANF */
1160 goto error_return;
1161 }
1162 else
1163 match--; /* % found, compensate for inc below */
1164
1165 if (!suppress)
1166 va_copy(arglist, arglistsave);
1167
1168 } /* SWITCH */
1169
1170 match++; /* matched a format field - set flag */
1171
1172 } /* WHILE (width) */
1173
1174 else { /* zero-width field in format string */
1175 UN_INC(ch); /* check for input error */
1176 goto error_return;
1177 }
1178
1179 ++format; /* skip to next char */
1180
1181 } else /* ('%' != *format) */
1182 {
1183
1184 if ((int)*format++ != (int)(ch = INC()))
1185 {
1186 UN_INC(ch);
1187 goto error_return;
1188 }
1189#if 0 // we are not supporting multibyte input strings
1190#ifndef _UNICODE
1191 if (isleadbyte((unsigned char)ch))
1192 {
1193 int ch2;
1194 if ((int)*format++ != (ch2=INC()))
1195 {
1196 UN_INC(ch2);
1197 UN_INC(ch);
1198 goto error_return;
1199 }
1200
1201 --charcount; /* only count as one character read */
1202 }
1203#endif /* _UNICODE */
1204#endif
1205 }
1206
1207#ifndef CPRFLAG
1208 if ( (_TEOF == ch) && ((*format != _T('%')) || (*(format + 1) != _T('n'))) )
1209 break;
1210#endif /* CPRFLAG */
1211
1212 } /* WHILE (*format) */
1213
1214error_return:
1215#if ALLOC_TABLE
1216 if (malloc_flag == 1)
1217 {
1218 _free_crt(table);
1219 }
1220#endif /* ALLOC_TABLE */
1221 if (malloc_FloatStrFlag == 1)
1222 {
1223 _free_crt(pFloatStr);
1224 }
1225
1226#ifndef CPRFLAG
1227 if (_TEOF == ch)
1228 /* If any fields were matched or assigned, return count */
1229 return ( (count || match) ? count : EOF);
1230 else
1231#endif /* CPRFLAG */
1232#ifdef _SECURE_SCANF
1233 if(format_error == TRUE) {
1234 _VALIDATE_RETURN( ("Invalid Input Format" && 0), EINVAL, count);
1235 }
1236#endif /* _SECURE_SCANF */
1237 return count;
1238
1239}
1240
1241/* _hextodec() returns a value of 0-15 and expects a char 0-9, a-f, A-F */
1242/* _inc() is the one place where we put the actual getc code. */
1243/* _whiteout() returns the first non-blank character, as defined by isspace() */
1244
1245static int __cdecl _hextodec ( _TCHAR chr)
1246{
1247 return _ISDIGIT(chr) ? chr : (chr & ~(_T('a') - _T('A'))) - _T('A') + 10 + _T('0');
1248}
1249
1250#ifdef CPRFLAG
1251
1252static int __cdecl _inc(void)
1253{
1254 return (_gettche_nolock());
1255}
1256
1257static void __cdecl _un_inc(int chr)
1258{
1259 if (_TEOF != chr) {
1260 _ungettch_nolock(chr);
1261 }
1262}
1263
1264static int __cdecl _whiteout(REG1 int* counter)
1265{
1266 REG2 int ch;
1267
1268 do
1269 {
1270 ++*counter;
1271 ch = _inc();
1272
1273 if (ch == _TEOF)
1274 {
1275 break;
1276 }
1277 }
1278 while(_istspace((_TUCHAR)ch));
1279 return ch;
1280}
1281
1282#else /* CPRFLAG */
1283
1284static int __cdecl _inc(miniFILE* fileptr)
1285{
1286 return (_gettc_nolock(fileptr));
1287}
1288
1289static void __cdecl _un_inc(int chr, miniFILE* fileptr)
1290{
1291 if (_TEOF != chr) {
1292 _ungettc_nolock(chr,fileptr);
1293 }
1294}
1295
1296static int __cdecl _whiteout(int* counter, miniFILE* fileptr)
1297{
1298 int ch;
1299
1300 do
1301 {
1302 ++*counter;
1303 ch = _inc(fileptr);
1304
1305 if (ch == _TEOF)
1306 {
1307 break;
1308 }
1309 }
1310 while(_istspace((_TUCHAR)ch));
1311 return ch;
1312}
1313
1314#endif /* CPRFLAG */
1315