Leaked source code of windows server 2003
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.

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