Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1374 lines
46 KiB

  1. /***
  2. *input.c - C formatted input, used by scanf, etc.
  3. *
  4. * Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _input() to do formatted input; called from scanf(),
  8. * etc. functions. This module defines _cscanf() instead when
  9. * CPRFLAG is defined. The file cscanf.c defines that symbol
  10. * and then includes this file in order to implement _cscanf().
  11. *
  12. *Revision History:
  13. * 09-26-83 RN author
  14. * 11-01-85 TC added %F? %N? %?p %n %i
  15. * 11-20-86 SKS enlarged "table" to 256 bytes, to support chars > 0x7F
  16. * 12-12-86 SKS changed "s_in()" to pushback whitespace or other delimiter
  17. * 03-24-87 BCM Evaluation Issues:
  18. * SDS - needs #ifdef SS_NE_DS for the "number" buffer
  19. * (for S/M models only)
  20. * GD/TS : (not evaluated)
  21. * other INIT : (not evaluated)
  22. * needs _cfltcvt_init to have been called if
  23. * floating-point i/o conversions are being done
  24. * TERM - nothing
  25. * 06-25-87 PHG added check_stack pragma
  26. * 08-31-87 JCR Made %n conform to ANSI standard: (1) %n is supposed to
  27. * return the # of chars read so far by the current scanf(),
  28. * NOT the total read on the stream since open; (2) %n is NOT
  29. * supposed to affect the # of items read that is returned by
  30. * scanf().
  31. * 09-24-87 JCR Made cscanf() use the va_ macros (fixes cl warnings).
  32. * 11-04-87 JCR Multi-thread support
  33. * 11-16-87 JCR Cscanf() now gets _CONIO_LOCK
  34. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  35. * 02-25-88 JCR If burn() char hits EOF, only return EOF if count==0.
  36. * 05-31-88 WAJ Now suports %Fs and %Ns
  37. * 06-01-88 PHG Merged DLL and normal versions
  38. * 06-08-88 SJM %D no longer means %ld. %[]ABC], %[^]ABC] work.
  39. * 06-14-88 SJM Fixed %p, and %F? and %N? code.
  40. * SJM Complete re-write of input/_input for 6.00
  41. * 09-15-88 JCR If we match a field but it's not assigned, then are
  42. * terminated by EOF, we must return 0 not EOF (ANSI).
  43. * 09-25-88 GJF Initial adaption for the 386
  44. * 10-04-88 JCR 386: Removed 'far' keyword
  45. * 11-30-88 GJF Cleanup, now specific to 386
  46. * 06-09-89 GJF Propagated fixes of 03-06-89 and 04-05-89
  47. * 11-20-89 GJF Added const attribute to type of format. Also, fixed
  48. * copyright.
  49. * 12-21-89 GJF Allow null character in scanset
  50. * 02-14-90 KRS Fix suppressed-assignment pattern matching.
  51. * 03-20-90 GJF Made _cscanf() _CALLTYPE2 and _input() _CALLTYPE1. Added
  52. * #include <cruntime.h> and #include <register.h>.
  53. * 03-26-90 GJF Made static functions _CALLTYPE4. Placed prototype for
  54. * _input() in internal.h and #include-d it. Changed type of
  55. * arglist from void ** to va_list (to get rid of annoying
  56. * warnings). Added #include <string.h>. Elaborated prototypes
  57. * of static functions to get rid of compiler warnings.
  58. * 05-21-90 GJF Fixed stack checking pragma syntax.
  59. * 07-23-90 SBM Compiles cleanly with -W3, replaced <assertm.h> by
  60. * <assert.h>, moved _cfltcvt_tab to new header
  61. * <fltintrn.h>, formerly named <struct.h>
  62. * 08-13-90 SBM Compiles cleanly with -W3 with new build of compiler
  63. * 08-27-90 SBM Minor cleanup to agree with CRT7 version
  64. * 10-02-90 GJF New-style function declarators. Also, rewrote expr. to
  65. * avoid using casts as lvalues.
  66. * 10-22-90 GJF Added arglistsave, used to save and restore arglist pointer
  67. * without using pointer arithmetic.
  68. * 12-28-90 SRW Added _CRUISER_ conditional around check_stack pragma
  69. * 01-16-91 GJF ANSI naming.
  70. * 03-14-91 GJF Fix to allow processing of %n, even at eof. Fix devised by
  71. * DanK of PSS.
  72. * 06-19-91 GJF Fixed execution of string, character and scan-set format
  73. * directives to avoid problem with line-buffered devices
  74. * (C700 bug 1441).
  75. * 10-22-91 ETC Int'l dec point; Under _INTL: wchar_t/mb support; fix bug
  76. * under !ALLOW_RANGE (never compiled).
  77. * 11-15-91 ETC Fixed bug with %f %lf %Lf (bad handling of longone).
  78. * 11-19-91 ETC Added support for _wsscanf with WPRFLAG; added %tc %ts.
  79. * 06-09-92 KRS Rip out %tc/%ts; conform to new ISO spec.
  80. * 08-17-92 KRS Further ISO changes: Add %lc/%ls/%hc/%hs/%C/%S.
  81. * 12-23-92 SKS Needed to handle %*n (suppressed storage of byte count)
  82. * 02-16-93 CFW Added wide character output for [] scanset.
  83. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  84. * 04-26-93 CFW Wide char enable.
  85. * 08-17-93 CFW Avoid mapping tchar macros incorrectly if _MBCS defined.
  86. * 09-15-93 CFW Use ANSI conformant "__" names.
  87. * 11-08-93 GJF Merged in NT SDK version (use __unaligned pointer
  88. * casts on MIPS and Alpha. Also, fixed #elif WPRFLAG to
  89. * be #elif defined(WPRFLAG), and removed old CRUISER
  90. * support.
  91. * 12-16-93 CFW Get rid of spurious compiler warnings.
  92. * 03-15-94 GJF Added support for I64 size modifier.
  93. * 04-21-94 GJF Must reinitialize integer64 flag.
  94. * 09-05-94 SKS Remove include of obsolete 16-bit file <sizeptr.h>
  95. * 12-14-94 GJF Changed test for (hex) digits so that when WPRFLAG is
  96. * defined, only zero-extended (hex) digits are
  97. * recognized. This way, the familar arithmetic to convert
  98. * from character rep. to binary integer value will work.
  99. * 01-10-95 CFW Debug CRT allocs.
  100. * 02-06-94 CFW assert -> _ASSERTE.
  101. * 02-22-95 GJF Appended Mac version of source file (somewhat cleaned
  102. * up), with appropriate #ifdef-s. Also, replaced
  103. * WPRFLAG with _UNICODE.
  104. * 08-01-96 RDK For PMac, added __int64 support for _input.
  105. * 02-27-98 RKP Added 64 bit support.
  106. * 07-07-98 RKP Corrected %P formatting for 64 bit.
  107. * 09-21-98 GJF Added support for %I and %I32 modifiers.
  108. * 05-17-99 PML Remove all Macintosh support.
  109. * 10-28-99 PML vs7#10705 Win64 %p was totally busted
  110. * 04-25-00 GB Adding support for _cwprintf.
  111. * 05-31-00 GB Changed scanf to match with standards. problem was
  112. * reading octal or hexa while %d was specified.
  113. * 10-20-00 GB Changed input not to use %[] case for %c and %s.
  114. * 02-19-01 GB Added check for return value of malloc.
  115. * 03-13-01 PML Fix heap leak on multiple %[] specs (vs7#224990)
  116. * 07-07-01 BWT Fix prefix bug - init pointer to a known value
  117. * when handling * formatting.
  118. *
  119. *******************************************************************************/
  120. #define ALLOW_RANGE /* allow "%[a-z]"-style scansets */
  121. /* temporary work-around for compiler without 64-bit support */
  122. #ifndef _INTEGRAL_MAX_BITS
  123. #define _INTEGRAL_MAX_BITS 64
  124. #endif
  125. #include <cruntime.h>
  126. #include <stdio.h>
  127. #include <ctype.h>
  128. #include <cvt.h>
  129. #include <conio.h>
  130. #include <stdarg.h>
  131. #include <string.h>
  132. #include <internal.h>
  133. #include <fltintrn.h>
  134. #include <malloc.h>
  135. #include <mtdll.h>
  136. #include <stdlib.h>
  137. #include <nlsint.h>
  138. #include <dbgint.h>
  139. #ifdef _MBCS /* always want either Unicode or SBCS for tchar.h */
  140. #undef _MBCS
  141. #endif
  142. #include <tchar.h>
  143. #if defined(_NTSUBSET_) || defined(_POSIX_)
  144. #if defined (UNICODE)
  145. #define malloc_crt(x) RtlAllocateHeap(RtlProcessHeap(), 0, x)
  146. #define free_crt(x) RtlFreeHeap(RtlProcessHeap(), 0, x)
  147. #define ALLOC_TABLE 1
  148. #else
  149. #define ALLOC_TABLE 0
  150. #endif
  151. #else
  152. #define ALLOC_TABLE 1
  153. #endif
  154. #define HEXTODEC(chr) _hextodec(chr)
  155. #define LEFT_BRACKET ('[' | ('a' - 'A')) /* 'lowercase' version */
  156. #ifdef _UNICODE
  157. static wchar_t __cdecl _hextodec(wchar_t);
  158. #else
  159. static int __cdecl _hextodec(int);
  160. #endif /* _UNICODE */
  161. #ifdef CPRFLAG
  162. #define INC() (++charcount, _inc())
  163. #define UN_INC(chr) (--charcount, _un_inc(chr))
  164. #define EAT_WHITE() _whiteout(&charcount)
  165. #ifndef _UNICODE
  166. static int __cdecl _inc(void);
  167. static void __cdecl _un_inc(int);
  168. static int __cdecl _whiteout(int *);
  169. #else /* _UNICODE */
  170. static wchar_t __cdecl _inc(void);
  171. static void __cdecl _un_inc(wchar_t);
  172. static wchar_t __cdecl _whiteout(int *);
  173. #endif /* _UNICODE */
  174. #else /* CPRFLAG */
  175. #define INC() (++charcount, _inc(stream))
  176. #define UN_INC(chr) (--charcount, _un_inc(chr, stream))
  177. #define EAT_WHITE() _whiteout(&charcount, stream)
  178. #ifndef _UNICODE
  179. static int __cdecl _inc(FILE *);
  180. static void __cdecl _un_inc(int, FILE *);
  181. static int __cdecl _whiteout(int *, FILE *);
  182. #else /* _UNICODE */
  183. static wchar_t __cdecl _inc(FILE *);
  184. static void __cdecl _un_inc(wchar_t, FILE *);
  185. static wchar_t __cdecl _whiteout(int *, FILE *);
  186. #endif /* _UNICODE */
  187. #endif /* CPRFLAG */
  188. #ifndef _UNICODE
  189. #define _ISDIGIT(chr) isdigit(chr)
  190. #define _ISXDIGIT(chr) isxdigit(chr)
  191. #else
  192. #define _ISDIGIT(chr) ( !(chr & 0xff00) && isdigit( chr & 0x00ff ) )
  193. #define _ISXDIGIT(chr) ( !(chr & 0xff00) && isxdigit( chr & 0x00ff ) )
  194. #endif
  195. #ifdef CPRFLAG
  196. #ifndef _UNICODE
  197. static int __cdecl input(const unsigned char *, va_list);
  198. #else
  199. static int __cdecl input(const wchar_t *, va_list);
  200. #endif
  201. /***
  202. *int _cscanf(format, arglist) - read formatted input direct from console
  203. *
  204. *Purpose:
  205. * Reads formatted data like scanf, but uses console I/O functions.
  206. *
  207. *Entry:
  208. * char *format - format string to determine data formats
  209. * arglist - list of POINTERS to where to put data
  210. *
  211. *Exit:
  212. * returns number of successfully matched data items (from input)
  213. *
  214. *Exceptions:
  215. *
  216. *******************************************************************************/
  217. #ifndef _UNICODE
  218. int __cdecl _cscanf (
  219. const char *format,
  220. #else /* _UNICODE */
  221. int __cdecl _cwscanf (
  222. const wchar_t *format,
  223. #endif /* _UNICODE */
  224. ...
  225. )
  226. {
  227. va_list arglist;
  228. va_start(arglist, format);
  229. _ASSERTE(format != NULL);
  230. return input(format,arglist); /* get the input */
  231. }
  232. #endif /* CPRFLAG */
  233. #define ASCII 32 /* # of bytes needed to hold 256 bits */
  234. #define SCAN_SHORT 0 /* also for FLOAT */
  235. #define SCAN_LONG 1 /* also for DOUBLE */
  236. #define SCAN_L_DOUBLE 2 /* only for LONG DOUBLE */
  237. #define SCAN_NEAR 0
  238. #define SCAN_FAR 1
  239. #ifndef _UNICODE
  240. #define TABLESIZE ASCII
  241. #else
  242. #define TABLESIZE (ASCII * 256)
  243. #endif
  244. /***
  245. *int _input(stream, format, arglist), static int input(format, arglist)
  246. *
  247. *Purpose:
  248. * get input items (data items or literal matches) from the input stream
  249. * and assign them if appropriate to the items thru the arglist. this
  250. * function is intended for internal library use only, not for the user
  251. *
  252. * The _input entry point is for the normal scanf() functions
  253. * The input entry point is used when compiling for _cscanf() [CPRFLAF
  254. * defined] and is a static function called only by _cscanf() -- reads from
  255. * console.
  256. *
  257. *Entry:
  258. * FILE *stream - file to read from
  259. * char *format - format string to determine the data to read
  260. * arglist - list of pointer to data items
  261. *
  262. *Exit:
  263. * returns number of items assigned and fills in data items
  264. * returns EOF if error or EOF found on stream before 1st data item matched
  265. *
  266. *Exceptions:
  267. *
  268. *******************************************************************************/
  269. #ifdef CPRFLAG
  270. #ifndef _UNICODE
  271. static int __cdecl input (
  272. const unsigned char *format,
  273. va_list arglist
  274. )
  275. #else
  276. static int __cdecl input (
  277. const wchar_t *format,
  278. va_list arglist
  279. )
  280. #endif /* _UNICODE */
  281. #else
  282. #if defined(_UNICODE)
  283. int __cdecl _winput (
  284. FILE *stream,
  285. const wchar_t *format,
  286. va_list arglist
  287. )
  288. #else
  289. int __cdecl _input (
  290. FILE *stream,
  291. const unsigned char *format,
  292. va_list arglist
  293. )
  294. #endif /* _UNICODE */
  295. #endif /* CPRFLAG */
  296. {
  297. #ifndef _UNICODE
  298. char floatstring[CVTBUFSIZE + 1]; /* ASCII buffer for floats */
  299. #else
  300. wchar_t floatstring[CVTBUFSIZE + 1];
  301. #endif
  302. unsigned long number; /* temp hold-value */
  303. #if ALLOC_TABLE
  304. char *table = NULL; /* which chars allowed for %[] */
  305. int malloc_flag = 0; /* is "table" allocated on the heap? */
  306. #else
  307. char AsciiTable[TABLESIZE];
  308. char *table = AsciiTable;
  309. #endif
  310. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  311. unsigned __int64 num64; /* temp for 64-bit integers */
  312. #endif
  313. void *pointer; /* points to user data receptacle */
  314. void *start; /* indicate non-empty string */
  315. #ifdef _UNICODE
  316. wchar_t *scanptr; /* for building "table" data */
  317. REG2 wchar_t ch = 0;
  318. #else
  319. wchar_t wctemp;
  320. unsigned char *scanptr; /* for building "table" data */
  321. REG2 int ch = 0;
  322. #endif
  323. int charcount; /* total number of chars read */
  324. REG1 int comchr; /* holds designator type */
  325. int count; /* return value. # of assignments */
  326. int started; /* indicate good number */
  327. int width; /* width of field */
  328. int widthset; /* user has specified width */
  329. /* Neither coerceshort nor farone are need for the 386 */
  330. char done_flag; /* general purpose loop monitor */
  331. char longone; /* 0 = SHORT, 1 = LONG, 2 = L_DOUBLE */
  332. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  333. int integer64; /* 1 for 64-bit integer, 0 otherwise */
  334. #endif
  335. signed char widechar; /* -1 = char, 0 = ????, 1 = wchar_t */
  336. char reject; /* %[^ABC] instead of %[ABC] */
  337. char negative; /* flag for '-' detected */
  338. char suppress; /* don't assign anything */
  339. char match; /* flag: !0 if any fields matched */
  340. va_list arglistsave; /* save arglist value */
  341. char fl_wchar_arg; /* flags wide char/string argument */
  342. #ifdef _UNICODE
  343. #ifdef ALLOW_RANGE
  344. wchar_t rngch; /* used while scanning range */
  345. #endif
  346. wchar_t last; /* also for %[a-z] */
  347. wchar_t prevchar; /* for %[a-z] */
  348. wchar_t wdecimal; /* wide version of decimal point */
  349. wchar_t *wptr; /* pointer traverses wide floatstring*/
  350. #else
  351. #ifdef ALLOW_RANGE
  352. unsigned char rngch; /* used while scanning range */
  353. #endif
  354. unsigned char last; /* also for %[a-z] */
  355. unsigned char prevchar; /* for %[a-z] */
  356. #endif
  357. _ASSERTE(format != NULL);
  358. #ifndef CPRFLAG
  359. _ASSERTE(stream != NULL);
  360. #endif
  361. /*
  362. count = # fields assigned
  363. charcount = # chars read
  364. match = flag indicating if any fields were matched
  365. [Note that we need both count and match. For example, a field
  366. may match a format but have assignments suppressed. In this case,
  367. match will get set, but 'count' will still equal 0. We need to
  368. distinguish 'match vs no-match' when terminating due to EOF.]
  369. */
  370. count = charcount = match = 0;
  371. while (*format) {
  372. if (_istspace((_TUCHAR)*format)) {
  373. UN_INC(EAT_WHITE()); /* put first non-space char back */
  374. while ((_istspace)(*++format)); /* NULL */
  375. /* careful: isspace macro may evaluate argument more than once! */
  376. continue;
  377. }
  378. if (_T('%') == *format) {
  379. number = 0;
  380. prevchar = 0;
  381. width = widthset = started = 0;
  382. fl_wchar_arg = done_flag = suppress = negative = reject = 0;
  383. widechar = 0;
  384. longone = 1;
  385. integer64 = 0;
  386. while (!done_flag) {
  387. comchr = *++format;
  388. if (_ISDIGIT((_TUCHAR)comchr)) {
  389. ++widthset;
  390. width = MUL10(width) + (comchr - _T('0'));
  391. } else
  392. switch (comchr) {
  393. case _T('F') :
  394. case _T('N') : /* no way to push NEAR in large model */
  395. break; /* NEAR is default in small model */
  396. case _T('h') :
  397. /* set longone to 0 */
  398. --longone;
  399. --widechar; /* set widechar = -1 */
  400. break;
  401. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  402. case _T('I'):
  403. if ( (*(format + 1) == _T('6')) &&
  404. (*(format + 2) == _T('4')) )
  405. {
  406. format += 2;
  407. ++integer64;
  408. num64 = 0;
  409. break;
  410. }
  411. else if ( (*(format + 1) == _T('3')) &&
  412. (*(format + 2) == _T('2')) )
  413. {
  414. format += 2;
  415. break;
  416. }
  417. else if ( (*(format + 1) == _T('d')) ||
  418. (*(format + 1) == _T('i')) ||
  419. (*(format + 1) == _T('o')) ||
  420. (*(format + 1) == _T('x')) ||
  421. (*(format + 1) == _T('X')) )
  422. {
  423. if (sizeof(void*) == sizeof(__int64))
  424. {
  425. ++integer64;
  426. num64 = 0;
  427. }
  428. break;
  429. }
  430. if (sizeof(void*) == sizeof(__int64))
  431. {
  432. ++integer64;
  433. num64 = 0;
  434. }
  435. goto DEFAULT_LABEL;
  436. #endif
  437. case _T('L') :
  438. /* ++longone; */
  439. ++longone;
  440. break;
  441. case _T('l') :
  442. ++longone;
  443. /* NOBREAK */
  444. case _T('w') :
  445. ++widechar; /* set widechar = 1 */
  446. break;
  447. case _T('*') :
  448. ++suppress;
  449. break;
  450. default:
  451. DEFAULT_LABEL:
  452. ++done_flag;
  453. break;
  454. }
  455. }
  456. if (!suppress) {
  457. arglistsave = arglist;
  458. pointer = va_arg(arglist,void *);
  459. } else {
  460. pointer = NULL; // doesn't matter what value we use here - we're only using it as a flag
  461. }
  462. done_flag = 0;
  463. if (!widechar) { /* use case if not explicitly specified */
  464. if ((*format == _T('S')) || (*format == _T('C')))
  465. #ifdef _UNICODE
  466. --widechar;
  467. else
  468. ++widechar;
  469. #else
  470. ++widechar;
  471. else
  472. --widechar;
  473. #endif
  474. }
  475. /* switch to lowercase to allow %E,%G, and to
  476. keep the switch table small */
  477. comchr = *format | (_T('a') - _T('A'));
  478. if (_T('n') != comchr)
  479. if (_T('c') != comchr && LEFT_BRACKET != comchr)
  480. ch = EAT_WHITE();
  481. else
  482. ch = INC();
  483. #ifdef _POSIX_
  484. if (_T('n') != comchr)
  485. {
  486. if (EOF == ch)
  487. goto error_return;
  488. }
  489. #endif
  490. if (!widthset || width) {
  491. switch(comchr) {
  492. case _T('c'):
  493. /* case _T('C'): */
  494. if (!widthset) {
  495. ++widthset;
  496. ++width;
  497. }
  498. if (widechar > 0)
  499. fl_wchar_arg++;
  500. goto scanit;
  501. case _T('s'):
  502. /* case _T('S'): */
  503. if(widechar > 0)
  504. fl_wchar_arg++;
  505. goto scanit;
  506. case LEFT_BRACKET : /* scanset */
  507. if (widechar>0)
  508. fl_wchar_arg++;
  509. scanptr = (_TCHAR *)(++format);
  510. if (_T('^') == *scanptr) {
  511. ++scanptr;
  512. --reject; /* set reject to 255 */
  513. }
  514. /* Allocate "table" on first %[] spec */
  515. #if ALLOC_TABLE
  516. if (table == NULL) {
  517. __try {
  518. table = _alloca(TABLESIZE);
  519. }
  520. __except(EXCEPTION_EXECUTE_HANDLER) {
  521. _resetstkoflw();
  522. table = _malloc_crt(TABLESIZE);
  523. if ( table == NULL)
  524. goto error_return;
  525. malloc_flag = 1;
  526. }
  527. }
  528. #endif
  529. memset(table, 0, TABLESIZE);
  530. #ifdef ALLOW_RANGE
  531. if (LEFT_BRACKET == comchr)
  532. if (_T(']') == *scanptr) {
  533. prevchar = _T(']');
  534. ++scanptr;
  535. table[ _T(']') >> 3] = 1 << (_T(']') & 7);
  536. }
  537. while (_T(']') != *scanptr) {
  538. rngch = *scanptr++;
  539. if (_T('-') != rngch ||
  540. !prevchar || /* first char */
  541. _T(']') == *scanptr) /* last char */
  542. table[(prevchar = rngch) >> 3] |= 1 << (rngch & 7);
  543. else { /* handle a-z type set */
  544. rngch = *scanptr++; /* get end of range */
  545. if (prevchar < rngch) /* %[a-z] */
  546. last = rngch;
  547. else { /* %[z-a] */
  548. last = prevchar;
  549. prevchar = rngch;
  550. }
  551. for (rngch = prevchar; rngch <= last; ++rngch)
  552. table[rngch >> 3] |= 1 << (rngch & 7);
  553. prevchar = 0;
  554. }
  555. }
  556. #else
  557. if (LEFT_BRACKET == comchr)
  558. if (_T(']') == *scanptr) {
  559. ++scanptr;
  560. table[(prevchar = _T(']')) >> 3] |= 1 << (_T(']') & 7);
  561. }
  562. while (_T(']') != *scanptr) {
  563. table[scanptr >> 3] |= 1 << (scanptr & 7);
  564. ++scanptr;
  565. }
  566. /* code under !ALLOW_RANGE is probably never compiled */
  567. /* and has probably never been tested */
  568. #endif
  569. if (!*scanptr)
  570. goto error_return; /* trunc'd format string */
  571. /* scanset completed. Now read string */
  572. if (LEFT_BRACKET == comchr)
  573. format = scanptr;
  574. scanit:
  575. start = pointer;
  576. /*
  577. * execute the format directive. that is, scan input
  578. * characters until the directive is fulfilled, eof
  579. * is reached, or a non-matching character is
  580. * encountered.
  581. *
  582. * it is important not to get the next character
  583. * unless that character needs to be tested! other-
  584. * wise, reads from line-buffered devices (e.g.,
  585. * scanf()) would require an extra, spurious, newline
  586. * if the first newline completes the current format
  587. * directive.
  588. */
  589. UN_INC(ch);
  590. while ( !widthset || width-- ) {
  591. ch = INC();
  592. if (
  593. #ifndef CPRFLAG
  594. #ifndef _UNICODE
  595. (EOF != ch) &&
  596. #else
  597. (WEOF != ch) &&
  598. #endif /* _UNICODE */
  599. #endif
  600. // char conditions
  601. ( ( comchr == _T('c')) ||
  602. // string conditions !isspace()
  603. ( ( comchr == _T('s') &&
  604. (!(ch >= _T('\t') && ch <= _T('\r')) &&
  605. ch != _T(' ')))) ||
  606. // BRACKET conditions
  607. ( (comchr == LEFT_BRACKET) &&
  608. ((table[ch >> 3] ^ reject) & (1 << (ch & 7)))
  609. )
  610. )
  611. )
  612. {
  613. if (!suppress) {
  614. #ifndef _UNICODE
  615. if (fl_wchar_arg) {
  616. char temp[2];
  617. temp[0] = (char) ch;
  618. if (isleadbyte(ch))
  619. temp[1] = (char) INC();
  620. mbtowc(&wctemp, temp, MB_CUR_MAX);
  621. *(wchar_t UNALIGNED *)pointer =
  622. wctemp;
  623. /* do nothing if mbtowc fails */
  624. pointer = (wchar_t *)pointer + 1;
  625. } else
  626. #else
  627. if (fl_wchar_arg) {
  628. *(wchar_t UNALIGNED *)pointer = ch;
  629. pointer = (wchar_t *)pointer + 1;
  630. } else
  631. #endif
  632. {
  633. #ifndef _UNICODE
  634. *(char *)pointer = (char)ch;
  635. pointer = (char *)pointer + 1;
  636. #else
  637. int temp;
  638. /* convert wide to multibyte */
  639. temp = wctomb((char *)pointer, ch);
  640. /* do nothing if wctomb fails */
  641. pointer = (char *)pointer + temp;
  642. #endif
  643. }
  644. } /* suppress */
  645. else {
  646. /* just indicate a match */
  647. start = (_TCHAR *)start + 1;
  648. }
  649. }
  650. else {
  651. UN_INC(ch);
  652. break;
  653. }
  654. }
  655. /* make sure something has been matched and, if
  656. assignment is not suppressed, null-terminate
  657. output string if comchr != c */
  658. if (start != pointer) {
  659. if (!suppress) {
  660. ++count;
  661. if ('c' != comchr) /* null-terminate strings */
  662. if (fl_wchar_arg)
  663. *(wchar_t UNALIGNED *)pointer = L'\0';
  664. else
  665. *(char *)pointer = '\0';
  666. } else /*NULL*/;
  667. }
  668. else
  669. goto error_return;
  670. break;
  671. case _T('i') : /* could be d, o, or x */
  672. comchr = _T('d'); /* use as default */
  673. case _T('x'):
  674. if (_T('-') == ch) {
  675. ++negative;
  676. goto x_incwidth;
  677. } else if (_T('+') == ch) {
  678. x_incwidth:
  679. if (!--width && widthset)
  680. ++done_flag;
  681. else
  682. ch = INC();
  683. }
  684. if (_T('0') == ch) {
  685. if (_T('x') == (_TCHAR)(ch = INC()) || _T('X') == (_TCHAR)ch) {
  686. ch = INC();
  687. if (widthset) {
  688. width -= 2;
  689. if (width < 1)
  690. ++done_flag;
  691. }
  692. comchr = _T('x');
  693. } else {
  694. ++started;
  695. if (_T('x') != comchr) {
  696. if (widthset && !--width)
  697. ++done_flag;
  698. comchr = _T('o');
  699. }
  700. else {
  701. /* scanning a hex number that starts */
  702. /* with a 0. push back the character */
  703. /* currently in ch and restore the 0 */
  704. UN_INC(ch);
  705. ch = _T('0');
  706. }
  707. }
  708. }
  709. goto getnum;
  710. /* NOTREACHED */
  711. case _T('p') :
  712. /* force %hp to be treated as %p */
  713. longone = 1;
  714. #ifdef _WIN64
  715. /* force %p to be 64 bit in WIN64 */
  716. ++integer64;
  717. num64 = 0;
  718. #endif
  719. case _T('o') :
  720. case _T('u') :
  721. case _T('d') :
  722. if (_T('-') == ch) {
  723. ++negative;
  724. goto d_incwidth;
  725. } else if (_T('+') == ch) {
  726. d_incwidth:
  727. if (!--width && widthset)
  728. ++done_flag;
  729. else
  730. ch = INC();
  731. }
  732. getnum:
  733. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  734. if ( integer64 ) {
  735. while (!done_flag) {
  736. if (_T('x') == comchr || _T('p') == comchr)
  737. if (_ISXDIGIT(ch)) {
  738. num64 <<= 4;
  739. ch = HEXTODEC(ch);
  740. }
  741. else
  742. ++done_flag;
  743. else if (_ISDIGIT(ch))
  744. if (_T('o') == comchr)
  745. if (_T('8') > ch)
  746. num64 <<= 3;
  747. else {
  748. ++done_flag;
  749. }
  750. else /* _T('d') == comchr */
  751. num64 = MUL10(num64);
  752. else
  753. ++done_flag;
  754. if (!done_flag) {
  755. ++started;
  756. num64 += ch - _T('0');
  757. if (widthset && !--width)
  758. ++done_flag;
  759. else
  760. ch = INC();
  761. } else
  762. UN_INC(ch);
  763. } /* end of WHILE loop */
  764. if (negative)
  765. num64 = (unsigned __int64 )(-(__int64)num64);
  766. }
  767. else {
  768. #endif
  769. while (!done_flag) {
  770. if (_T('x') == comchr || _T('p') == comchr)
  771. if (_ISXDIGIT(ch)) {
  772. number = (number << 4);
  773. ch = HEXTODEC(ch);
  774. }
  775. else
  776. ++done_flag;
  777. else if (_ISDIGIT(ch))
  778. if (_T('o') == comchr)
  779. if (_T('8') > ch)
  780. number = (number << 3);
  781. else {
  782. ++done_flag;
  783. }
  784. else /* _T('d') == comchr */
  785. number = MUL10(number);
  786. else
  787. ++done_flag;
  788. if (!done_flag) {
  789. ++started;
  790. number += ch - _T('0');
  791. if (widthset && !--width)
  792. ++done_flag;
  793. else
  794. ch = INC();
  795. } else
  796. UN_INC(ch);
  797. } /* end of WHILE loop */
  798. if (negative)
  799. number = (unsigned long)(-(long)number);
  800. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  801. }
  802. #endif
  803. if (_T('F')==comchr) /* expected ':' in long pointer */
  804. started = 0;
  805. if (started)
  806. if (!suppress) {
  807. ++count;
  808. assign_num:
  809. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  810. if ( integer64 )
  811. *(__int64 UNALIGNED *)pointer = (unsigned __int64)num64;
  812. else
  813. #endif
  814. if (longone)
  815. *(long UNALIGNED *)pointer = (unsigned long)number;
  816. else
  817. *(short UNALIGNED *)pointer = (unsigned short)number;
  818. } else /*NULL*/;
  819. else
  820. goto error_return;
  821. break;
  822. case _T('n') : /* char count, don't inc return value */
  823. number = charcount;
  824. if(!suppress)
  825. goto assign_num; /* found in number code above */
  826. break;
  827. case _T('e') :
  828. /* case _T('E') : */
  829. case _T('f') :
  830. case _T('g') : /* scan a float */
  831. /* case _T('G') : */
  832. #ifndef _UNICODE
  833. scanptr = floatstring;
  834. if (_T('-') == ch) {
  835. *scanptr++ = _T('-');
  836. goto f_incwidth;
  837. } else if (_T('+') == ch) {
  838. f_incwidth:
  839. --width;
  840. ch = INC();
  841. }
  842. if (!widthset || width > CVTBUFSIZE) /* must watch width */
  843. width = CVTBUFSIZE;
  844. /* now get integral part */
  845. while (_ISDIGIT(ch) && width--) {
  846. ++started;
  847. *scanptr++ = (char)ch;
  848. ch = INC();
  849. }
  850. /* now check for decimal */
  851. if (*___decimal_point == (char)ch && width--) {
  852. ch = INC();
  853. *scanptr++ = *___decimal_point;
  854. while (_ISDIGIT(ch) && width--) {
  855. ++started;
  856. *scanptr++ = (char)ch;
  857. ch = INC();
  858. }
  859. }
  860. /* now check for exponent */
  861. if (started && (_T('e') == ch || _T('E') == ch) && width--) {
  862. *scanptr++ = 'e';
  863. if (_T('-') == (ch = INC())) {
  864. *scanptr++ = '-';
  865. goto f_incwidth2;
  866. } else if (_T('+') == ch) {
  867. f_incwidth2:
  868. if (!width--)
  869. ++width;
  870. else
  871. ch = INC();
  872. }
  873. while (_ISDIGIT(ch) && width--) {
  874. ++started;
  875. *scanptr++ = (char)ch;
  876. ch = INC();
  877. }
  878. }
  879. UN_INC(ch);
  880. if (started)
  881. if (!suppress) {
  882. ++count;
  883. *scanptr = '\0';
  884. _fassign( longone-1, pointer , floatstring);
  885. } else /*NULL */;
  886. else
  887. goto error_return;
  888. #else /* _UNICODE */
  889. wptr = floatstring;
  890. if (L'-' == ch) {
  891. *wptr++ = L'-';
  892. goto f_incwidthw;
  893. } else if (L'+' == ch) {
  894. f_incwidthw:
  895. --width;
  896. ch = INC();
  897. }
  898. if (!widthset || width > CVTBUFSIZE)
  899. width = CVTBUFSIZE;
  900. /* now get integral part */
  901. while (_ISDIGIT(ch) && width--) {
  902. ++started;
  903. *wptr++ = ch;
  904. ch = INC();
  905. }
  906. /* now check for decimal */
  907. /* convert decimal point to wide-char */
  908. /* assume result is single wide-char */
  909. mbtowc (&wdecimal, ___decimal_point, MB_CUR_MAX);
  910. if (wdecimal == ch && width--) {
  911. ch = INC();
  912. *wptr++ = wdecimal;
  913. while (_ISDIGIT(ch) && width--) {
  914. ++started;
  915. *wptr++ = ch;
  916. ch = INC();
  917. }
  918. }
  919. /* now check for exponent */
  920. if (started && (L'e' == ch || L'E' == ch) && width--) {
  921. *wptr++ = L'e';
  922. if (L'-' == (ch = INC())) {
  923. *wptr++ = L'-';
  924. goto f_incwidth2w;
  925. } else if (L'+' == ch) {
  926. f_incwidth2w:
  927. if (!width--)
  928. ++width;
  929. else
  930. ch = INC();
  931. }
  932. while (_ISDIGIT(ch) && width--) {
  933. ++started;
  934. *wptr++ = ch;
  935. ch = INC();
  936. }
  937. }
  938. UN_INC(ch);
  939. if (started)
  940. if (!suppress) {
  941. ++count;
  942. *wptr = '\0';
  943. {
  944. /* convert floatstring to char string */
  945. /* and do the conversion */
  946. size_t cfslength;
  947. char *cfloatstring;
  948. cfslength =(size_t)(wptr-floatstring+1)*sizeof(wchar_t);
  949. if ((cfloatstring = (char *)_malloc_crt (cfslength)) == NULL)
  950. goto error_return;
  951. wcstombs (cfloatstring, floatstring, cfslength);
  952. _fassign( longone-1, pointer , cfloatstring);
  953. _free_crt (cfloatstring);
  954. }
  955. } else /*NULL */;
  956. else
  957. goto error_return;
  958. #endif /* _UNICODE */
  959. break;
  960. default: /* either found '%' or something else */
  961. if ((int)*format != (int)ch) {
  962. UN_INC(ch);
  963. goto error_return;
  964. }
  965. else
  966. match--; /* % found, compensate for inc below */
  967. if (!suppress)
  968. arglist = arglistsave;
  969. } /* SWITCH */
  970. match++; /* matched a format field - set flag */
  971. } /* WHILE (width) */
  972. else { /* zero-width field in format string */
  973. UN_INC(ch); /* check for input error */
  974. goto error_return;
  975. }
  976. ++format; /* skip to next char */
  977. } else /* ('%' != *format) */
  978. {
  979. if ((int)*format++ != (int)(ch = INC()))
  980. {
  981. UN_INC(ch);
  982. goto error_return;
  983. }
  984. #ifndef _UNICODE
  985. if (isleadbyte(ch))
  986. {
  987. int ch2;
  988. if ((int)*format++ != (ch2=INC()))
  989. {
  990. UN_INC(ch2);
  991. UN_INC(ch);
  992. goto error_return;
  993. }
  994. --charcount; /* only count as one character read */
  995. }
  996. #endif
  997. }
  998. #ifndef CPRFLAG
  999. if ( (EOF == ch) && ((*format != '%') || (*(format + 1) != 'n')) )
  1000. break;
  1001. #endif
  1002. } /* WHILE (*format) */
  1003. error_return:
  1004. #if ALLOC_TABLE
  1005. if (malloc_flag == 1)
  1006. _free_crt(table);
  1007. #endif
  1008. #ifndef CPRFLAG
  1009. if (EOF == ch)
  1010. /* If any fields were matched or assigned, return count */
  1011. return ( (count || match) ? count : EOF);
  1012. else
  1013. #endif
  1014. return count;
  1015. }
  1016. /* _hextodec() returns a value of 0-15 and expects a char 0-9, a-f, A-F */
  1017. /* _inc() is the one place where we put the actual getc code. */
  1018. /* _whiteout() returns the first non-blank character, as defined by isspace() */
  1019. #ifndef _UNICODE
  1020. static int __cdecl _hextodec (
  1021. int chr
  1022. )
  1023. {
  1024. return _ISDIGIT(chr) ? chr : (chr & ~(_T('a') - _T('A'))) - _T('A') + 10 + _T('0');
  1025. }
  1026. #else
  1027. static _TCHAR __cdecl _hextodec (
  1028. _TCHAR chr
  1029. )
  1030. {
  1031. if (_ISDIGIT(chr))
  1032. return chr;
  1033. if (_istlower(chr))
  1034. return (_TCHAR)(chr - _T('a') + 10 + _T('0'));
  1035. else
  1036. return (_TCHAR)(chr - _T('A') + 10 + _T('0'));
  1037. }
  1038. #endif
  1039. #ifdef CPRFLAG
  1040. #ifndef _UNICODE
  1041. static int __cdecl _inc (
  1042. void
  1043. )
  1044. {
  1045. return(_getche_lk());
  1046. }
  1047. static void __cdecl _un_inc (
  1048. int chr
  1049. )
  1050. {
  1051. if (EOF != chr)
  1052. _ungetch_lk(chr);
  1053. }
  1054. static int __cdecl _whiteout (
  1055. REG1 int *counter
  1056. )
  1057. {
  1058. REG2 int ch;
  1059. while((_istspace)(ch = (++*counter, _inc())));
  1060. return ch;
  1061. }
  1062. #else /* _UNICODE */
  1063. static wchar_t __cdecl _inc (
  1064. void
  1065. )
  1066. {
  1067. return(_getwche_lk());
  1068. }
  1069. static void __cdecl _un_inc (
  1070. wchar_t chr
  1071. )
  1072. {
  1073. if (WEOF != chr)
  1074. _ungetwch_lk(chr);
  1075. }
  1076. static wchar_t __cdecl _whiteout (
  1077. REG1 int *counter
  1078. )
  1079. {
  1080. REG2 wchar_t ch;
  1081. while((iswspace)(ch = (++*counter, _inc())));
  1082. return ch;
  1083. }
  1084. #endif
  1085. #else /* CPRFLAG */
  1086. #ifdef _UNICODE
  1087. /*
  1088. * Manipulate wide-chars in a file.
  1089. * A wide-char is hard-coded to be two chars for efficiency.
  1090. */
  1091. static wchar_t __cdecl _inc (
  1092. REG1 FILE *fileptr
  1093. )
  1094. {
  1095. return(_getwc_lk(fileptr));
  1096. }
  1097. static void __cdecl _un_inc (
  1098. wchar_t chr,
  1099. FILE *fileptr
  1100. )
  1101. {
  1102. if (WEOF != chr)
  1103. _ungetwc_lk(chr, fileptr);
  1104. }
  1105. static wchar_t __cdecl _whiteout (
  1106. REG1 int *counter,
  1107. REG3 FILE *fileptr
  1108. )
  1109. {
  1110. REG2 wchar_t ch;
  1111. while((iswspace)(ch = (++*counter, _inc(fileptr))));
  1112. return ch;
  1113. }
  1114. #else /* _UNICODE */
  1115. static int __cdecl _inc (
  1116. REG1 FILE *fileptr
  1117. )
  1118. {
  1119. return(_getc_lk(fileptr));
  1120. }
  1121. static void __cdecl _un_inc (
  1122. int chr,
  1123. FILE *fileptr
  1124. )
  1125. {
  1126. if (EOF != chr)
  1127. _ungetc_lk(chr, fileptr);
  1128. }
  1129. static int __cdecl _whiteout (
  1130. REG1 int *counter,
  1131. REG3 FILE *fileptr
  1132. )
  1133. {
  1134. REG2 int ch;
  1135. while((_istspace)(ch = (++*counter, _inc(fileptr))));
  1136. return ch;
  1137. }
  1138. #endif /* _UNICODE */
  1139. #endif /* CPRFLAG */