output.inl 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744
  1. //
  2. // Copyright (c) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  4. //
  5. /***
  6. *output.c - printf style output to a FILE
  7. *
  8. *
  9. *Purpose:
  10. * This file contains the code that does all the work for the
  11. * printf family of functions. It should not be called directly, only
  12. * by the *printf functions. We don't make any assumtions about the
  13. * sizes of ints, longs, shorts, or long doubles, but if types do overlap,
  14. * we also try to be efficient. We do assume that pointers are the same
  15. * size as either ints or longs.
  16. * If CPRFLAG is defined, defines _cprintf instead.
  17. * **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
  18. *
  19. *Note:
  20. * this file is included in safecrt.lib build directly, plese refer
  21. * to safecrt_[w]output_s.c
  22. *
  23. *******************************************************************************/
  24. //typedef __int64_t __int64;
  25. #define FORMAT_VALIDATIONS
  26. typedef double _CRT_DOUBLE;
  27. //typedef int* intptr_t;
  28. /*
  29. Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines
  30. */
  31. #define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
  32. /* temporary work-around for compiler without 64-bit support */
  33. #ifndef _INTEGRAL_MAX_BITS
  34. #define _INTEGRAL_MAX_BITS 64
  35. #endif /* _INTEGRAL_MAX_BITS */
  36. //#include <mtdll.h>
  37. //#include <cruntime.h>
  38. //#include <limits.h>
  39. //#include <string.h>
  40. //#include <stddef.h>
  41. //#include <crtdefs.h>
  42. //#include <stdio.h>
  43. //#include <stdarg.h>
  44. //#include <cvt.h>
  45. //#include <conio.h>
  46. //#include <internal.h>
  47. //#include <fltintrn.h>
  48. //#include <stdlib.h>
  49. //#include <ctype.h>
  50. //#include <dbgint.h>
  51. //#include <setlocal.h>
  52. #define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
  53. #ifndef _WCTOMB_S
  54. #define _WCTOMB_S wctomb_s
  55. #endif /* _WCTOMB_S */
  56. #undef _malloc_crt
  57. #define _malloc_crt malloc
  58. #undef _free_crt
  59. #define _free_crt free
  60. /* Wrapper for _output_s so that we do not expose FILE in the _output_s signature.
  61. * Always ensure null-termination. Returns the number of written chars, not including the terminating null.
  62. * Returns -1 if something went wrong during the formatting (in _output_s), e.g. mbcs conversions.
  63. * Returns -2 if the string has been truncated.
  64. * _output_s calls _invalid_parameter (and returns -1, possibly) if the format string is malformed.
  65. */
  66. #ifndef _UNICODE
  67. int __cdecl _soutput_s(char *_Dst, size_t _Size, const char *_Format, va_list _ArgList)
  68. #else /* _UNICODE */
  69. int __cdecl _swoutput_s(char16_t *_Dst, size_t _Size, const char16_t *_Format, va_list _ArgList)
  70. #endif /* _UNICODE */
  71. {
  72. miniFILE stream;
  73. miniFILE *outfile = &stream;
  74. int written = -1;
  75. /* validation section */
  76. #ifndef _UNICODE
  77. if(_Size==SIZE_MAX)
  78. {
  79. /* user is attempting to make us unbounded, but we don't fit that much */
  80. outfile->_cnt = INT_MAX;
  81. }
  82. else
  83. {
  84. _VALIDATE_RETURN(_Size <= INT_MAX, EINVAL, -1);
  85. outfile->_cnt = (int)_Size;
  86. }
  87. outfile->_ptr = outfile->_base = _Dst;
  88. #else /* _UNICODE */
  89. if(_Size==SIZE_MAX)
  90. {
  91. /* user is attempting to make us unbounded, but we don't fit that much */
  92. outfile->_cnt = INT_MAX;
  93. }
  94. else if(_Size>(INT_MAX/sizeof(char16_t)))
  95. {
  96. /* we can't represent the amount of output the user asked for */
  97. _VALIDATE_RETURN( 0 /* FALSE */, EINVAL, -1 );
  98. }
  99. else
  100. {
  101. outfile->_cnt = (int)(_Size*sizeof(char16_t));
  102. }
  103. outfile->_ptr = outfile->_base = (char*)_Dst;
  104. #endif /* _UNICODE */
  105. outfile->_flag = _IOWRT | _IOSTRG;
  106. #ifndef _UNICODE
  107. written = _output_s(outfile, _Format, _ArgList);
  108. #else /* _UNICODE */
  109. written = _woutput_s(outfile, _Format, _ArgList);
  110. #endif /* _UNICODE */
  111. _Dst[_Size - 1] = 0;
  112. if (written < 0)
  113. {
  114. if (outfile->_cnt < 0)
  115. {
  116. /* the buffer was too small; we return -2 to indicate truncation */
  117. return -2;
  118. }
  119. /* otherwise, something else failed: we reset the string and we return */
  120. if (_Dst != NULL && _Size > 0)
  121. {
  122. *_Dst = 0;
  123. }
  124. return written;
  125. }
  126. #ifndef _UNICODE
  127. if ((_putc_nolock('\0', outfile) != EOF))
  128. #else /* _UNICODE */
  129. if ((_putc_nolock('\0', outfile) != EOF) && (_putc_nolock('\0', outfile) != EOF))
  130. #endif /* _UNICODE */
  131. {
  132. return written;
  133. }
  134. /* the last putc failed, so it means there is not enough space in the buffer */
  135. return -2;
  136. }
  137. #ifndef _CFLTCVT
  138. #define _CFLTCVT _cfltcvt
  139. #endif /* _CFLTCVT */
  140. #ifndef _CLDCVT
  141. #define _CLDCVT _cldcvt
  142. #endif /* _CLDCVT */
  143. #ifdef _MBCS
  144. #undef _MBCS
  145. #endif /* _MBCS */
  146. //#include <tchar.h>
  147. /* this macro defines a function which is private and as fast as possible: */
  148. /* for example, in C 6.0, it might be static _fastcall <type> near. */
  149. #define LOCAL(x) static x __cdecl
  150. /* int/long/short/pointer sizes */
  151. /* the following should be set depending on the sizes of various types */
  152. #if __LP64__
  153. #define LONG_IS_INT 0
  154. CASSERT(sizeof(long) > sizeof(int));
  155. #else
  156. #define LONG_IS_INT 1 /* 1 means long is same size as int */
  157. CASSERT(sizeof(long) == sizeof(int));
  158. #endif
  159. #define SHORT_IS_INT 0 /* 1 means short is same size as int */
  160. #define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
  161. #if defined (_WIN64)
  162. #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
  163. CASSERT(sizeof(void *) != sizeof(int));
  164. #if __LP64__
  165. #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
  166. CASSERT(sizeof(void *) == sizeof(long));
  167. #else
  168. #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
  169. CASSERT(sizeof(void *) != sizeof(long));
  170. #endif
  171. #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
  172. CASSERT(sizeof(void *) == sizeof(int64_t));
  173. #else /* defined (_WIN64) */
  174. #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
  175. CASSERT(sizeof(void *) == sizeof(int));
  176. #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
  177. CASSERT(sizeof(void *) == sizeof(long));
  178. #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
  179. #ifndef __APPLE__
  180. // todo : investigate
  181. CASSERT(sizeof(void *) != sizeof(int64_t));
  182. #endif
  183. #endif /* defined (_WIN64) */
  184. #ifndef __GNUC_VA_LIST
  185. #if LONGLONG_IS_INT64
  186. #define get_long_long_arg(x) (long long)get_int64_arg(x)
  187. #endif /* LONGLONG_IS_INT64 */
  188. #if LONG_IS_INT
  189. #define get_long_arg(x) (long)get_int_arg(x)
  190. #endif /* LONG_IS_INT */
  191. #if PTR_IS_INT
  192. #define get_ptr_arg(x) (void *)(intptr_t)get_int_arg(x)
  193. #elif PTR_IS_LONG
  194. #define get_ptr_arg(x) (void *)(intptr_t)get_long_arg(x)
  195. #elif PTR_IS_INT64
  196. #define get_ptr_arg(x) (void *)get_int64_arg(x)
  197. #else /* PTR_IS_INT64 */
  198. #error Size of pointer must be same as size of int or long
  199. #endif /* PTR_IS_INT64 */
  200. #endif // __GNUC_VA_LIST
  201. /* CONSTANTS */
  202. /* size of conversion buffer (ANSI-specified minimum is 509) */
  203. #define BUFFERSIZE 512
  204. #define MAXPRECISION BUFFERSIZE
  205. #if BUFFERSIZE < _CVTBUFSIZE + 6
  206. /*
  207. * Buffer needs to be big enough for default minimum precision
  208. * when converting floating point needs bigger buffer, and malloc
  209. * fails
  210. */
  211. #error Conversion buffer too small for max double.
  212. #endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */
  213. /* flag definitions */
  214. #define FL_SIGN 0x00001 /* put plus or minus in front */
  215. #define FL_SIGNSP 0x00002 /* put space or minus in front */
  216. #define FL_LEFT 0x00004 /* left justify */
  217. #define FL_LEADZERO 0x00008 /* pad with leading zeros */
  218. #define FL_LONG 0x00010 /* long value given */
  219. #define FL_SHORT 0x00020 /* short value given */
  220. #define FL_SIGNED 0x00040 /* signed data given */
  221. #define FL_ALTERNATE 0x00080 /* alternate form requested */
  222. #define FL_NEGATIVE 0x00100 /* value is negative */
  223. #define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
  224. #define FL_LONGDOUBLE 0x00400 /* long double value given */
  225. #define FL_WIDECHAR 0x00800 /* wide characters */
  226. #define FL_LONGLONG 0x01000 /* long long value given */
  227. #define FL_I64 0x08000 /* __int64 value given */
  228. /* state definitions */
  229. enum STATE {
  230. ST_NORMAL, /* normal state; outputting literal chars */
  231. ST_PERCENT, /* just read '%' */
  232. ST_FLAG, /* just read flag character */
  233. ST_WIDTH, /* just read width specifier */
  234. ST_DOT, /* just read '.' */
  235. ST_PRECIS, /* just read precision specifier */
  236. ST_SIZE, /* just read size specifier */
  237. ST_TYPE /* just read type specifier */
  238. #ifdef FORMAT_VALIDATIONS
  239. ,ST_INVALID /* Invalid format */
  240. #endif /* FORMAT_VALIDATIONS */
  241. };
  242. #ifdef FORMAT_VALIDATIONS
  243. #define NUMSTATES (ST_INVALID + 1)
  244. #else /* FORMAT_VALIDATIONS */
  245. #define NUMSTATES (ST_TYPE + 1)
  246. #endif /* FORMAT_VALIDATIONS */
  247. /* character type values */
  248. enum CHARTYPE {
  249. CH_OTHER, /* character with no special meaning */
  250. CH_PERCENT, /* '%' */
  251. CH_DOT, /* '.' */
  252. CH_STAR, /* '*' */
  253. CH_ZERO, /* '0' */
  254. CH_DIGIT, /* '1'..'9' */
  255. CH_FLAG, /* ' ', '+', '-', '#' */
  256. CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
  257. CH_TYPE /* type specifying character */
  258. };
  259. /* static data (read only, since we are re-entrant) */
  260. //#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS)
  261. //extern const char __nullstring[]; /* string to print on null ptr */
  262. //extern const char16_t __wnullstring[]; /* string to print on null ptr */
  263. //#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
  264. static const char __nullstring[] = "(null)"; /* string to print on null ptr */
  265. static const char16_t __wnullstring[] = {'(', 'n', 'u', 'l', 'l', ')', '\0'};/* string to print on null ptr */
  266. //#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
  267. /* The state table. This table is actually two tables combined into one. */
  268. /* The lower nybble of each byte gives the character class of any */
  269. /* character; while the uper nybble of the byte gives the next state */
  270. /* to enter. See the macros below the table for details. */
  271. /* */
  272. /* The table is generated by maketabc.c -- use this program to make */
  273. /* changes. */
  274. #ifndef FORMAT_VALIDATIONS
  275. //#if defined (_UNICODE) || defined (CPRFLAG)
  276. //extern const char __lookuptable[];
  277. //#else /* defined (_UNICODE) || defined (CPRFLAG) */
  278. extern const char __lookuptable[] = {
  279. /* ' ' */ 0x06,
  280. /* '!' */ 0x00,
  281. /* '"' */ 0x00,
  282. /* '#' */ 0x06,
  283. /* '$' */ 0x00,
  284. /* '%' */ 0x01,
  285. /* '&' */ 0x00,
  286. /* ''' */ 0x00,
  287. /* '(' */ 0x10,
  288. /* ')' */ 0x00,
  289. /* '*' */ 0x03,
  290. /* '+' */ 0x06,
  291. /* ',' */ 0x00,
  292. /* '-' */ 0x06,
  293. /* '.' */ 0x02,
  294. /* '/' */ 0x10,
  295. /* '0' */ 0x04,
  296. /* '1' */ 0x45,
  297. /* '2' */ 0x45,
  298. /* '3' */ 0x45,
  299. /* '4' */ 0x05,
  300. /* '5' */ 0x05,
  301. /* '6' */ 0x05,
  302. /* '7' */ 0x05,
  303. /* '8' */ 0x05,
  304. /* '9' */ 0x35,
  305. /* ':' */ 0x30,
  306. /* ';' */ 0x00,
  307. /* '<' */ 0x50,
  308. /* '=' */ 0x00,
  309. /* '>' */ 0x00,
  310. /* '?' */ 0x00,
  311. /* '@' */ 0x00,
  312. /* 'A' */ 0x20, // Disable %A format
  313. /* 'B' */ 0x20,
  314. /* 'C' */ 0x38,
  315. /* 'D' */ 0x50,
  316. /* 'E' */ 0x58,
  317. /* 'F' */ 0x07,
  318. /* 'G' */ 0x08,
  319. /* 'H' */ 0x00,
  320. /* 'I' */ 0x37,
  321. /* 'J' */ 0x30,
  322. /* 'K' */ 0x30,
  323. /* 'L' */ 0x57,
  324. /* 'M' */ 0x50,
  325. /* 'N' */ 0x07,
  326. /* 'O' */ 0x00,
  327. /* 'P' */ 0x00,
  328. /* 'Q' */ 0x20,
  329. /* 'R' */ 0x20,
  330. /* 'S' */ 0x08,
  331. /* 'T' */ 0x00,
  332. /* 'U' */ 0x00,
  333. /* 'V' */ 0x00,
  334. /* 'W' */ 0x00,
  335. /* 'X' */ 0x08,
  336. /* 'Y' */ 0x60,
  337. /* 'Z' */ 0x68,
  338. /* '[' */ 0x60,
  339. /* '\' */ 0x60,
  340. /* ']' */ 0x60,
  341. /* '^' */ 0x60,
  342. /* '_' */ 0x00,
  343. /* '`' */ 0x00,
  344. /* 'a' */ 0x70, // Disable %a format
  345. /* 'b' */ 0x70,
  346. /* 'c' */ 0x78,
  347. /* 'd' */ 0x78,
  348. /* 'e' */ 0x78,
  349. /* 'f' */ 0x78,
  350. /* 'g' */ 0x08,
  351. /* 'h' */ 0x07,
  352. /* 'i' */ 0x08,
  353. /* 'j' */ 0x00,
  354. /* 'k' */ 0x00,
  355. /* 'l' */ 0x07,
  356. /* 'm' */ 0x00,
  357. /* 'n' */ 0x00, // Disable %n format
  358. /* 'o' */ 0x08,
  359. /* 'p' */ 0x08,
  360. /* 'q' */ 0x00,
  361. /* 'r' */ 0x00,
  362. /* 's' */ 0x08,
  363. /* 't' */ 0x00,
  364. /* 'u' */ 0x08,
  365. /* 'v' */ 0x00,
  366. /* 'w' */ 0x07,
  367. /* 'x' */ 0x08
  368. };
  369. //#endif /* defined (_UNICODE) || defined (CPRFLAG) */
  370. #else /* FORMAT_VALIDATIONS */
  371. //#if defined (_UNICODE) || defined (CPRFLAG)
  372. //extern const unsigned char __lookuptable_s[];
  373. //#else /* defined (_UNICODE) || defined (CPRFLAG) */
  374. static const unsigned char __lookuptable_s[] = {
  375. /* ' ' */ 0x06,
  376. /* '!' */ 0x80,
  377. /* '"' */ 0x80,
  378. /* '#' */ 0x86,
  379. /* '$' */ 0x80,
  380. /* '%' */ 0x81,
  381. /* '&' */ 0x80,
  382. /* ''' */ 0x00,
  383. /* '(' */ 0x00,
  384. /* ')' */ 0x10,
  385. /* '*' */ 0x03,
  386. /* '+' */ 0x86,
  387. /* ',' */ 0x80,
  388. /* '-' */ 0x86,
  389. /* '.' */ 0x82,
  390. /* '/' */ 0x80,
  391. /* '0' */ 0x14,
  392. /* '1' */ 0x05,
  393. /* '2' */ 0x05,
  394. /* '3' */ 0x45,
  395. /* '4' */ 0x45,
  396. /* '5' */ 0x45,
  397. /* '6' */ 0x85,
  398. /* '7' */ 0x85,
  399. /* '8' */ 0x85,
  400. /* '9' */ 0x05,
  401. /* ':' */ 0x00,
  402. /* ';' */ 0x00,
  403. /* '<' */ 0x30,
  404. /* '=' */ 0x30,
  405. /* '>' */ 0x80,
  406. /* '?' */ 0x50,
  407. /* '@' */ 0x80,
  408. /* 'A' */ 0x80, // Disable %A format
  409. /* 'B' */ 0x00,
  410. /* 'C' */ 0x08,
  411. /* 'D' */ 0x00,
  412. /* 'E' */ 0x28,
  413. /* 'F' */ 0x27,
  414. /* 'G' */ 0x38,
  415. /* 'H' */ 0x50,
  416. /* 'I' */ 0x57,
  417. /* 'J' */ 0x80,
  418. /* 'K' */ 0x00,
  419. /* 'L' */ 0x07,
  420. /* 'M' */ 0x00,
  421. /* 'N' */ 0x37,
  422. /* 'O' */ 0x30,
  423. /* 'P' */ 0x30,
  424. /* 'Q' */ 0x50,
  425. /* 'R' */ 0x50,
  426. /* 'S' */ 0x88,
  427. /* 'T' */ 0x00,
  428. /* 'U' */ 0x00,
  429. /* 'V' */ 0x00,
  430. /* 'W' */ 0x20,
  431. /* 'X' */ 0x28,
  432. /* 'Y' */ 0x80,
  433. /* 'Z' */ 0x88,
  434. /* '[' */ 0x80,
  435. /* '\' */ 0x80,
  436. /* ']' */ 0x00,
  437. /* '^' */ 0x00,
  438. /* '_' */ 0x00,
  439. /* '`' */ 0x60,
  440. /* 'a' */ 0x60, // Disable %a format
  441. /* 'b' */ 0x60,
  442. /* 'c' */ 0x68,
  443. /* 'd' */ 0x68,
  444. /* 'e' */ 0x68,
  445. /* 'f' */ 0x08,
  446. /* 'g' */ 0x08,
  447. /* 'h' */ 0x07,
  448. /* 'i' */ 0x78,
  449. /* 'j' */ 0x70,
  450. /* 'k' */ 0x70,
  451. /* 'l' */ 0x77,
  452. /* 'm' */ 0x70,
  453. /* 'n' */ 0x70,
  454. /* 'o' */ 0x08,
  455. /* 'p' */ 0x08,
  456. /* 'q' */ 0x00,
  457. /* 'r' */ 0x00,
  458. /* 's' */ 0x08,
  459. /* 't' */ 0x00,
  460. /* 'u' */ 0x08,
  461. /* 'v' */ 0x00,
  462. /* 'w' */ 0x07,
  463. /* 'x' */ 0x08
  464. };
  465. //#endif /* defined (_UNICODE) || defined (CPRFLAG) */
  466. #endif /* FORMAT_VALIDATIONS */
  467. #define FIND_CHAR_CLASS(lookuptbl, c) \
  468. ((c) < _T(' ') || (c) > _T('x') ? \
  469. CH_OTHER \
  470. : \
  471. (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
  472. #define FIND_NEXT_STATE(lookuptbl, class, state) \
  473. (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4)
  474. /*
  475. * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
  476. */
  477. /* prototypes */
  478. #ifdef CPRFLAG
  479. #define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
  480. #define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
  481. #define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
  482. LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
  483. LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
  484. LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten);
  485. #else /* CPRFLAG */
  486. #define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
  487. #define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
  488. #define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
  489. LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten);
  490. LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten);
  491. LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten);
  492. #endif /* CPRFLAG */
  493. #ifdef __GNUC_VA_LIST
  494. #define get_int_arg(list) va_arg(*list, int)
  495. #define get_long_arg(list) va_arg(*list, long)
  496. #define get_long_long_arg(list) va_arg(*list, long long)
  497. #define get_int64_arg(list) va_arg(*list, __int64)
  498. #define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE)
  499. #define get_ptr_arg(list) va_arg(*list, void *)
  500. #else // __GNUC_VA_LIST
  501. __inline int __cdecl get_int_arg(va_list *pargptr);
  502. #if !LONG_IS_INT
  503. __inline long __cdecl get_long_arg(va_list *pargptr);
  504. #endif /* !LONG_IS_INT */
  505. #if !LONGLONG_IS_INT64
  506. __inline long long __cdecl get_long_long_arg(va_list *pargptr);
  507. #endif /* !LONGLONG_IS_INT64 */
  508. #if _INTEGRAL_MAX_BITS >= 64
  509. __inline __int64 __cdecl get_int64_arg(va_list *pargptr);
  510. #endif /* _INTEGRAL_MAX_BITS >= 64 */
  511. #endif // __GNUC_VA_LIST
  512. #ifdef CPRFLAG
  513. LOCAL(int) output(const _TCHAR *, _locale_t , va_list);
  514. _CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list);
  515. _CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list);
  516. _CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list);
  517. /***
  518. *int _cprintf(format, arglist) - write formatted output directly to console
  519. *
  520. *Purpose:
  521. * Writes formatted data like printf, but uses console I/O functions.
  522. *
  523. *Entry:
  524. * char *format - format string to determine data formats
  525. * arglist - list of POINTERS to where to put data
  526. *
  527. *Exit:
  528. * returns number of characters written
  529. *
  530. *Exceptions:
  531. *
  532. *******************************************************************************/
  533. #ifndef FORMAT_VALIDATIONS
  534. _CRTIMP int __cdecl _tcprintf_l (
  535. const _TCHAR * format,
  536. _locale_t plocinfo,
  537. ...
  538. )
  539. #else /* FORMAT_VALIDATIONS */
  540. _CRTIMP int __cdecl _tcprintf_s_l (
  541. const _TCHAR * format,
  542. _locale_t plocinfo,
  543. ...
  544. )
  545. #endif /* FORMAT_VALIDATIONS */
  546. {
  547. int ret;
  548. va_list arglist;
  549. va_start(arglist, plocinfo);
  550. #ifndef FORMAT_VALIDATIONS
  551. ret = _vtcprintf_l(format, plocinfo, arglist);
  552. #else /* FORMAT_VALIDATIONS */
  553. ret = _vtcprintf_s_l(format, plocinfo, arglist);
  554. #endif /* FORMAT_VALIDATIONS */
  555. va_end(arglist);
  556. return ret;
  557. }
  558. #ifndef FORMAT_VALIDATIONS
  559. _CRTIMP int __cdecl _tcprintf (
  560. const _TCHAR * format,
  561. ...
  562. )
  563. #else /* FORMAT_VALIDATIONS */
  564. _CRTIMP int __cdecl _tcprintf_s (
  565. const _TCHAR * format,
  566. ...
  567. )
  568. #endif /* FORMAT_VALIDATIONS */
  569. {
  570. int ret;
  571. va_list arglist;
  572. va_start(arglist, format);
  573. #ifndef FORMAT_VALIDATIONS
  574. ret = _vtcprintf_l(format, NULL, arglist);
  575. #else /* FORMAT_VALIDATIONS */
  576. ret = _vtcprintf_s_l(format, NULL, arglist);
  577. #endif /* FORMAT_VALIDATIONS */
  578. va_end(arglist);
  579. return ret;
  580. }
  581. #endif /* CPRFLAG */
  582. /***
  583. *int _output(stream, format, argptr), static int output(format, argptr)
  584. *
  585. *Purpose:
  586. * Output performs printf style output onto a stream. It is called by
  587. * printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
  588. * work. In multi-thread situations, _output assumes that the given
  589. * stream is already locked.
  590. *
  591. * Algorithm:
  592. * The format string is parsed by using a finite state automaton
  593. * based on the current state and the current character read from
  594. * the format string. Thus, looping is on a per-character basis,
  595. * not a per conversion specifier basis. Once the format specififying
  596. * character is read, output is performed.
  597. *
  598. *Entry:
  599. * FILE *stream - stream for output
  600. * char *format - printf style format string
  601. * va_list argptr - pointer to list of subsidiary arguments
  602. *
  603. *Exit:
  604. * Returns the number of characters written, or -1 if an output error
  605. * occurs.
  606. *ifdef _UNICODE
  607. * The wide-character flavour returns the number of wide-characters written.
  608. *endif
  609. *
  610. *Exceptions:
  611. *
  612. *******************************************************************************/
  613. #ifdef CPRFLAG
  614. #ifndef FORMAT_VALIDATIONS
  615. _CRTIMP int __cdecl _vtcprintf (
  616. const _TCHAR *format,
  617. va_list argptr
  618. )
  619. {
  620. return _vtcprintf_l(format, NULL, argptr);
  621. }
  622. #else /* FORMAT_VALIDATIONS */
  623. _CRTIMP int __cdecl _vtcprintf_s (
  624. const _TCHAR *format,
  625. va_list argptr
  626. )
  627. {
  628. return _vtcprintf_s_l(format, NULL, argptr);
  629. }
  630. #endif /* FORMAT_VALIDATIONS */
  631. #endif /* CPRFLAG */
  632. #ifdef CPRFLAG
  633. #ifndef FORMAT_VALIDATIONS
  634. _CRTIMP int __cdecl _vtcprintf_l (
  635. #else /* FORMAT_VALIDATIONS */
  636. _CRTIMP int __cdecl _vtcprintf_s_l (
  637. #endif /* FORMAT_VALIDATIONS */
  638. #else /* CPRFLAG */
  639. #ifdef _UNICODE
  640. #ifndef FORMAT_VALIDATIONS
  641. int __cdecl _woutput (
  642. miniFILE *stream,
  643. #else /* FORMAT_VALIDATIONS */
  644. int __cdecl _woutput_s (
  645. miniFILE *stream,
  646. #endif /* FORMAT_VALIDATIONS */
  647. #else /* _UNICODE */
  648. #ifndef FORMAT_VALIDATIONS
  649. int __cdecl _output (
  650. miniFILE *stream,
  651. #else /* FORMAT_VALIDATIONS */
  652. int __cdecl _output_s (
  653. miniFILE *stream,
  654. #endif /* FORMAT_VALIDATIONS */
  655. #endif /* _UNICODE */
  656. #endif /* CPRFLAG */
  657. const _TCHAR *format,
  658. va_list argptr
  659. )
  660. {
  661. int hexadd=0; /* offset to add to number to get 'a'..'f' */
  662. TCHAR ch; /* character just read */
  663. int flags=0; /* flag word -- see #defines above for flag values */
  664. enum STATE state; /* current state */
  665. enum CHARTYPE chclass; /* class of current character */
  666. int radix; /* current conversion radix */
  667. int charsout; /* characters currently written so far, -1 = IO error */
  668. int fldwidth = 0; /* selected field width -- 0 means default */
  669. int precision = 0; /* selected precision -- -1 means default */
  670. TCHAR prefix[2]; /* numeric prefix -- up to two characters */
  671. int prefixlen=0; /* length of prefix -- 0 means no prefix */
  672. int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
  673. int no_output=0; /* non-zero = prodcue no output for this specifier */
  674. union {
  675. const char *sz; /* pointer text to be printed, not zero terminated */
  676. const char16_t *wz;
  677. } text;
  678. text.sz = NULL;
  679. int textlen; /* length of the text in bytes/wchars to be printed.
  680. textlen is in multibyte or wide chars if _UNICODE */
  681. union {
  682. char sz[BUFFERSIZE];
  683. #ifdef _UNICODE
  684. char16_t wz[BUFFERSIZE];
  685. #endif /* _UNICODE */
  686. } buffer;
  687. char16_t wchar; /* temp char16_t */
  688. int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
  689. int bufferiswide=0; /* non-zero = buffer contains wide chars already */
  690. #ifndef CPRFLAG
  691. _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
  692. #endif /* CPRFLAG */
  693. _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
  694. charsout = 0; /* no characters written yet */
  695. textlen = 0; /* no text yet */
  696. state = ST_NORMAL; /* starting state */
  697. buffersize = 0;
  698. /* main loop -- loop while format character exist and no I/O errors */
  699. while ((ch = *format++) != _T('\0') && charsout >= 0) {
  700. #ifndef FORMAT_VALIDATIONS
  701. chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
  702. state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
  703. #else /* FORMAT_VALIDATIONS */
  704. chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
  705. state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
  706. _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
  707. #endif /* FORMAT_VALIDATIONS */
  708. /* execute code for each state */
  709. switch (state) {
  710. case ST_NORMAL:
  711. NORMAL_STATE:
  712. /* normal state -- just write character */
  713. #ifdef _UNICODE
  714. bufferiswide = 1;
  715. #else /* _UNICODE */
  716. bufferiswide = 0;
  717. #endif /* _UNICODE */
  718. WRITE_CHAR(ch, &charsout);
  719. break;
  720. case ST_PERCENT:
  721. /* set default value of conversion parameters */
  722. prefixlen = fldwidth = no_output = capexp = 0;
  723. flags = 0;
  724. precision = -1;
  725. bufferiswide = 0; /* default */
  726. break;
  727. case ST_FLAG:
  728. /* set flag based on which flag character */
  729. switch (ch) {
  730. case _T('-'):
  731. flags |= FL_LEFT; /* '-' => left justify */
  732. break;
  733. case _T('+'):
  734. flags |= FL_SIGN; /* '+' => force sign indicator */
  735. break;
  736. case _T(' '):
  737. flags |= FL_SIGNSP; /* ' ' => force sign or space */
  738. break;
  739. case _T('#'):
  740. flags |= FL_ALTERNATE; /* '#' => alternate form */
  741. break;
  742. case _T('0'):
  743. flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
  744. break;
  745. }
  746. break;
  747. case ST_WIDTH:
  748. /* update width value */
  749. if (ch == _T('*')) {
  750. /* get width from arg list */
  751. fldwidth = get_int_arg(&argptr);
  752. if (fldwidth < 0) {
  753. /* ANSI says neg fld width means '-' flag and pos width */
  754. flags |= FL_LEFT;
  755. fldwidth = -fldwidth;
  756. }
  757. }
  758. else {
  759. /* add digit to current field width */
  760. fldwidth = fldwidth * 10 + (ch - _T('0'));
  761. }
  762. break;
  763. case ST_DOT:
  764. /* zero the precision, since dot with no number means 0
  765. not default, according to ANSI */
  766. precision = 0;
  767. break;
  768. case ST_PRECIS:
  769. /* update precison value */
  770. if (ch == _T('*')) {
  771. /* get precision from arg list */
  772. precision = get_int_arg(&argptr);
  773. if (precision < 0)
  774. precision = -1; /* neg precision means default */
  775. }
  776. else {
  777. /* add digit to current precision */
  778. precision = precision * 10 + (ch - _T('0'));
  779. }
  780. break;
  781. case ST_SIZE:
  782. /* just read a size specifier, set the flags based on it */
  783. switch (ch) {
  784. case _T('l'):
  785. /*
  786. * In order to handle the ll case, we depart from the
  787. * simple deterministic state machine.
  788. */
  789. if (*format == _T('l'))
  790. {
  791. ++format;
  792. flags |= FL_LONGLONG; /* 'll' => long long */
  793. }
  794. else
  795. {
  796. flags |= FL_LONG; /* 'l' => long int or char16_t */
  797. }
  798. break;
  799. case _T('I'):
  800. /*
  801. * In order to handle the I, I32, and I64 size modifiers, we
  802. * depart from the simple deterministic state machine. The
  803. * code below scans for characters following the 'I',
  804. * and defaults to 64 bit on WIN64 and 32 bit on WIN32
  805. */
  806. #if PTR_IS_INT64
  807. flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
  808. #endif /* PTR_IS_INT64 */
  809. if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
  810. {
  811. format += 2;
  812. flags |= FL_I64; /* I64 => __int64 */
  813. }
  814. else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
  815. {
  816. format += 2;
  817. flags &= ~FL_I64; /* I32 => __int32 */
  818. }
  819. else if ( (*format == _T('d')) ||
  820. (*format == _T('i')) ||
  821. (*format == _T('o')) ||
  822. (*format == _T('u')) ||
  823. (*format == _T('x')) ||
  824. (*format == _T('X')) )
  825. {
  826. /*
  827. * Nothing further needed. %Id (et al) is
  828. * handled just like %d, except that it defaults to 64 bits
  829. * on WIN64. Fall through to the next iteration.
  830. */
  831. }
  832. else {
  833. state = ST_NORMAL;
  834. goto NORMAL_STATE;
  835. }
  836. break;
  837. case _T('h'):
  838. flags |= FL_SHORT; /* 'h' => short int or char */
  839. break;
  840. case _T('w'):
  841. flags |= FL_WIDECHAR; /* 'w' => wide character */
  842. break;
  843. }
  844. break;
  845. case ST_TYPE:
  846. /* we have finally read the actual type character, so we */
  847. /* now format and "print" the output. We use a big switch */
  848. /* statement that sets 'text' to point to the text that should */
  849. /* be printed, and 'textlen' to the length of this text. */
  850. /* Common code later on takes care of justifying it and */
  851. /* other miscellaneous chores. Note that cases share code, */
  852. /* in particular, all integer formatting is done in one place. */
  853. /* Look at those funky goto statements! */
  854. switch (ch) {
  855. case _T('C'): /* ISO wide character */
  856. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  857. #ifdef _UNICODE
  858. flags |= FL_SHORT;
  859. #else /* _UNICODE */
  860. flags |= FL_WIDECHAR; /* ISO std. */
  861. #endif /* _UNICODE */
  862. /* fall into 'c' case */
  863. case _T('c'): {
  864. /* print a single character specified by int argument */
  865. #ifdef _UNICODE
  866. bufferiswide = 1;
  867. wchar = (char16_t) get_int_arg(&argptr);
  868. if (flags & FL_SHORT) {
  869. /* format multibyte character */
  870. /* this is an extension of ANSI */
  871. char tempchar[2];
  872. {
  873. tempchar[0] = (char)(wchar & 0x00ff);
  874. tempchar[1] = '\0';
  875. }
  876. if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
  877. {
  878. /* ignore if conversion was unsuccessful */
  879. no_output = 1;
  880. }
  881. } else {
  882. buffer.wz[0] = wchar;
  883. }
  884. text.wz = buffer.wz;
  885. textlen = 1; /* print just a single character */
  886. #else /* _UNICODE */
  887. if (flags & (FL_LONG|FL_WIDECHAR)) {
  888. wchar = (char16_t) get_int_arg(&argptr);
  889. no_output = 1;
  890. } else {
  891. /* format multibyte character */
  892. /* this is an extension of ANSI */
  893. unsigned short temp;
  894. wchar = (char16_t)get_int_arg(&argptr);
  895. temp = (unsigned short)wchar;
  896. {
  897. buffer.sz[0] = (char) temp;
  898. textlen = 1;
  899. }
  900. }
  901. text.sz = buffer.sz;
  902. #endif /* _UNICODE */
  903. }
  904. break;
  905. case _T('Z'): {
  906. /* print a Counted String */
  907. struct _count_string {
  908. short Length;
  909. short MaximumLength;
  910. char *Buffer;
  911. } *pstr;
  912. pstr = (struct _count_string *)get_ptr_arg(&argptr);
  913. if (pstr == NULL || pstr->Buffer == NULL) {
  914. /* null ptr passed, use special string */
  915. text.sz = __nullstring;
  916. textlen = (int)strlen(text.sz);
  917. } else {
  918. if (flags & FL_WIDECHAR) {
  919. text.wz = (char16_t *)pstr->Buffer;
  920. textlen = pstr->Length / (int)sizeof(char16_t);
  921. bufferiswide = 1;
  922. } else {
  923. bufferiswide = 0;
  924. text.sz = pstr->Buffer;
  925. textlen = pstr->Length;
  926. }
  927. }
  928. }
  929. break;
  930. case _T('S'): /* ISO wide character string */
  931. #ifndef _UNICODE
  932. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  933. flags |= FL_WIDECHAR;
  934. #else /* _UNICODE */
  935. if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
  936. flags |= FL_SHORT;
  937. #endif /* _UNICODE */
  938. case _T('s'): {
  939. /* print a string -- */
  940. /* ANSI rules on how much of string to print: */
  941. /* all if precision is default, */
  942. /* min(precision, length) if precision given. */
  943. /* prints '(null)' if a null string is passed */
  944. int i;
  945. const char *p; /* temps */
  946. const char16_t *pwch;
  947. /* At this point it is tempting to use strlen(), but */
  948. /* if a precision is specified, we're not allowed to */
  949. /* scan past there, because there might be no null */
  950. /* at all. Thus, we must do our own scan. */
  951. i = (precision == -1) ? INT_MAX : precision;
  952. text.sz = (char *)get_ptr_arg(&argptr);
  953. /* scan for null upto i characters */
  954. #ifdef _UNICODE
  955. if (flags & FL_SHORT) {
  956. if (text.sz == NULL) /* NULL passed, use special string */
  957. text.sz = __nullstring;
  958. p = text.sz;
  959. for (textlen=0; textlen<i && *p; textlen++) {
  960. ++p;
  961. }
  962. /* textlen now contains length in multibyte chars */
  963. } else {
  964. if (text.wz == NULL) /* NULL passed, use special string */
  965. text.wz = __wnullstring;
  966. bufferiswide = 1;
  967. pwch = text.wz;
  968. while (i-- && *pwch)
  969. ++pwch;
  970. textlen = (int)(pwch - text.wz); /* in char16_ts */
  971. /* textlen now contains length in wide chars */
  972. }
  973. #else /* _UNICODE */
  974. if (flags & (FL_LONG|FL_WIDECHAR)) {
  975. if (text.wz == NULL) /* NULL passed, use special string */
  976. text.wz = __wnullstring;
  977. bufferiswide = 1;
  978. pwch = text.wz;
  979. while ( i-- && *pwch )
  980. ++pwch;
  981. textlen = (int)(pwch - text.wz);
  982. /* textlen now contains length in wide chars */
  983. } else {
  984. if (text.sz == NULL) /* NULL passed, use special string */
  985. text.sz = __nullstring;
  986. p = text.sz;
  987. while (i-- && *p)
  988. ++p;
  989. textlen = (int)(p - text.sz); /* length of the string */
  990. }
  991. #endif /* _UNICODE */
  992. }
  993. break;
  994. case _T('n'): {
  995. /* write count of characters seen so far into */
  996. /* short/int/long thru ptr read from args */
  997. void *p; /* temp */
  998. p = get_ptr_arg(&argptr);
  999. /* %n is disabled */
  1000. _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
  1001. break;
  1002. /* store chars out into short/long/int depending on flags */
  1003. #if !LONG_IS_INT
  1004. if (flags & FL_LONG)
  1005. *(long *)p = charsout;
  1006. else
  1007. #endif /* !LONG_IS_INT */
  1008. #if !SHORT_IS_INT
  1009. if (flags & FL_SHORT)
  1010. *(short *)p = (short) charsout;
  1011. else
  1012. #endif /* !SHORT_IS_INT */
  1013. *(int *)p = charsout;
  1014. no_output = 1; /* force no output */
  1015. }
  1016. break;
  1017. case _T('E'):
  1018. case _T('G'):
  1019. case _T('A'):
  1020. capexp = 1; /* capitalize exponent */
  1021. ch = (TCHAR)((int)ch + _T('a') - _T('A')); /* convert format char to lower */
  1022. /* DROP THROUGH */
  1023. case _T('e'):
  1024. case _T('f'):
  1025. case _T('g'):
  1026. case _T('a'): {
  1027. /* floating point conversion -- we call cfltcvt routines */
  1028. /* to do the work for us. */
  1029. flags |= FL_SIGNED; /* floating point is signed conversion */
  1030. text.sz = buffer.sz; /* put result in buffer */
  1031. buffersize = BUFFERSIZE;
  1032. /* compute the precision value */
  1033. if (precision < 0)
  1034. precision = 6; /* default precision: 6 */
  1035. else if (precision == 0 && ch == _T('g'))
  1036. precision = 1; /* ANSI specified */
  1037. else if (precision > MAXPRECISION)
  1038. precision = MAXPRECISION;
  1039. if (precision > BUFFERSIZE - _CVTBUFSIZE) {
  1040. /* cap precision further */
  1041. precision = BUFFERSIZE - _CVTBUFSIZE;
  1042. }
  1043. /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
  1044. if (flags & FL_ALTERNATE)
  1045. {
  1046. capexp |= FL_ALTERNATE;
  1047. }
  1048. _CRT_DOUBLE tmp;
  1049. tmp=va_arg(argptr, _CRT_DOUBLE);
  1050. /* Note: assumes ch is in ASCII range */
  1051. /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
  1052. _CFLTCVT(&tmp, buffer.sz, (size_t)buffersize, (char)ch, precision, capexp);
  1053. /* check if result was negative, save '-' for later */
  1054. /* and point to positive part (this is for '0' padding) */
  1055. if (*text.sz == '-') {
  1056. flags |= FL_NEGATIVE;
  1057. ++text.sz;
  1058. }
  1059. textlen = (int)strlen(text.sz); /* compute length of text */
  1060. }
  1061. break;
  1062. case _T('d'):
  1063. case _T('i'):
  1064. /* signed decimal output */
  1065. flags |= FL_SIGNED;
  1066. radix = 10;
  1067. goto COMMON_INT;
  1068. case _T('u'):
  1069. radix = 10;
  1070. goto COMMON_INT;
  1071. case _T('p'):
  1072. /* write a pointer -- this is like an integer or long */
  1073. /* except we force precision to pad with zeros and */
  1074. /* output in big hex. */
  1075. precision = 2 * sizeof(void *); /* number of hex digits needed */
  1076. #if PTR_IS_INT64
  1077. flags |= FL_I64; /* assume we're converting an int64 */
  1078. #elif !PTR_IS_INT
  1079. flags |= FL_LONG; /* assume we're converting a long */
  1080. #endif /* !PTR_IS_INT */
  1081. /* DROP THROUGH to hex formatting */
  1082. case _T('X'):
  1083. /* unsigned upper hex output */
  1084. hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
  1085. goto COMMON_HEX;
  1086. case _T('x'):
  1087. /* unsigned lower hex output */
  1088. hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
  1089. /* DROP THROUGH TO COMMON_HEX */
  1090. COMMON_HEX:
  1091. radix = 16;
  1092. if (flags & FL_ALTERNATE) {
  1093. /* alternate form means '0x' prefix */
  1094. prefix[0] = _T('0');
  1095. prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
  1096. prefixlen = 2;
  1097. }
  1098. goto COMMON_INT;
  1099. case _T('o'):
  1100. /* unsigned octal output */
  1101. radix = 8;
  1102. if (flags & FL_ALTERNATE) {
  1103. /* alternate form means force a leading 0 */
  1104. flags |= FL_FORCEOCTAL;
  1105. }
  1106. /* DROP THROUGH to COMMON_INT */
  1107. COMMON_INT: {
  1108. /* This is the general integer formatting routine. */
  1109. /* Basically, we get an argument, make it positive */
  1110. /* if necessary, and convert it according to the */
  1111. /* correct radix, setting text and textlen */
  1112. /* appropriately. */
  1113. #if _INTEGRAL_MAX_BITS >= 64
  1114. __uint64_t number; /* number to convert */
  1115. int digit; /* ascii value of digit */
  1116. __int64 l; /* temp long value */
  1117. #else /* _INTEGRAL_MAX_BITS >= 64 */
  1118. unsigned long number; /* number to convert */
  1119. int digit; /* ascii value of digit */
  1120. long l; /* temp long value */
  1121. #endif /* _INTEGRAL_MAX_BITS >= 64 */
  1122. /* 1. read argument into l, sign extend as needed */
  1123. #if _INTEGRAL_MAX_BITS >= 64
  1124. if (flags & FL_I64)
  1125. l = get_int64_arg(&argptr);
  1126. else
  1127. #endif /* _INTEGRAL_MAX_BITS >= 64 */
  1128. if (flags & FL_LONGLONG)
  1129. l = get_long_long_arg(&argptr);
  1130. else
  1131. #if !LONG_IS_INT
  1132. if (flags & FL_LONG)
  1133. l = get_long_arg(&argptr);
  1134. else
  1135. #endif /* !LONG_IS_INT */
  1136. #if !SHORT_IS_INT
  1137. if (flags & FL_SHORT) {
  1138. if (flags & FL_SIGNED)
  1139. l = (short) get_int_arg(&argptr); /* sign extend */
  1140. else
  1141. l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
  1142. } else
  1143. #endif /* !SHORT_IS_INT */
  1144. {
  1145. if (flags & FL_SIGNED)
  1146. l = get_int_arg(&argptr); /* sign extend */
  1147. else
  1148. l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
  1149. }
  1150. /* 2. check for negative; copy into number */
  1151. if ( (flags & FL_SIGNED) && l < 0) {
  1152. number = (__uint64_t)(-l);
  1153. flags |= FL_NEGATIVE; /* remember negative sign */
  1154. } else {
  1155. number = (__uint64_t)(l);
  1156. }
  1157. #if _INTEGRAL_MAX_BITS >= 64
  1158. if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) {
  1159. /*
  1160. * Unless printing a full 64-bit value, insure values
  1161. * here are not in cananical longword format to prevent
  1162. * the sign extended upper 32-bits from being printed.
  1163. */
  1164. number &= 0xffffffff;
  1165. }
  1166. #endif /* _INTEGRAL_MAX_BITS >= 64 */
  1167. /* 3. check precision value for default; non-default */
  1168. /* turns off 0 flag, according to ANSI. */
  1169. if (precision < 0)
  1170. precision = 1; /* default precision */
  1171. else {
  1172. flags &= ~FL_LEADZERO;
  1173. if (precision > MAXPRECISION)
  1174. precision = MAXPRECISION;
  1175. }
  1176. /* 4. Check if data is 0; if so, turn off hex prefix */
  1177. if (number == 0)
  1178. prefixlen = 0;
  1179. /* 5. Convert data to ASCII -- note if precision is zero */
  1180. /* and number is zero, we get no digits at all. */
  1181. char *sz;
  1182. sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
  1183. while (precision-- > 0 || number != 0) {
  1184. digit = (int)(number % ((__uint64_t)(radix))) + '0';
  1185. number /= ((__uint64_t)(radix)); /* reduce number */
  1186. if (digit > '9') {
  1187. /* a hex digit, make it a letter */
  1188. digit += hexadd;
  1189. }
  1190. *sz-- = (char)digit; /* store the digit */
  1191. }
  1192. textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
  1193. ++sz; /* text points to first digit now */
  1194. /* 6. Force a leading zero if FORCEOCTAL flag set */
  1195. if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
  1196. *--sz = '0';
  1197. ++textlen; /* add a zero */
  1198. }
  1199. text.sz = sz;
  1200. }
  1201. break;
  1202. }
  1203. /* At this point, we have done the specific conversion, and */
  1204. /* 'text' points to text to print; 'textlen' is length. Now we */
  1205. /* justify it, put on prefixes, leading zeros, and then */
  1206. /* print it. */
  1207. if (!no_output) {
  1208. int padding; /* amount of padding, negative means zero */
  1209. if (flags & FL_SIGNED) {
  1210. if (flags & FL_NEGATIVE) {
  1211. /* prefix is a '-' */
  1212. prefix[0] = _T('-');
  1213. prefixlen = 1;
  1214. }
  1215. else if (flags & FL_SIGN) {
  1216. /* prefix is '+' */
  1217. prefix[0] = _T('+');
  1218. prefixlen = 1;
  1219. }
  1220. else if (flags & FL_SIGNSP) {
  1221. /* prefix is ' ' */
  1222. prefix[0] = _T(' ');
  1223. prefixlen = 1;
  1224. }
  1225. }
  1226. /* calculate amount of padding -- might be negative, */
  1227. /* but this will just mean zero */
  1228. padding = fldwidth - textlen - prefixlen;
  1229. /* put out the padding, prefix, and text, in the correct order */
  1230. if (!(flags & (FL_LEFT | FL_LEADZERO))) {
  1231. /* pad on left with blanks */
  1232. WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  1233. }
  1234. /* write prefix */
  1235. WRITE_STRING(prefix, prefixlen, &charsout);
  1236. if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
  1237. /* write leading zeros */
  1238. WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
  1239. }
  1240. /* write text */
  1241. #ifndef _UNICODE
  1242. if (bufferiswide && (textlen > 0)) {
  1243. charsout = -1;
  1244. } else {
  1245. WRITE_STRING(text.sz, textlen, &charsout);
  1246. }
  1247. #else /* _UNICODE */
  1248. if (!bufferiswide && textlen > 0) {
  1249. const char *p;
  1250. int retval = 0;
  1251. int count;
  1252. p = text.sz;
  1253. count = textlen;
  1254. while (count-- > 0) {
  1255. retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
  1256. if (retval <= 0) {
  1257. charsout = -1;
  1258. break;
  1259. }
  1260. WRITE_CHAR(wchar, &charsout);
  1261. p += retval;
  1262. }
  1263. } else {
  1264. WRITE_STRING(text.wz, textlen, &charsout);
  1265. }
  1266. #endif /* _UNICODE */
  1267. if (charsout >= 0 && (flags & FL_LEFT)) {
  1268. /* pad on right with blanks */
  1269. WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
  1270. }
  1271. /* we're done! */
  1272. }
  1273. break;
  1274. case ST_INVALID:
  1275. _VALIDATE_RETURN(0 /* FALSE */, EINVAL, -1);
  1276. break;
  1277. }
  1278. }
  1279. #ifdef FORMAT_VALIDATIONS
  1280. /* The format string shouldn't be incomplete - i.e. when we are finished
  1281. with the format string, the last thing we should have encountered
  1282. should have been a regular char to be output or a type specifier. Else
  1283. the format string was incomplete */
  1284. _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
  1285. #endif /* FORMAT_VALIDATIONS */
  1286. return charsout; /* return value = number of characters written */
  1287. }
  1288. /*
  1289. * Future Optimizations for swprintf:
  1290. * - Don't free the memory used for converting the buffer to wide chars.
  1291. * Use realloc if the memory is not sufficient. Free it at the end.
  1292. */
  1293. /***
  1294. *void write_char(char ch, int *pnumwritten)
  1295. *ifdef _UNICODE
  1296. *void write_char(char16_t ch, FILE *f, int *pnumwritten)
  1297. *endif
  1298. *void write_char(char ch, FILE *f, int *pnumwritten)
  1299. *
  1300. *Purpose:
  1301. * Writes a single character to the given file/console. If no error occurs,
  1302. * then *pnumwritten is incremented; otherwise, *pnumwritten is set
  1303. * to -1.
  1304. *
  1305. *Entry:
  1306. * _TCHAR ch - character to write
  1307. * FILE *f - file to write to
  1308. * int *pnumwritten - pointer to integer to update with total chars written
  1309. *
  1310. *Exit:
  1311. * No return value.
  1312. *
  1313. *Exceptions:
  1314. *
  1315. *******************************************************************************/
  1316. #ifdef CPRFLAG
  1317. LOCAL(void) write_char (
  1318. _TCHAR ch,
  1319. int *pnumwritten
  1320. )
  1321. {
  1322. #ifdef _UNICODE
  1323. if (_putwch_nolock(ch) == WEOF)
  1324. #else /* _UNICODE */
  1325. if (_putch_nolock(ch) == EOF)
  1326. #endif /* _UNICODE */
  1327. *pnumwritten = -1;
  1328. else
  1329. ++(*pnumwritten);
  1330. }
  1331. #else /* CPRFLAG */
  1332. LOCAL(void) write_char (
  1333. _TCHAR ch,
  1334. miniFILE *f,
  1335. int *pnumwritten
  1336. )
  1337. {
  1338. if ( (f->_flag & _IOSTRG) && f->_base == NULL)
  1339. {
  1340. ++(*pnumwritten);
  1341. return;
  1342. }
  1343. #ifdef _UNICODE
  1344. if (_putwc_nolock(ch, f) == WEOF)
  1345. #else /* _UNICODE */
  1346. if (_putc_nolock(ch, f) == EOF)
  1347. #endif /* _UNICODE */
  1348. *pnumwritten = -1;
  1349. else
  1350. ++(*pnumwritten);
  1351. }
  1352. #endif /* CPRFLAG */
  1353. /***
  1354. *void write_multi_char(char ch, int num, int *pnumwritten)
  1355. *ifdef _UNICODE
  1356. *void write_multi_char(char16_t ch, int num, FILE *f, int *pnumwritten)
  1357. *endif
  1358. *void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
  1359. *
  1360. *Purpose:
  1361. * Writes num copies of a character to the given file/console. If no error occurs,
  1362. * then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
  1363. * to -1. If num is negative, it is treated as zero.
  1364. *
  1365. *Entry:
  1366. * _TCHAR ch - character to write
  1367. * int num - number of times to write the characters
  1368. * FILE *f - file to write to
  1369. * int *pnumwritten - pointer to integer to update with total chars written
  1370. *
  1371. *Exit:
  1372. * No return value.
  1373. *
  1374. *Exceptions:
  1375. *
  1376. *******************************************************************************/
  1377. #ifdef CPRFLAG
  1378. LOCAL(void) write_multi_char (
  1379. _TCHAR ch,
  1380. int num,
  1381. int *pnumwritten
  1382. )
  1383. {
  1384. while (num-- > 0) {
  1385. write_char(ch, pnumwritten);
  1386. if (*pnumwritten == -1)
  1387. break;
  1388. }
  1389. }
  1390. #else /* CPRFLAG */
  1391. LOCAL(void) write_multi_char (
  1392. _TCHAR ch,
  1393. int num,
  1394. miniFILE *f,
  1395. int *pnumwritten
  1396. )
  1397. {
  1398. while (num-- > 0) {
  1399. write_char(ch, f, pnumwritten);
  1400. if (*pnumwritten == -1)
  1401. break;
  1402. }
  1403. }
  1404. #endif /* CPRFLAG */
  1405. /***
  1406. *void write_string(const char *string, int len, int *pnumwritten)
  1407. *void write_string(const char *string, int len, FILE *f, int *pnumwritten)
  1408. *ifdef _UNICODE
  1409. *void write_string(const char16_t *string, int len, FILE *f, int *pnumwritten)
  1410. *endif
  1411. *
  1412. *Purpose:
  1413. * Writes a string of the given length to the given file. If no error occurs,
  1414. * then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
  1415. * to -1. If len is negative, it is treated as zero.
  1416. *
  1417. *Entry:
  1418. * _TCHAR *string - string to write (NOT null-terminated)
  1419. * int len - length of string
  1420. * FILE *f - file to write to
  1421. * int *pnumwritten - pointer to integer to update with total chars written
  1422. *
  1423. *Exit:
  1424. * No return value.
  1425. *
  1426. *Exceptions:
  1427. *
  1428. *******************************************************************************/
  1429. #ifdef CPRFLAG
  1430. LOCAL(void) write_string (
  1431. const _TCHAR *string,
  1432. int len,
  1433. int *pnumwritten
  1434. )
  1435. {
  1436. while (len-- > 0) {
  1437. write_char(*string++, pnumwritten);
  1438. if (*pnumwritten == -1)
  1439. {
  1440. if (errno == EILSEQ)
  1441. write_char(_T('?'), pnumwritten);
  1442. else
  1443. break;
  1444. }
  1445. }
  1446. }
  1447. #else /* CPRFLAG */
  1448. LOCAL(void) write_string (
  1449. const _TCHAR *string,
  1450. int len,
  1451. miniFILE *f,
  1452. int *pnumwritten
  1453. )
  1454. {
  1455. if ( (f->_flag & _IOSTRG) && f->_base == NULL)
  1456. {
  1457. (*pnumwritten) += len;
  1458. return;
  1459. }
  1460. while (len-- > 0) {
  1461. write_char(*string++, f, pnumwritten);
  1462. if (*pnumwritten == -1)
  1463. {
  1464. if (errno == EILSEQ)
  1465. write_char(_T('?'), f, pnumwritten);
  1466. else
  1467. break;
  1468. }
  1469. }
  1470. }
  1471. #endif /* CPRFLAG */
  1472. // For GCC 64 bit, we can't cast to va_list *, so we need to make these functions defines.
  1473. #ifndef __GNUC_VA_LIST
  1474. /***
  1475. *int get_int_arg(va_list *pargptr)
  1476. *
  1477. *Purpose:
  1478. * Gets an int argument off the given argument list and updates *pargptr.
  1479. *
  1480. *Entry:
  1481. * va_list *pargptr - pointer to argument list; updated by function
  1482. *
  1483. *Exit:
  1484. * Returns the integer argument read from the argument list.
  1485. *
  1486. *Exceptions:
  1487. *
  1488. *******************************************************************************/
  1489. __inline int __cdecl get_int_arg (
  1490. va_list *pargptr
  1491. )
  1492. {
  1493. return va_arg(*pargptr, int);
  1494. }
  1495. /***
  1496. *long get_long_arg(va_list *pargptr)
  1497. *
  1498. *Purpose:
  1499. * Gets an long argument off the given argument list and updates *pargptr.
  1500. *
  1501. *Entry:
  1502. * va_list *pargptr - pointer to argument list; updated by function
  1503. *
  1504. *Exit:
  1505. * Returns the long argument read from the argument list.
  1506. *
  1507. *Exceptions:
  1508. *
  1509. *******************************************************************************/
  1510. #if !LONG_IS_INT
  1511. __inline long __cdecl get_long_arg (
  1512. va_list *pargptr
  1513. )
  1514. {
  1515. return va_arg(*pargptr, long);
  1516. }
  1517. #endif /* !LONG_IS_INT */
  1518. #if !LONGLONG_IS_INT64
  1519. __inline long long __cdecl get_long_long_arg (
  1520. va_list *pargptr
  1521. )
  1522. {
  1523. return va_arg(*pargptr, long long);
  1524. }
  1525. #endif /* !LONGLONG_IS_INT64 */
  1526. #if _INTEGRAL_MAX_BITS >= 64
  1527. __inline __int64 __cdecl get_int64_arg (
  1528. va_list *pargptr
  1529. )
  1530. {
  1531. return va_arg(*pargptr, __int64);
  1532. }
  1533. #endif /* _INTEGRAL_MAX_BITS >= 64 */
  1534. #ifndef _UNICODE
  1535. #endif /* _UNICODE */
  1536. #endif // __GNUC_VA_LIST