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.

1514 lines
50 KiB

  1. /***
  2. *output.c - printf style output to a FILE
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This file contains the code that does all the work for the
  8. * printf family of functions. It should not be called directly, only
  9. * by the *printf functions. We don't make any assumtions about the
  10. * sizes of ints, longs, shorts, or long doubles, but if types do overlap,
  11. * we also try to be efficient. We do assume that pointers are the same
  12. * size as either ints or longs.
  13. * If CPRFLAG is defined, defines _cprintf instead.
  14. * **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
  15. *
  16. *Revision History:
  17. * 06-01-89 PHG Module created
  18. * 08-28-89 JCR Added cast to get rid of warning (no object changes)
  19. * 02-15-90 GJF Fixed copyright
  20. * 03-19-90 GJF Made calling type _CALLTYPE1 and added #include
  21. * <cruntime.h>.
  22. * 03-26-90 GJF Changed LOCAL macro to incorporate _CALLTYPE4. Placed
  23. * prototype for _output() in internal.h and #include-d
  24. * it.
  25. * 08-01-90 SBM Compiles cleanly with -W3, moved _cfltcvt_tab and
  26. * typedefs DOUBLE and LONGDOUBLE to new header
  27. * <fltintrn.h>, formerly named <struct.h>
  28. * 09-05-90 SBM First attempt at adding CPRFLAG and code to generate
  29. * cprintf. Anything in #ifdef CPRFLAG untested.
  30. * Still needs to have locking added for MTHREAD case.
  31. * 10-03-90 GJF New-style function declarators.
  32. * 01-02-91 SRW Added _WIN32_ conditional for 'C' and 'S' format chars.
  33. * 01-16-91 GJF ANSI naming.
  34. * 01-16-91 SRW Added #include of maketabc.out (_WIN32_)
  35. * 04-09-91 PNT Use the _CRUISER_ mapping for _MAC_
  36. * 04-16-91 SRW Fixed #include of maketabc.out (_WIN32_)
  37. * 04-25-91 SRW Made nullstring static
  38. * 05-20-91 GJF Moved state table for Win32 inline (_WIN32_).
  39. * 09-12-91 JCR Bumped conversion buffer size to be ANSI-compliant
  40. * 09-17-91 IHJ Add partial UNICODE (%ws, %wc) support
  41. * 09-28-91 GJF Merged with crt32 and crtdll versions. For now, 9-17-91
  42. * change is built only for Win32, not Dosx32 (_WIN32_).
  43. * 10-22-91 ETC Complete wchar_t/mb support under _INTL. For now,
  44. * 9-28-91 change is additionally under !_INTL. Bug fix:
  45. * ints and pointers are longs.
  46. * 11-19-91 ETC Added support for _wsprintf, _vwsprintf with WPRFLAG;
  47. * added %tc %ts (generic string handling).
  48. * 12-05-91 GDP Bug fix: va_arg was used inconsistently for double
  49. * 12-19-91 ETC Added some comments on wsprintf optimization, undones;
  50. * check return on malloc.
  51. * 03-25-92 DJM POSIX support
  52. * 04-16-92 KRS Support new ISO {s|f}wprintf with Unicode format string.
  53. * 06-08-92 SRW Modified to not use free and malloc for mbtowc conversion.
  54. * 06-10-92 KRS Fix glitch in previous change.
  55. * 07-17-92 KRS Fix typo which broke WPRFLAG support.
  56. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  57. * 04-16-93 SKS Fix bug in 'S' option logic.
  58. * 04-26-93 CFW Wide char enable.
  59. * 07-14-93 TVB Added Alpha support (quad stuff).
  60. * 07-16-93 SRW ALPHA Merge
  61. * 07-26-93 GJF Fixed write_multichar and write_string so that they
  62. * stop looping when an error occurs. This generalizes
  63. * and supplants the fix MattBr made for POSIX only.
  64. * 08-17-93 CFW Avoid mapping tchar macros incorrectly if _MBCS
  65. * defined.
  66. * 11-10-93 GJF Merged in NT SDK version. Deleted Cruiser support
  67. * and references to _WIN32_ (the former is obsolete and
  68. * the later is assumed).
  69. * 03-10-94 GJF Added support for I64 size modifier.
  70. * 03-25-94 GJF Rebuilt __lookuptable[].
  71. * 09-05-94 SKS Change "#ifdef" inside comments to "*ifdef" to avoid
  72. * problems with CRTL source release process.
  73. * 10-02-94 BWT Add _M_PPC definition.
  74. * 10-19-94 BWT Reenable %Z and %ws/%wc for NT_BUILD only.
  75. * 02-06-94 CFW assert -> _ASSERTE.
  76. * 02-23-95 GJF Appended Mac version of source file (somewhat cleaned
  77. * up), with appropriate #ifdef-s. Also, replaced
  78. * WPRFLAG with _UNICODE.
  79. * 05-03-96 GJF Removed NT_BUILD. The extensions for NT (i.e., the 'Z'
  80. * descriptor and 'w' modifier) are now in the retail
  81. * build. Fixed textlen calculation for %ws. Also,
  82. * detab-ed.
  83. * 07-25-96 SKS Added initialization of textlen for cases where no valid
  84. * format character is found after the % character.
  85. * 08-01-96 RDK Add support for %I64 for PMac.
  86. * 09-09-96 JWM Local struct "string" renamed to "_count_string" (Orion
  87. * 8710).
  88. * 02-27-98 RKP Added 64 bit support.
  89. * 03-05-98 RKP Expanded pointers to 64 bits on AXP64 and IA64.
  90. * 09-17-98 GJF Added support for %I32 and %I modifiers.
  91. * 01-04-99 GJF Changes for 64-bit size_t.
  92. * 05-17-99 PML Remove all Macintosh support.
  93. * 11-03-99 GB VS7#5431. Fixed output() for the case when L format
  94. * specifier is used with wprintf
  95. * 11-30-99 PML Compile /Wp64 clean.
  96. * 02-11-00 GB Added support for unicode console output function
  97. * (_cwprintf).
  98. * 03-10-00 GB Modified write_char for NULL pointer string in
  99. * sprintf.
  100. * 11-22-00 PML Wide-char *putwc* functions take a wchar_t, not wint_t.
  101. * 07-05-01 BWT Turn off %n formatting for NTSUBSET - it's a security hole
  102. * waiting to happen.
  103. * 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
  104. * 08-11-01 PML Cap precision to fix overrun of 'buffer' (vs7#298618)
  105. *
  106. *******************************************************************************/
  107. /* temporary work-around for compiler without 64-bit support */
  108. #ifndef _INTEGRAL_MAX_BITS
  109. #define _INTEGRAL_MAX_BITS 64
  110. #endif
  111. #include <cruntime.h>
  112. #include <limits.h>
  113. #include <string.h>
  114. #include <stddef.h>
  115. #include <stdio.h>
  116. #include <stdarg.h>
  117. #include <cvt.h>
  118. #include <conio.h>
  119. #include <internal.h>
  120. #include <fltintrn.h>
  121. #include <stdlib.h>
  122. #include <ctype.h>
  123. #include <dbgint.h>
  124. /* inline keyword is non-ANSI C7 extension */
  125. #if !defined(_MSC_VER) || defined(__STDC__)
  126. #define __inline static
  127. #else
  128. /* UNDONE: compiler is broken */
  129. #define __inline static
  130. #endif
  131. #ifdef _MBCS /* always want either Unicode or SBCS for tchar.h */
  132. #undef _MBCS
  133. #endif
  134. #include <tchar.h>
  135. /* this macro defines a function which is private and as fast as possible: */
  136. /* for example, in C 6.0, it might be static _fastcall <type> near. */
  137. #define LOCAL(x) static x __cdecl
  138. /* int/long/short/pointer sizes */
  139. /* the following should be set depending on the sizes of various types */
  140. #define LONG_IS_INT 1 /* 1 means long is same size as int */
  141. #define SHORT_IS_INT 0 /* 1 means short is same size as int */
  142. #define LONGDOUBLE_IS_DOUBLE 1 /* 1 means long double is same as double */
  143. #if defined (_WIN64)
  144. #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
  145. #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
  146. #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
  147. #else
  148. #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
  149. #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
  150. #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
  151. #endif
  152. #if LONG_IS_INT
  153. #define get_long_arg(x) (long)get_int_arg(x)
  154. #endif
  155. #ifndef _UNICODE
  156. #if SHORT_IS_INT
  157. #define get_short_arg(x) (short)get_int_arg(x)
  158. #endif
  159. #endif
  160. #if PTR_IS_INT
  161. #define get_ptr_arg(x) (void *)(intptr_t)get_int_arg(x)
  162. #elif PTR_IS_LONG
  163. #define get_ptr_arg(x) (void *)(intptr_t)get_long_arg(x)
  164. #elif PTR_IS_INT64
  165. #define get_ptr_arg(x) (void *)get_int64_arg(x)
  166. #else
  167. #error Size of pointer must be same as size of int or long
  168. #endif
  169. /* CONSTANTS */
  170. /* size of conversion buffer (ANSI-specified minimum is 509) */
  171. #define BUFFERSIZE 512
  172. #define MAXPRECISION BUFFERSIZE
  173. #if BUFFERSIZE < CVTBUFSIZE + 6 /*IFSTRIP=IGN*/
  174. /*
  175. * Buffer needs to be big enough for default minimum precision
  176. * when converting floating point needs bigger buffer, and malloc
  177. * fails
  178. */
  179. #error Conversion buffer too small for max double.
  180. #endif
  181. /* flag definitions */
  182. #define FL_SIGN 0x00001 /* put plus or minus in front */
  183. #define FL_SIGNSP 0x00002 /* put space or minus in front */
  184. #define FL_LEFT 0x00004 /* left justify */
  185. #define FL_LEADZERO 0x00008 /* pad with leading zeros */
  186. #define FL_LONG 0x00010 /* long value given */
  187. #define FL_SHORT 0x00020 /* short value given */
  188. #define FL_SIGNED 0x00040 /* signed data given */
  189. #define FL_ALTERNATE 0x00080 /* alternate form requested */
  190. #define FL_NEGATIVE 0x00100 /* value is negative */
  191. #define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
  192. #define FL_LONGDOUBLE 0x00400 /* long double value given */
  193. #define FL_WIDECHAR 0x00800 /* wide characters */
  194. #define FL_I64 0x08000 /* __int64 value given */
  195. /* state definitions */
  196. enum STATE {
  197. ST_NORMAL, /* normal state; outputting literal chars */
  198. ST_PERCENT, /* just read '%' */
  199. ST_FLAG, /* just read flag character */
  200. ST_WIDTH, /* just read width specifier */
  201. ST_DOT, /* just read '.' */
  202. ST_PRECIS, /* just read precision specifier */
  203. ST_SIZE, /* just read size specifier */
  204. ST_TYPE /* just read type specifier */
  205. };
  206. #define NUMSTATES (ST_TYPE + 1)
  207. /* character type values */
  208. enum CHARTYPE {
  209. CH_OTHER, /* character with no special meaning */
  210. CH_PERCENT, /* '%' */
  211. CH_DOT, /* '.' */
  212. CH_STAR, /* '*' */
  213. CH_ZERO, /* '0' */
  214. CH_DIGIT, /* '1'..'9' */
  215. CH_FLAG, /* ' ', '+', '-', '#' */
  216. CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
  217. CH_TYPE /* type specifying character */
  218. };
  219. /* static data (read only, since we are re-entrant) */
  220. #if defined(_UNICODE) || defined(CPRFLAG)
  221. extern char *__nullstring; /* string to print on null ptr */
  222. extern wchar_t *__wnullstring; /* string to print on null ptr */
  223. #else /* _UNICODE || CPRFLAG */
  224. char *__nullstring = "(null)"; /* string to print on null ptr */
  225. wchar_t *__wnullstring = L"(null)";/* string to print on null ptr */
  226. #endif /* _UNICODE || CPRFLAG */
  227. /* The state table. This table is actually two tables combined into one. */
  228. /* The lower nybble of each byte gives the character class of any */
  229. /* character; while the uper nybble of the byte gives the next state */
  230. /* to enter. See the macros below the table for details. */
  231. /* */
  232. /* The table is generated by maketabc.c -- use this program to make */
  233. /* changes. */
  234. #if defined(_UNICODE) || defined(CPRFLAG)
  235. extern const char __lookuptable[];
  236. #else /* _UNICODE/CPRFLAG */
  237. const char __lookuptable[] = {
  238. /* ' ' */ 0x06,
  239. /* '!' */ 0x00,
  240. /* '"' */ 0x00,
  241. /* '#' */ 0x06,
  242. /* '$' */ 0x00,
  243. /* '%' */ 0x01,
  244. /* '&' */ 0x00,
  245. /* ''' */ 0x00,
  246. /* ('' */ 0x10,
  247. /* ')' */ 0x00,
  248. /* '*' */ 0x03,
  249. /* '+' */ 0x06,
  250. /* ',' */ 0x00,
  251. /* '-' */ 0x06,
  252. /* '.' */ 0x02,
  253. /* '/' */ 0x10,
  254. /* '0' */ 0x04,
  255. /* '1' */ 0x45,
  256. /* '2' */ 0x45,
  257. /* '3' */ 0x45,
  258. /* '4' */ 0x05,
  259. /* '5' */ 0x05,
  260. /* '6' */ 0x05,
  261. /* '7' */ 0x05,
  262. /* '8' */ 0x05,
  263. /* '9' */ 0x35,
  264. /* ':' */ 0x30,
  265. /* ';' */ 0x00,
  266. /* '<' */ 0x50,
  267. /* '=' */ 0x00,
  268. /* '>' */ 0x00,
  269. /* '?' */ 0x00,
  270. /* '@' */ 0x00,
  271. /* 'A' */ 0x20,
  272. /* 'B' */ 0x28,
  273. /* 'C' */ 0x38,
  274. /* 'D' */ 0x50,
  275. /* 'E' */ 0x58,
  276. /* 'F' */ 0x07,
  277. /* 'G' */ 0x08,
  278. /* 'H' */ 0x00,
  279. /* 'I' */ 0x37,
  280. /* 'J' */ 0x30,
  281. /* 'K' */ 0x30,
  282. /* 'L' */ 0x57,
  283. /* 'M' */ 0x50,
  284. /* 'N' */ 0x07,
  285. /* 'O' */ 0x00,
  286. /* 'P' */ 0x00,
  287. /* 'Q' */ 0x20,
  288. /* 'R' */ 0x20,
  289. /* 'S' */ 0x08,
  290. /* 'T' */ 0x00,
  291. /* 'U' */ 0x00,
  292. /* 'V' */ 0x00,
  293. /* 'W' */ 0x00,
  294. /* 'X' */ 0x08,
  295. /* 'Y' */ 0x60,
  296. /* 'Z' */ 0x68,
  297. /* '[' */ 0x60,
  298. /* '\' */ 0x60,
  299. /* ']' */ 0x60,
  300. /* '^' */ 0x60,
  301. /* '_' */ 0x00,
  302. /* '`' */ 0x00,
  303. /* 'a' */ 0x70,
  304. /* 'b' */ 0x70,
  305. /* 'c' */ 0x78,
  306. /* 'd' */ 0x78,
  307. /* 'e' */ 0x78,
  308. /* 'f' */ 0x78,
  309. /* 'g' */ 0x08,
  310. /* 'h' */ 0x07,
  311. /* 'i' */ 0x08,
  312. /* 'j' */ 0x00,
  313. /* 'k' */ 0x00,
  314. /* 'l' */ 0x07,
  315. /* 'm' */ 0x00,
  316. #ifdef _NTSUBSET_
  317. /* 'n' */ 0x00, // Disable %n format for kernel (ST_NORMAL|CH_OTHER)
  318. #else
  319. /* 'n' */ 0x08,
  320. #endif
  321. /* 'o' */ 0x08,
  322. /* 'p' */ 0x08,
  323. /* 'q' */ 0x00,
  324. /* 'r' */ 0x00,
  325. /* 's' */ 0x08,
  326. /* 't' */ 0x00,
  327. /* 'u' */ 0x08,
  328. /* 'v' */ 0x00,
  329. /* 'w' */ 0x07,
  330. /* '*' */ 0x08
  331. };
  332. #endif /* _UNICODE || CPRFLAG */
  333. #define find_char_class(c) \
  334. ((c) < _T(' ') || (c) > _T('x') ? \
  335. CH_OTHER \
  336. : \
  337. __lookuptable[(c)-_T(' ')] & 0xF)
  338. #define find_next_state(class, state) \
  339. (__lookuptable[(class) * NUMSTATES + (state)] >> 4)
  340. /*
  341. * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
  342. */
  343. /* prototypes */
  344. #ifdef CPRFLAG
  345. #define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
  346. #define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
  347. #define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
  348. #define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, pnw)
  349. LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
  350. LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
  351. LOCAL(void) write_string(_TCHAR *string, int len, int *numwritten);
  352. LOCAL(void) write_wstring(wchar_t *string, int len, int *numwritten);
  353. #else
  354. #define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
  355. #define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
  356. #define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
  357. #define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, stream, pnw)
  358. LOCAL(void) write_char(_TCHAR ch, FILE *f, int *pnumwritten);
  359. LOCAL(void) write_multi_char(_TCHAR ch, int num, FILE *f, int *pnumwritten);
  360. LOCAL(void) write_string(_TCHAR *string, int len, FILE *f, int *numwritten);
  361. LOCAL(void) write_wstring(wchar_t *string, int len, FILE *f, int *numwritten);
  362. #endif
  363. __inline int __cdecl get_int_arg(va_list *pargptr);
  364. #ifndef _UNICODE
  365. #if !SHORT_IS_INT
  366. __inline short __cdecl get_short_arg(va_list *pargptr);
  367. #endif
  368. #endif
  369. #if !LONG_IS_INT
  370. __inline long __cdecl get_long_arg(va_list *pargptr);
  371. #endif
  372. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  373. __inline __int64 __cdecl get_int64_arg(va_list *pargptr);
  374. #endif
  375. #ifdef CPRFLAG
  376. LOCAL(int) output(const _TCHAR *, va_list);
  377. /***
  378. *int _cprintf(format, arglist) - write formatted output directly to console
  379. *
  380. *Purpose:
  381. * Writes formatted data like printf, but uses console I/O functions.
  382. *
  383. *Entry:
  384. * char *format - format string to determine data formats
  385. * arglist - list of POINTERS to where to put data
  386. *
  387. *Exit:
  388. * returns number of characters written
  389. *
  390. *Exceptions:
  391. *
  392. *******************************************************************************/
  393. #ifdef _UNICODE
  394. int __cdecl _cwprintf (
  395. #else
  396. int __cdecl _cprintf (
  397. #endif
  398. const _TCHAR * format,
  399. ...
  400. )
  401. {
  402. va_list arglist;
  403. va_start(arglist, format);
  404. return output(format, arglist);
  405. }
  406. #endif /* CPRFLAG */
  407. /***
  408. *int _output(stream, format, argptr), static int output(format, argptr)
  409. *
  410. *Purpose:
  411. * Output performs printf style output onto a stream. It is called by
  412. * printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
  413. * work. In multi-thread situations, _output assumes that the given
  414. * stream is already locked.
  415. *
  416. * Algorithm:
  417. * The format string is parsed by using a finite state automaton
  418. * based on the current state and the current character read from
  419. * the format string. Thus, looping is on a per-character basis,
  420. * not a per conversion specifier basis. Once the format specififying
  421. * character is read, output is performed.
  422. *
  423. *Entry:
  424. * FILE *stream - stream for output
  425. * char *format - printf style format string
  426. * va_list argptr - pointer to list of subsidiary arguments
  427. *
  428. *Exit:
  429. * Returns the number of characters written, or -1 if an output error
  430. * occurs.
  431. *ifdef _UNICODE
  432. * The wide-character flavour returns the number of wide-characters written.
  433. *endif
  434. *
  435. *Exceptions:
  436. *
  437. *******************************************************************************/
  438. #ifdef CPRFLAG
  439. LOCAL(int) output (
  440. #else
  441. #ifdef _UNICODE
  442. int __cdecl _woutput (
  443. FILE *stream,
  444. #else
  445. int __cdecl _output (
  446. FILE *stream,
  447. #endif
  448. #endif
  449. const _TCHAR *format,
  450. va_list argptr
  451. )
  452. {
  453. int hexadd; /* offset to add to number to get 'a'..'f' */
  454. TCHAR ch; /* character just read */
  455. int flags; /* flag word -- see #defines above for flag values */
  456. enum STATE state; /* current state */
  457. enum CHARTYPE chclass; /* class of current character */
  458. int radix; /* current conversion radix */
  459. int charsout; /* characters currently written so far, -1 = IO error */
  460. int fldwidth; /* selected field width -- 0 means default */
  461. int precision; /* selected precision -- -1 means default */
  462. TCHAR prefix[2]; /* numeric prefix -- up to two characters */
  463. int prefixlen; /* length of prefix -- 0 means no prefix */
  464. int capexp; /* non-zero = 'E' exponent signifient, zero = 'e' */
  465. int no_output; /* non-zero = prodcue no output for this specifier */
  466. union {
  467. char *sz; /* pointer text to be printed, not zero terminated */
  468. wchar_t *wz;
  469. } text;
  470. int textlen; /* length of the text in bytes/wchars to be printed.
  471. textlen is in multibyte or wide chars if _UNICODE */
  472. union {
  473. char sz[BUFFERSIZE];
  474. #ifdef _UNICODE
  475. wchar_t wz[BUFFERSIZE];
  476. #endif
  477. } buffer;
  478. wchar_t wchar; /* temp wchar_t */
  479. int bufferiswide; /* non-zero = buffer contains wide chars already */
  480. #if !defined(_NTSUBSET_) && !defined(_POSIX_)
  481. char *heapbuf = NULL; /* non-zero = test.sz using heap buffer to be freed */
  482. #endif
  483. textlen = 0; /* no text yet */
  484. charsout = 0; /* no characters written yet */
  485. state = ST_NORMAL; /* starting state */
  486. /* main loop -- loop while format character exist and no I/O errors */
  487. while ((ch = *format++) != _T('\0') && charsout >= 0) {
  488. chclass = find_char_class(ch); /* find character class */
  489. state = find_next_state(chclass, state); /* find next state */
  490. /* execute code for each state */
  491. switch (state) {
  492. case ST_NORMAL:
  493. NORMAL_STATE:
  494. /* normal state -- just write character */
  495. #ifdef _UNICODE
  496. bufferiswide = 1;
  497. #else
  498. bufferiswide = 0;
  499. if (isleadbyte((int)(unsigned char)ch)) {
  500. WRITE_CHAR(ch, &charsout);
  501. ch = *format++;
  502. _ASSERTE (ch != _T('\0')); /* UNDONE: don't fall off format string */
  503. }
  504. #endif /* !_UNICODE */
  505. WRITE_CHAR(ch, &charsout);
  506. break;
  507. case ST_PERCENT:
  508. /* set default value of conversion parameters */
  509. prefixlen = fldwidth = no_output = capexp = 0;
  510. flags = 0;
  511. precision = -1;
  512. bufferiswide = 0; /* default */
  513. break;
  514. case ST_FLAG:
  515. /* set flag based on which flag character */
  516. switch (ch) {
  517. case _T('-'):
  518. flags |= FL_LEFT; /* '-' => left justify */
  519. break;
  520. case _T('+'):
  521. flags |= FL_SIGN; /* '+' => force sign indicator */
  522. break;
  523. case _T(' '):
  524. flags |= FL_SIGNSP; /* ' ' => force sign or space */
  525. break;
  526. case _T('#'):
  527. flags |= FL_ALTERNATE; /* '#' => alternate form */
  528. break;
  529. case _T('0'):
  530. flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
  531. break;
  532. }
  533. break;
  534. case ST_WIDTH:
  535. /* update width value */
  536. if (ch == _T('*')) {
  537. /* get width from arg list */
  538. fldwidth = get_int_arg(&argptr);
  539. if (fldwidth < 0) {
  540. /* ANSI says neg fld width means '-' flag and pos width */
  541. flags |= FL_LEFT;
  542. fldwidth = -fldwidth;
  543. }
  544. }
  545. else {
  546. /* add digit to current field width */
  547. fldwidth = fldwidth * 10 + (ch - _T('0'));
  548. }
  549. break;
  550. case ST_DOT:
  551. /* zero the precision, since dot with no number means 0
  552. not default, according to ANSI */
  553. precision = 0;
  554. break;
  555. case ST_PRECIS:
  556. /* update precison value */
  557. if (ch == _T('*')) {
  558. /* get precision from arg list */
  559. precision = get_int_arg(&argptr);
  560. if (precision < 0)
  561. precision = -1; /* neg precision means default */
  562. }
  563. else {
  564. /* add digit to current precision */
  565. precision = precision * 10 + (ch - _T('0'));
  566. }
  567. break;
  568. case ST_SIZE:
  569. /* just read a size specifier, set the flags based on it */
  570. switch (ch) {
  571. case _T('l'):
  572. flags |= FL_LONG; /* 'l' => long int or wchar_t */
  573. break;
  574. case _T('I'):
  575. /*
  576. * In order to handle the I, I32, and I64 size modifiers, we
  577. * depart from the simple deterministic state machine. The
  578. * code below scans for characters following the 'I',
  579. * and defaults to 64 bit on WIN64 and 32 bit on WIN32
  580. */
  581. #if PTR_IS_INT64
  582. flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
  583. #endif
  584. if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
  585. {
  586. format += 2;
  587. flags |= FL_I64; /* I64 => __int64 */
  588. }
  589. else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
  590. {
  591. format += 2;
  592. flags &= ~FL_I64; /* I32 => __int32 */
  593. }
  594. else if ( (*format == _T('d')) ||
  595. (*format == _T('i')) ||
  596. (*format == _T('o')) ||
  597. (*format == _T('u')) ||
  598. (*format == _T('x')) ||
  599. (*format == _T('X')) )
  600. {
  601. /*
  602. * Nothing further needed. %Id (et al) is
  603. * handled just like %d, except that it defaults to 64 bits
  604. * on WIN64. Fall through to the next iteration.
  605. */
  606. }
  607. else {
  608. state = ST_NORMAL;
  609. goto NORMAL_STATE;
  610. }
  611. break;
  612. case _T('h'):
  613. flags |= FL_SHORT; /* 'h' => short int or char */
  614. break;
  615. /* UNDONE: support %wc and %ws for now only for compatibility */
  616. case _T('w'):
  617. flags |= FL_WIDECHAR; /* 'w' => wide character */
  618. break;
  619. }
  620. break;
  621. case ST_TYPE:
  622. /* we have finally read the actual type character, so we */
  623. /* now format and "print" the output. We use a big switch */
  624. /* statement that sets 'text' to point to the text that should */
  625. /* be printed, and 'textlen' to the length of this text. */
  626. /* Common code later on takes care of justifying it and */
  627. /* other miscellaneous chores. Note that cases share code, */
  628. /* in particular, all integer formatting is done in one place. */
  629. /* Look at those funky goto statements! */
  630. switch (ch) {
  631. case _T('C'): /* ISO wide character */
  632. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  633. #ifdef _UNICODE
  634. flags |= FL_SHORT;
  635. #else
  636. flags |= FL_WIDECHAR; /* ISO std. */
  637. #endif
  638. /* fall into 'c' case */
  639. case _T('c'): {
  640. /* print a single character specified by int argument */
  641. #ifdef _UNICODE
  642. bufferiswide = 1;
  643. wchar = (wchar_t) get_int_arg(&argptr);
  644. if (flags & FL_SHORT) {
  645. /* format multibyte character */
  646. /* this is an extension of ANSI */
  647. char tempchar[2];
  648. #ifdef _OUT
  649. if (isleadbyte(wchar >> 8)) {
  650. tempchar[0] = (wchar >> 8);
  651. tempchar[1] = (wchar & 0x00ff);
  652. }
  653. else
  654. #endif /* _OUT */
  655. {
  656. tempchar[0] = (char)(wchar & 0x00ff);
  657. tempchar[1] = '\0';
  658. }
  659. if (mbtowc(buffer.wz,tempchar,MB_CUR_MAX) < 0) {
  660. /* ignore if conversion was unsuccessful */
  661. no_output = 1;
  662. }
  663. } else {
  664. buffer.wz[0] = wchar;
  665. }
  666. text.wz = buffer.wz;
  667. textlen = 1; /* print just a single character */
  668. #else /* _UNICODE */
  669. if (flags & (FL_LONG|FL_WIDECHAR)) {
  670. wchar = (wchar_t) get_short_arg(&argptr);
  671. /* convert to multibyte character */
  672. textlen = wctomb(buffer.sz, wchar);
  673. /* check that conversion was successful */
  674. if (textlen < 0)
  675. no_output = 1;
  676. } else {
  677. /* format multibyte character */
  678. /* this is an extension of ANSI */
  679. unsigned short temp;
  680. temp = (unsigned short) get_int_arg(&argptr);
  681. #ifdef _OUT
  682. if (isleadbyte(temp >> 8)) {
  683. buffer.sz[0] = temp >> 8;
  684. buffer.sz[1] = temp & 0x00ff;
  685. textlen = 2;
  686. } else
  687. #endif /* _OUT */
  688. {
  689. buffer.sz[0] = (char) temp;
  690. textlen = 1;
  691. }
  692. }
  693. text.sz = buffer.sz;
  694. #endif /* _UNICODE */
  695. }
  696. break;
  697. case _T('Z'): {
  698. /* print a Counted String
  699. int i;
  700. char *p; /* temps */
  701. struct _count_string {
  702. short Length;
  703. short MaximumLength;
  704. char *Buffer;
  705. } *pstr;
  706. pstr = get_ptr_arg(&argptr);
  707. if (pstr == NULL || pstr->Buffer == NULL) {
  708. /* null ptr passed, use special string */
  709. text.sz = __nullstring;
  710. textlen = (int)strlen(text.sz);
  711. } else {
  712. if (flags & FL_WIDECHAR) {
  713. text.wz = (wchar_t *)pstr->Buffer;
  714. textlen = pstr->Length / (int)sizeof(wchar_t);
  715. bufferiswide = 1;
  716. } else {
  717. bufferiswide = 0;
  718. text.sz = pstr->Buffer;
  719. textlen = pstr->Length;
  720. }
  721. }
  722. }
  723. break;
  724. case _T('S'): /* ISO wide character string */
  725. #ifndef _UNICODE
  726. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  727. flags |= FL_WIDECHAR;
  728. #else
  729. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  730. flags |= FL_SHORT;
  731. #endif
  732. case _T('s'): {
  733. /* print a string -- */
  734. /* ANSI rules on how much of string to print: */
  735. /* all if precision is default, */
  736. /* min(precision, length) if precision given. */
  737. /* prints '(null)' if a null string is passed */
  738. int i;
  739. char *p; /* temps */
  740. wchar_t *pwch;
  741. /* At this point it is tempting to use strlen(), but */
  742. /* if a precision is specified, we're not allowed to */
  743. /* scan past there, because there might be no null */
  744. /* at all. Thus, we must do our own scan. */
  745. i = (precision == -1) ? INT_MAX : precision;
  746. text.sz = get_ptr_arg(&argptr);
  747. /* UNDONE: handle '#' case properly */
  748. /* scan for null upto i characters */
  749. #ifdef _UNICODE
  750. if (flags & FL_SHORT) {
  751. if (text.sz == NULL) /* NULL passed, use special string */
  752. text.sz = __nullstring;
  753. p = text.sz;
  754. for (textlen=0; textlen<i && *p; textlen++) {
  755. if (isleadbyte((int)*p))
  756. ++p;
  757. ++p;
  758. }
  759. /* textlen now contains length in multibyte chars */
  760. } else {
  761. if (text.wz == NULL) /* NULL passed, use special string */
  762. text.wz = __wnullstring;
  763. bufferiswide = 1;
  764. pwch = text.wz;
  765. while (i-- && *pwch)
  766. ++pwch;
  767. textlen = (int)(pwch - text.wz); /* in wchar_ts */
  768. /* textlen now contains length in wide chars */
  769. }
  770. #else /* _UNICODE */
  771. if (flags & (FL_LONG|FL_WIDECHAR)) {
  772. if (text.wz == NULL) /* NULL passed, use special string */
  773. text.wz = __wnullstring;
  774. bufferiswide = 1;
  775. pwch = text.wz;
  776. while ( i-- && *pwch )
  777. ++pwch;
  778. textlen = (int)(pwch - text.wz);
  779. /* textlen now contains length in wide chars */
  780. } else {
  781. if (text.sz == NULL) /* NULL passed, use special string */
  782. text.sz = __nullstring;
  783. p = text.sz;
  784. while (i-- && *p)
  785. ++p;
  786. textlen = (int)(p - text.sz); /* length of the string */
  787. }
  788. #endif /* _UNICODE */
  789. }
  790. break;
  791. case _T('n'): {
  792. /* write count of characters seen so far into */
  793. /* short/int/long thru ptr read from args */
  794. void *p; /* temp */
  795. p = get_ptr_arg(&argptr);
  796. /* store chars out into short/long/int depending on flags */
  797. #if !LONG_IS_INT
  798. if (flags & FL_LONG)
  799. *(long *)p = charsout;
  800. else
  801. #endif
  802. #if !SHORT_IS_INT
  803. if (flags & FL_SHORT)
  804. *(short *)p = (short) charsout;
  805. else
  806. #endif
  807. *(int *)p = charsout;
  808. no_output = 1; /* force no output */
  809. }
  810. break;
  811. case _T('E'):
  812. case _T('G'):
  813. capexp = 1; /* capitalize exponent */
  814. ch += _T('a') - _T('A'); /* convert format char to lower */
  815. /* DROP THROUGH */
  816. case _T('e'):
  817. case _T('f'):
  818. case _T('g'): {
  819. /* floating point conversion -- we call cfltcvt routines */
  820. /* to do the work for us. */
  821. flags |= FL_SIGNED; /* floating point is signed conversion */
  822. text.sz = buffer.sz; /* put result in buffer */
  823. /* compute the precision value */
  824. if (precision < 0)
  825. precision = 6; /* default precision: 6 */
  826. else if (precision == 0 && ch == _T('g'))
  827. precision = 1; /* ANSI specified */
  828. else if (precision > MAXPRECISION)
  829. precision = MAXPRECISION;
  830. if (precision > BUFFERSIZE - CVTBUFSIZE) {
  831. #if !defined(_NTSUBSET_) && !defined(_POSIX_)
  832. /* conversion will potentially overflow local buffer */
  833. /* so we need to use a heap-allocated buffer. */
  834. heapbuf = (char *)_malloc_crt(CVTBUFSIZE + precision);
  835. if (heapbuf != NULL)
  836. text.sz = heapbuf;
  837. else
  838. /* malloc failed, cap precision further */
  839. #endif
  840. precision = BUFFERSIZE - CVTBUFSIZE;
  841. }
  842. #if !LONGDOUBLE_IS_DOUBLE
  843. /* do the conversion */
  844. if (flags & FL_LONGDOUBLE) {
  845. LONGDOUBLE tmp;
  846. tmp=va_arg(argptr, LONGDOUBLE);
  847. /* Note: assumes ch is in ASCII range */
  848. _cldcvt(&tmp, text.sz, (char)ch, precision, capexp);
  849. } else
  850. #endif
  851. {
  852. DOUBLE tmp;
  853. tmp=va_arg(argptr, DOUBLE);
  854. /* Note: assumes ch is in ASCII range */
  855. _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
  856. }
  857. /* '#' and precision == 0 means force a decimal point */
  858. if ((flags & FL_ALTERNATE) && precision == 0)
  859. _forcdecpt(text.sz);
  860. /* 'g' format means crop zero unless '#' given */
  861. if (ch == _T('g') && !(flags & FL_ALTERNATE))
  862. _cropzeros(text.sz);
  863. /* check if result was negative, save '-' for later */
  864. /* and point to positive part (this is for '0' padding) */
  865. if (*text.sz == '-') {
  866. flags |= FL_NEGATIVE;
  867. ++text.sz;
  868. }
  869. textlen = (int)strlen(text.sz); /* compute length of text */
  870. }
  871. break;
  872. case _T('d'):
  873. case _T('i'):
  874. /* signed decimal output */
  875. flags |= FL_SIGNED;
  876. radix = 10;
  877. goto COMMON_INT;
  878. case _T('u'):
  879. radix = 10;
  880. goto COMMON_INT;
  881. case _T('p'):
  882. /* write a pointer -- this is like an integer or long */
  883. /* except we force precision to pad with zeros and */
  884. /* output in big hex. */
  885. precision = 2 * sizeof(void *); /* number of hex digits needed */
  886. #if PTR_IS_INT64
  887. flags |= FL_I64; /* assume we're converting an int64 */
  888. #elif !PTR_IS_INT
  889. flags |= FL_LONG; /* assume we're converting a long */
  890. #endif
  891. /* DROP THROUGH to hex formatting */
  892. case _T('X'):
  893. /* unsigned upper hex output */
  894. hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
  895. goto COMMON_HEX;
  896. case _T('x'):
  897. /* unsigned lower hex output */
  898. hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
  899. /* DROP THROUGH TO COMMON_HEX */
  900. COMMON_HEX:
  901. radix = 16;
  902. if (flags & FL_ALTERNATE) {
  903. /* alternate form means '0x' prefix */
  904. prefix[0] = _T('0');
  905. prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
  906. prefixlen = 2;
  907. }
  908. goto COMMON_INT;
  909. case _T('o'):
  910. /* unsigned octal output */
  911. radix = 8;
  912. if (flags & FL_ALTERNATE) {
  913. /* alternate form means force a leading 0 */
  914. flags |= FL_FORCEOCTAL;
  915. }
  916. /* DROP THROUGH to COMMON_INT */
  917. COMMON_INT: {
  918. /* This is the general integer formatting routine. */
  919. /* Basically, we get an argument, make it positive */
  920. /* if necessary, and convert it according to the */
  921. /* correct radix, setting text and textlen */
  922. /* appropriately. */
  923. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  924. unsigned __int64 number; /* number to convert */
  925. int digit; /* ascii value of digit */
  926. __int64 l; /* temp long value */
  927. #else
  928. unsigned long number; /* number to convert */
  929. int digit; /* ascii value of digit */
  930. long l; /* temp long value */
  931. #endif
  932. /* 1. read argument into l, sign extend as needed */
  933. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  934. if (flags & FL_I64)
  935. l = get_int64_arg(&argptr);
  936. else
  937. #endif
  938. #if !LONG_IS_INT
  939. if (flags & FL_LONG)
  940. l = get_long_arg(&argptr);
  941. else
  942. #endif
  943. #if !SHORT_IS_INT
  944. if (flags & FL_SHORT) {
  945. if (flags & FL_SIGNED)
  946. l = (short) get_int_arg(&argptr); /* sign extend */
  947. else
  948. l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
  949. } else
  950. #endif
  951. {
  952. if (flags & FL_SIGNED)
  953. l = get_int_arg(&argptr); /* sign extend */
  954. else
  955. l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
  956. }
  957. /* 2. check for negative; copy into number */
  958. if ( (flags & FL_SIGNED) && l < 0) {
  959. number = -l;
  960. flags |= FL_NEGATIVE; /* remember negative sign */
  961. } else {
  962. number = l;
  963. }
  964. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  965. if ( (flags & FL_I64) == 0 ) {
  966. /*
  967. * Unless printing a full 64-bit value, insure values
  968. * here are not in cananical longword format to prevent
  969. * the sign extended upper 32-bits from being printed.
  970. */
  971. number &= 0xffffffff;
  972. }
  973. #endif
  974. /* 3. check precision value for default; non-default */
  975. /* turns off 0 flag, according to ANSI. */
  976. if (precision < 0)
  977. precision = 1; /* default precision */
  978. else {
  979. flags &= ~FL_LEADZERO;
  980. if (precision > MAXPRECISION)
  981. precision = MAXPRECISION;
  982. }
  983. /* 4. Check if data is 0; if so, turn off hex prefix */
  984. if (number == 0)
  985. prefixlen = 0;
  986. /* 5. Convert data to ASCII -- note if precision is zero */
  987. /* and number is zero, we get no digits at all. */
  988. text.sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
  989. while (precision-- > 0 || number != 0) {
  990. digit = (int)(number % radix) + '0';
  991. number /= radix; /* reduce number */
  992. if (digit > '9') {
  993. /* a hex digit, make it a letter */
  994. digit += hexadd;
  995. }
  996. *text.sz-- = (char)digit; /* store the digit */
  997. }
  998. textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - text.sz); /* compute length of number */
  999. ++text.sz; /* text points to first digit now */
  1000. /* 6. Force a leading zero if FORCEOCTAL flag set */
  1001. if ((flags & FL_FORCEOCTAL) && (text.sz[0] != '0' || textlen == 0)) {
  1002. *--text.sz = '0';
  1003. ++textlen; /* add a zero */
  1004. }
  1005. }
  1006. break;
  1007. }
  1008. /* At this point, we have done the specific conversion, and */
  1009. /* 'text' points to text to print; 'textlen' is length. Now we */
  1010. /* justify it, put on prefixes, leading zeros, and then */
  1011. /* print it. */
  1012. if (!no_output) {
  1013. int padding; /* amount of padding, negative means zero */
  1014. if (flags & FL_SIGNED) {
  1015. if (flags & FL_NEGATIVE) {
  1016. /* prefix is a '-' */
  1017. prefix[0] = _T('-');
  1018. prefixlen = 1;
  1019. }
  1020. else if (flags & FL_SIGN) {
  1021. /* prefix is '+' */
  1022. prefix[0] = _T('+');
  1023. prefixlen = 1;
  1024. }
  1025. else if (flags & FL_SIGNSP) {
  1026. /* prefix is ' ' */
  1027. prefix[0] = _T(' ');
  1028. prefixlen = 1;
  1029. }
  1030. }
  1031. /* calculate amount of padding -- might be negative, */
  1032. /* but this will just mean zero */
  1033. padding = fldwidth - textlen - prefixlen;
  1034. /* put out the padding, prefix, and text, in the correct order */
  1035. if (!(flags & (FL_LEFT | FL_LEADZERO))) {
  1036. /* pad on left with blanks */
  1037. WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  1038. }
  1039. /* write prefix */
  1040. WRITE_STRING(prefix, prefixlen, &charsout);
  1041. if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
  1042. /* write leading zeros */
  1043. WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
  1044. }
  1045. /* write text */
  1046. #ifndef _UNICODE
  1047. if (bufferiswide && (textlen > 0)) {
  1048. wchar_t *p;
  1049. int retval, count;
  1050. char buffer[MB_LEN_MAX+1];
  1051. p = text.wz;
  1052. count = textlen;
  1053. while (count--) {
  1054. retval = wctomb(buffer, *p++);
  1055. if (retval <= 0)
  1056. break;
  1057. WRITE_STRING(buffer, retval, &charsout);
  1058. }
  1059. } else {
  1060. WRITE_STRING(text.sz, textlen, &charsout);
  1061. }
  1062. #else
  1063. if (!bufferiswide && textlen > 0) {
  1064. char *p;
  1065. int retval, count;
  1066. p = text.sz;
  1067. count = textlen;
  1068. while (count-- > 0) {
  1069. retval = mbtowc(&wchar, p, MB_CUR_MAX);
  1070. if (retval <= 0)
  1071. break;
  1072. WRITE_CHAR(wchar, &charsout);
  1073. p += retval;
  1074. }
  1075. } else {
  1076. WRITE_STRING(text.wz, textlen, &charsout);
  1077. }
  1078. #endif /* _UNICODE */
  1079. if (flags & FL_LEFT) {
  1080. /* pad on right with blanks */
  1081. WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  1082. }
  1083. /* we're done! */
  1084. }
  1085. #if !defined(_NTSUBSET_) && !defined(_POSIX_)
  1086. if (heapbuf) {
  1087. _free_crt(heapbuf);
  1088. heapbuf = NULL;
  1089. }
  1090. #endif
  1091. break;
  1092. }
  1093. }
  1094. return charsout; /* return value = number of characters written */
  1095. }
  1096. /*
  1097. * Future Optimizations for swprintf:
  1098. * - Don't free the memory used for converting the buffer to wide chars.
  1099. * Use realloc if the memory is not sufficient. Free it at the end.
  1100. */
  1101. /***
  1102. *void write_char(char ch, int *pnumwritten)
  1103. *ifdef _UNICODE
  1104. *void write_char(wchar_t ch, FILE *f, int *pnumwritten)
  1105. *endif
  1106. *void write_char(char ch, FILE *f, int *pnumwritten)
  1107. *
  1108. *Purpose:
  1109. * Writes a single character to the given file/console. If no error occurs,
  1110. * then *pnumwritten is incremented; otherwise, *pnumwritten is set
  1111. * to -1.
  1112. *
  1113. *Entry:
  1114. * _TCHAR ch - character to write
  1115. * FILE *f - file to write to
  1116. * int *pnumwritten - pointer to integer to update with total chars written
  1117. *
  1118. *Exit:
  1119. * No return value.
  1120. *
  1121. *Exceptions:
  1122. *
  1123. *******************************************************************************/
  1124. #ifdef CPRFLAG
  1125. LOCAL(void) write_char (
  1126. _TCHAR ch,
  1127. int *pnumwritten
  1128. )
  1129. {
  1130. #ifdef _UNICODE
  1131. if (_putwch_lk(ch) == WEOF)
  1132. #else
  1133. if (_putch_lk(ch) == EOF)
  1134. #endif //_UNICODE
  1135. *pnumwritten = -1;
  1136. else
  1137. ++(*pnumwritten);
  1138. }
  1139. #else
  1140. LOCAL(void) write_char (
  1141. _TCHAR ch,
  1142. FILE *f,
  1143. int *pnumwritten
  1144. )
  1145. {
  1146. if ( (f->_flag & _IOSTRG) && f->_base == NULL)
  1147. {
  1148. ++(*pnumwritten);
  1149. return;
  1150. }
  1151. #ifdef _UNICODE
  1152. if (_putwc_lk(ch, f) == WEOF)
  1153. #else
  1154. if (_putc_lk(ch, f) == EOF)
  1155. #endif //_UNICODE
  1156. *pnumwritten = -1;
  1157. else
  1158. ++(*pnumwritten);
  1159. }
  1160. #endif
  1161. /***
  1162. *void write_multi_char(char ch, int num, int *pnumwritten)
  1163. *ifdef _UNICODE
  1164. *void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
  1165. *endif
  1166. *void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
  1167. *
  1168. *Purpose:
  1169. * Writes num copies of a character to the given file/console. If no error occurs,
  1170. * then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
  1171. * to -1. If num is negative, it is treated as zero.
  1172. *
  1173. *Entry:
  1174. * _TCHAR ch - character to write
  1175. * int num - number of times to write the characters
  1176. * FILE *f - file to write to
  1177. * int *pnumwritten - pointer to integer to update with total chars written
  1178. *
  1179. *Exit:
  1180. * No return value.
  1181. *
  1182. *Exceptions:
  1183. *
  1184. *******************************************************************************/
  1185. #ifdef CPRFLAG
  1186. LOCAL(void) write_multi_char (
  1187. _TCHAR ch,
  1188. int num,
  1189. int *pnumwritten
  1190. )
  1191. {
  1192. while (num-- > 0) {
  1193. write_char(ch, pnumwritten);
  1194. if (*pnumwritten == -1)
  1195. break;
  1196. }
  1197. }
  1198. #else /* CPRFLAG */
  1199. LOCAL(void) write_multi_char (
  1200. _TCHAR ch,
  1201. int num,
  1202. FILE *f,
  1203. int *pnumwritten
  1204. )
  1205. {
  1206. while (num-- > 0) {
  1207. write_char(ch, f, pnumwritten);
  1208. if (*pnumwritten == -1)
  1209. break;
  1210. }
  1211. }
  1212. #endif /* CPRFLAG */
  1213. /***
  1214. *void write_string(char *string, int len, int *pnumwritten)
  1215. *void write_string(char *string, int len, FILE *f, int *pnumwritten)
  1216. *ifdef _UNICODE
  1217. *void write_string(wchar_t *string, int len, FILE *f, int *pnumwritten)
  1218. *endif
  1219. *void write_wstring(wchar_t *string, int len, int *pnumwritten)
  1220. *void write_wstring(wchar_t *string, int len, FILE *f, int *pnumwritten)
  1221. *
  1222. *Purpose:
  1223. * Writes a string of the given length to the given file. If no error occurs,
  1224. * then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
  1225. * to -1. If len is negative, it is treated as zero.
  1226. *
  1227. *Entry:
  1228. * _TCHAR *string - string to write (NOT null-terminated)
  1229. * int len - length of string
  1230. * FILE *f - file to write to
  1231. * int *pnumwritten - pointer to integer to update with total chars written
  1232. *
  1233. *Exit:
  1234. * No return value.
  1235. *
  1236. *Exceptions:
  1237. *
  1238. *******************************************************************************/
  1239. #ifdef CPRFLAG
  1240. LOCAL(void) write_string (
  1241. _TCHAR *string,
  1242. int len,
  1243. int *pnumwritten
  1244. )
  1245. {
  1246. while (len-- > 0) {
  1247. write_char(*string++, pnumwritten);
  1248. if (*pnumwritten == -1)
  1249. break;
  1250. }
  1251. }
  1252. #else /* CPRFLAG */
  1253. LOCAL(void) write_string (
  1254. _TCHAR *string,
  1255. int len,
  1256. FILE *f,
  1257. int *pnumwritten
  1258. )
  1259. {
  1260. if ( (f->_flag & _IOSTRG) && f->_base == NULL)
  1261. {
  1262. (*pnumwritten) += len;
  1263. return;
  1264. }
  1265. while (len-- > 0) {
  1266. write_char(*string++, f, pnumwritten);
  1267. if (*pnumwritten == -1)
  1268. break;
  1269. }
  1270. }
  1271. #endif /* CPRFLAG */
  1272. /***
  1273. *int get_int_arg(va_list *pargptr)
  1274. *
  1275. *Purpose:
  1276. * Gets an int argument off the given argument list and updates *pargptr.
  1277. *
  1278. *Entry:
  1279. * va_list *pargptr - pointer to argument list; updated by function
  1280. *
  1281. *Exit:
  1282. * Returns the integer argument read from the argument list.
  1283. *
  1284. *Exceptions:
  1285. *
  1286. *******************************************************************************/
  1287. __inline int __cdecl get_int_arg (
  1288. va_list *pargptr
  1289. )
  1290. {
  1291. return va_arg(*pargptr, int);
  1292. }
  1293. /***
  1294. *long get_long_arg(va_list *pargptr)
  1295. *
  1296. *Purpose:
  1297. * Gets an long argument off the given argument list and updates *pargptr.
  1298. *
  1299. *Entry:
  1300. * va_list *pargptr - pointer to argument list; updated by function
  1301. *
  1302. *Exit:
  1303. * Returns the long argument read from the argument list.
  1304. *
  1305. *Exceptions:
  1306. *
  1307. *******************************************************************************/
  1308. #if !LONG_IS_INT
  1309. __inline long __cdecl get_long_arg (
  1310. va_list *pargptr
  1311. )
  1312. {
  1313. return va_arg(*pargptr, long);
  1314. }
  1315. #endif
  1316. #if _INTEGRAL_MAX_BITS >= 64 /*IFSTRIP=IGN*/
  1317. __inline __int64 __cdecl get_int64_arg (
  1318. va_list *pargptr
  1319. )
  1320. {
  1321. return va_arg(*pargptr, __int64);
  1322. }
  1323. #endif
  1324. #ifndef _UNICODE
  1325. /***
  1326. *short get_short_arg(va_list *pargptr)
  1327. *
  1328. *Purpose:
  1329. * Gets a short argument off the given argument list and updates *pargptr.
  1330. * *** CURRENTLY ONLY USED TO GET A WCHAR_T, IFDEF _INTL ***
  1331. *
  1332. *Entry:
  1333. * va_list *pargptr - pointer to argument list; updated by function
  1334. *
  1335. *Exit:
  1336. * Returns the short argument read from the argument list.
  1337. *
  1338. *Exceptions:
  1339. *
  1340. *******************************************************************************/
  1341. #if !SHORT_IS_INT
  1342. __inline short __cdecl get_short_arg (
  1343. va_list *pargptr
  1344. )
  1345. {
  1346. return va_arg(*pargptr, short);
  1347. }
  1348. #endif
  1349. #endif