EASprintfCore.cpp 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EAStdC/internal/Config.h>
  5. #include <EAStdC/internal/SprintfCore.h>
  6. #include <EAStdC/EAMathHelp.h>
  7. #include <EAStdC/EAString.h>
  8. #include <EAAssert/eaassert.h>
  9. #include <string.h>
  10. #include <float.h>
  11. #include <math.h>
  12. #if defined(EA_PLATFORM_ANDROID)
  13. #include <android/log.h>
  14. #endif
  15. //include for OutputDebugStringA
  16. #if defined(EASTDC_OUTPUTDEBUGSTRING_ENABLED) && EASTDC_OUTPUTDEBUGSTRING_ENABLED
  17. EA_DISABLE_ALL_VC_WARNINGS();
  18. #ifndef WIN32_LEAN_AND_MEAN
  19. #define WIN32_LEAN_AND_MEAN
  20. #define EASTDC_WIN32_LEAN_AND_MEAN_TEMP_DEF
  21. #endif
  22. #include <windows.h>
  23. #if defined(EASTDC_WIN32_LEAN_AND_MEAN_TEMP_DEF)
  24. #undef WIN32_LEAN_AND_MEAN
  25. #undef EASTDC_WIN32_LEAN_AND_MEAN_TEMP_DEF
  26. #endif
  27. EA_RESTORE_ALL_VC_WARNINGS();
  28. #endif
  29. #ifdef _MSC_VER
  30. #pragma warning(push)
  31. #pragma warning(disable: 4127) // conditional expression is constant.
  32. #endif
  33. // To do: switch this to instead use <EABase/eastdarg.h>'s va_list_reference at about Summer of 2015:
  34. #if (defined(__GNUC__) && (defined(__x86__) || defined(__x86_64__)))
  35. #define VA_LIST_REFERENCE(arguments) ((va_list*) arguments)
  36. #else
  37. #define VA_LIST_REFERENCE(arguments) ((va_list*)&arguments)
  38. #endif
  39. namespace EA
  40. {
  41. namespace StdC
  42. {
  43. namespace SprintfLocal
  44. {
  45. int StringWriter8(const char* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext8, WriteFunctionState /*wfs*/)
  46. {
  47. using namespace SprintfLocal;
  48. SnprintfContext8* const pSnprintfContext8 = (SnprintfContext8*)pContext8;
  49. if(nCount && !pSnprintfContext8->mbMaxCountReached) // If there is anything to write and if we haven't already exhausted the limit for this context...
  50. {
  51. if(nCount > (pSnprintfContext8->mnMaxCount - pSnprintfContext8->mnCount)) // If nCount results in an exhausting of the limit...
  52. {
  53. pSnprintfContext8->mbMaxCountReached = true; // Note that it is possible due to non-breakable multi-byte sequences that mnCount will be < mnMaxCount.
  54. // We must check for (UTF8) MBCS sequences here. We cannot write a
  55. // partial multi-byte sequence, but can only write a contiguous sequence.
  56. const size_t nRoom = pSnprintfContext8->mnMaxCount - pSnprintfContext8->mnCount;
  57. size_t i = 0;
  58. while (i < nCount)
  59. {
  60. size_t nClusterSize;
  61. if((uint8_t)pData[i] < 0xc2)
  62. nClusterSize = 1;
  63. else if((uint8_t)pData[i] < 0xe0)
  64. nClusterSize = 2;
  65. else if((uint8_t)pData[i] < 0xf0)
  66. nClusterSize = 3;
  67. else
  68. break; // Unknown size. Fail the cluster.
  69. if (i + nClusterSize > nRoom)
  70. break; // Out of room in our destination buffer.
  71. i += nClusterSize;
  72. }
  73. nCount = i;
  74. }
  75. memcpy(pSnprintfContext8->mpDestination + pSnprintfContext8->mnCount, pData, nCount * sizeof(*pData));
  76. pSnprintfContext8->mnCount += nCount;
  77. return (int)(unsigned)nCount;
  78. }
  79. return 0;
  80. }
  81. int StringWriter16(const char16_t* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext16, WriteFunctionState /*wfs*/)
  82. {
  83. using namespace SprintfLocal;
  84. SnprintfContext16* const pSnprintfContext16 = (SnprintfContext16*)pContext16;
  85. if(nCount > (pSnprintfContext16->mnMaxCount - pSnprintfContext16->mnCount)) // If nCount results in an exhausting of the limit...
  86. nCount = pSnprintfContext16->mnMaxCount - pSnprintfContext16->mnCount;
  87. memcpy(pSnprintfContext16->mpDestination + pSnprintfContext16->mnCount, pData, nCount * sizeof(char16_t));
  88. pSnprintfContext16->mnCount += nCount;
  89. return (int)(unsigned)nCount;
  90. }
  91. int StringWriter32(const char32_t* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext32, WriteFunctionState /*wfs*/)
  92. {
  93. using namespace SprintfLocal;
  94. SnprintfContext32* const pSnprintfContext32 = (SnprintfContext32*)pContext32;
  95. if(nCount > (pSnprintfContext32->mnMaxCount - pSnprintfContext32->mnCount)) // If nCount results in an exhausting of the limit...
  96. nCount = pSnprintfContext32->mnMaxCount - pSnprintfContext32->mnCount;
  97. memcpy(pSnprintfContext32->mpDestination + pSnprintfContext32->mnCount, pData, nCount * sizeof(char32_t));
  98. pSnprintfContext32->mnCount += nCount;
  99. return (int)(unsigned)nCount;
  100. }
  101. int FILEWriter8(const char* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext8, WriteFunctionState /*wfs*/)
  102. {
  103. FILE* const pFile = (FILE*)pContext8;
  104. const size_t nResult = fwrite(pData, sizeof(char), nCount, pFile); // It's OK if nCount == 0.
  105. if(nResult == nCount)
  106. return (int)(unsigned)nResult;
  107. return -1;
  108. }
  109. int FILEWriter16(const char16_t* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext16, WriteFunctionState /*wfs*/)
  110. {
  111. FILE* const pFile = (FILE*)pContext16;
  112. const size_t nResult = fwrite(pData, sizeof(char16_t), nCount, pFile); // It's OK if nCount == 0.
  113. if(nResult == nCount)
  114. return (int)(unsigned)nResult;
  115. return -1;
  116. }
  117. int FILEWriter32(const char32_t* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext32, WriteFunctionState /*wfs*/)
  118. {
  119. FILE* const pFile = (FILE*)pContext32;
  120. const size_t nResult = fwrite(pData, sizeof(char32_t), nCount, pFile); // It's OK if nCount == 0.
  121. if(nResult == nCount)
  122. return (int)(unsigned)nResult;
  123. return -1;
  124. }
  125. ///////////////////////////////////////////////////////////////////////////////
  126. // PlatformLogWriter8
  127. //
  128. int PlatformLogWriter8(const char* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext8, WriteFunctionState)
  129. {
  130. #if defined(EA_PLATFORM_ANDROID)
  131. // The __android_log_write function appends a \n to every call you make to it. This is a problem for
  132. // us because during a sprintf of a single string we call our Writer multiple times. If we just called
  133. // __android_log_write for every Writer call, a single sprintf would be split across multiple trace lines,
  134. // and \n are also (I think) ignored.
  135. size_t countOriginal = nCount;
  136. if(nCount)
  137. {
  138. const size_t kBufferSize = EAArrayCount(PlatformLogWriterContext8::mBuffer);
  139. const size_t kBufferSizeActual = kBufferSize - 1; // -1 because we need to save space for a terminating 0 char that __android_log_write wants.
  140. const size_t kPlatformBufferSize = 512; // This is the size that's the max size the platform's log-writing function can handle.
  141. const size_t kPlatformBufferSizeActual = kPlatformBufferSize - 1; // -1 because we need to save space for a terminating 0 char that __android_log_write wants.
  142. const size_t kMaxCountActual = (kBufferSizeActual < kPlatformBufferSizeActual) ? kBufferSizeActual : kPlatformBufferSizeActual;
  143. PlatformLogWriterContext8 *pWriteInfo = reinterpret_cast<PlatformLogWriterContext8*>(pContext8);
  144. // Pick the smaller of the two buffers.
  145. for(size_t i = 0; i < nCount; i++)
  146. {
  147. pWriteInfo->mBuffer[pWriteInfo->mPosition] = pData[i];
  148. if((pData[i] == '\n') || (pWriteInfo->mPosition == kMaxCountActual)) // If the user is requesting a newline or if we have exhausted the most we can write in a single line...
  149. {
  150. if(pWriteInfo->mPosition == kMaxCountActual)
  151. pWriteInfo->mPosition++;
  152. pWriteInfo->mBuffer[pWriteInfo->mPosition] = 0;
  153. __android_log_write(ANDROID_LOG_INFO, "EAStdC.Printf", pWriteInfo->mBuffer);
  154. pWriteInfo->mPosition = 0;
  155. pWriteInfo->mBuffer[0] = 0;
  156. }
  157. else
  158. pWriteInfo->mPosition++;
  159. }
  160. }
  161. return (int)(unsigned)countOriginal;
  162. #else
  163. EA_UNUSED(pContext8);
  164. // To do: buffer debug writes and flush the buffer at WriteFunctionState == kWFSEnd, because otherwise a
  165. // single Dprintf call could result in numerous calls to (for example) OutputDebugString instead of just one call.
  166. // A good way to do this is to have the buffer be part of the void* context; that way we don't have to worry about
  167. // having thread-local storage.
  168. if(nCount)
  169. {
  170. if(pData[nCount] == 0) // If already 0-terminated...
  171. {
  172. #if EASTDC_OUTPUTDEBUGSTRING_ENABLED
  173. OutputDebugStringA(pData);
  174. #else
  175. fputs(pData, stdout);
  176. #if defined(EA_PLATFORM_MOBILE)
  177. fflush(stdout); // Mobile platforms need this because otherwise you can easily lose output if the device crashes while not all the output has been written.
  178. #endif
  179. #endif
  180. }
  181. else
  182. {
  183. // Copy to a buffer first, taking into account that nCount may be larger than our buffer size.
  184. size_t i, iEnd, charIndex = 0;
  185. char buffer[512];
  186. while(charIndex < nCount)
  187. {
  188. for(i = 0, iEnd = (EAArrayCount(buffer) - 1); (i < iEnd) && (charIndex < nCount); ++i, ++charIndex)
  189. buffer[i] = pData[charIndex];
  190. buffer[i] = 0;
  191. #if EASTDC_OUTPUTDEBUGSTRING_ENABLED
  192. OutputDebugStringA(buffer);
  193. #else
  194. fputs(buffer, stdout);
  195. #if defined(EA_PLATFORM_MOBILE)
  196. fflush(stdout); // Mobile platforms need this because otherwise you can easily lose output if the device crashes while not all the output has been written.
  197. #endif
  198. #endif
  199. }
  200. }
  201. }
  202. return static_cast<int>(nCount);
  203. #endif
  204. }
  205. ///////////////////////////////////////////////////////////////////////////////
  206. // EASprintfInit
  207. //
  208. void EASprintfInit()
  209. {
  210. }
  211. ///////////////////////////////////////////////////////////////////////////////
  212. // EASprintfShutdown
  213. //
  214. void EASprintfShutdown()
  215. {
  216. }
  217. ///////////////////////////////////////////////////////////////////////////////
  218. // Helper template to avoid including EASTL
  219. //
  220. template<typename T, typename U>
  221. struct IsSameType
  222. {
  223. enum { value = 0 };
  224. };
  225. template<typename T>
  226. struct IsSameType<T, T>
  227. {
  228. enum { value = 1 };
  229. };
  230. ///////////////////////////////////////////////////////////////////////////////
  231. // WriteLeftPadding
  232. //
  233. // If the formatted data is right aligned, then this function prefixes the
  234. // output with the appropriate data.
  235. //
  236. template <typename CharT>
  237. static int WriteLeftPadding(int(*pWriteFunction)(const CharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  238. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, const CharT*& pBufferData, int nWriteCount)
  239. {
  240. if(fd.mAlignment == kAlignmentLeft || fd.mnWidth <= nWriteCount)
  241. return 0;
  242. CharT nFill;
  243. if(fd.mAlignment == kAlignmentZeroFill)
  244. {
  245. nFill = '0';
  246. if(pBufferData && ((*pBufferData == '+') || (*pBufferData == '-') || (*pBufferData == ' ')))
  247. { // Skip zero fill for leading sign character.
  248. if(pWriteFunction(pBufferData, 1, pWriteFunctionContext, kWFSIntermediate) == -1)
  249. return -1; // This is an error; not the same as running out of space.
  250. --nWriteCount;
  251. ++pBufferData;
  252. }
  253. }
  254. else
  255. nFill = ' ';
  256. int nFillCount = fd.mnWidth - nWriteCount;
  257. for(int i = 0; i < nFillCount; ++i)
  258. {
  259. // Consider making an optimization which writes more than one fill character at a time.
  260. // We can do this by using the space at the beginning of pBuffer;
  261. if(pWriteFunction(&nFill, 1, pWriteFunctionContext, kWFSIntermediate) == -1)
  262. return -1; // This is an error; not the same as running out of space.
  263. }
  264. return nFillCount;
  265. }
  266. ///////////////////////////////////////////////////////////////////////////////
  267. // WriteRightPadding
  268. //
  269. // If the formatted data is left aligned, then this function suffixes the
  270. // output with the appropriate data.
  271. //
  272. template <typename CharT>
  273. static int WriteRightPadding(int(*pWriteFunction)(const CharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  274. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, int nWriteCount)
  275. {
  276. if(fd.mAlignment != kAlignmentLeft || fd.mnWidth <= nWriteCount)
  277. return 0;
  278. const CharT nSpace = ' ';
  279. int nFillCount = fd.mnWidth - nWriteCount;
  280. for(int i = 0; i < nFillCount; ++i)
  281. {
  282. if(pWriteFunction(&nSpace, 1, pWriteFunctionContext, kWFSIntermediate) == -1)
  283. return -1; // This is an error; not the same as running out of space.
  284. }
  285. return nFillCount;
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////
  288. // WriteBuffer
  289. //
  290. // Write the given buffer with the required left and right padding
  291. //
  292. template <typename CharT>
  293. static int WriteBuffer(int(*pWriteFunction)(const CharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  294. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, const CharT* pBufferData, int nWriteCount)
  295. {
  296. const CharT* pBufferDataEnd = pBufferData + nWriteCount;
  297. int nWriteCountCurrent = nWriteCount; // We will write at least as much nWriteCount, possibly more if the format specified a specific width.
  298. int nFillCount = WriteLeftPadding(pWriteFunction, pWriteFunctionContext, fd, pBufferData, nWriteCount);
  299. if(nFillCount < 0)
  300. return -1; // This is an error; not the same as running out of space.
  301. nWriteCountCurrent += nFillCount;
  302. if(pBufferData != pBufferDataEnd && (pWriteFunction(pBufferData, pBufferDataEnd - pBufferData, pWriteFunctionContext, kWFSIntermediate) == -1))
  303. return -1; // This is an error; not the same as running out of space.
  304. nFillCount = WriteRightPadding(pWriteFunction, pWriteFunctionContext, fd, nWriteCountCurrent);
  305. if(nFillCount < 0)
  306. return -1; // This is an error; not the same as running out of space.
  307. nWriteCountCurrent += nFillCount;
  308. return nWriteCountCurrent;
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. // StringNull
  312. //
  313. // Based on the character type, return the appropriate (null) string.
  314. //
  315. template <typename CharT>
  316. const CharT* StringNull();
  317. template <>
  318. const char* StringNull<char>() { return kStringNull8; }
  319. template <>
  320. const char16_t* StringNull<char16_t>() { return kStringNull16; }
  321. template <>
  322. const char32_t* StringNull<char32_t>() { return kStringNull32; }
  323. ///////////////////////////////////////////////////////////////////////////////
  324. // StringFormatLength
  325. //
  326. template <typename CharT>
  327. int StringFormatLength(const SprintfLocal::FormatData& fd, const CharT* pInBufferData)
  328. {
  329. // For strings, the precision modifier refers to the number of chars to display.
  330. if(fd.mnPrecision != kNoPrecision) // If the user specified some precision...
  331. {
  332. // Find which is shorter, the length or the precision.
  333. const CharT* pBufferCurrent = pInBufferData;
  334. const CharT* const pBufferMax = pInBufferData + fd.mnPrecision;
  335. while((pBufferCurrent < pBufferMax) && *pBufferCurrent)
  336. ++pBufferCurrent;
  337. return (int)(pBufferCurrent - pInBufferData);
  338. }
  339. else
  340. {
  341. // Set the write count to be the string length.
  342. // Don't call strlen, as that would jump outside this module.
  343. const CharT* pBufferCurrent = pInBufferData;
  344. while(*pBufferCurrent) // Implement a small inline strlen.
  345. ++pBufferCurrent;
  346. return (int)(pBufferCurrent - pInBufferData);
  347. }
  348. }
  349. ///////////////////////////////////////////////////////////////////////////////
  350. // StringFormatHelper
  351. //
  352. // This is a structure template since we want to do partial specialization and it could be the case that some
  353. // compilers don't support it. There are two forms of the implementation. The first is when the
  354. // in and out types are the same. In that case we can use the input buffer as the output buffer and do
  355. // no conversions. When they are different, we are required to convert from one encoding to another.
  356. //
  357. template <bool IsSameType, typename InCharT, typename OutCharT>
  358. struct StringFormatHelper
  359. {};
  360. template <typename InCharT, typename OutCharT>
  361. struct StringFormatHelper<true, InCharT, OutCharT>
  362. {
  363. int operator()(int(*pWriteFunction)(const OutCharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  364. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, OutCharT* pScratchBuffer, const InCharT* pInBufferData)
  365. {
  366. EA_UNUSED(pScratchBuffer);
  367. int nWriteCount = StringFormatLength(fd, pInBufferData);
  368. return WriteBuffer(pWriteFunction, pWriteFunctionContext, fd, pInBufferData, nWriteCount);
  369. }
  370. };
  371. template <typename InCharT, typename OutCharT>
  372. struct StringFormatHelper<false, InCharT, OutCharT>
  373. {
  374. int operator()(int(*pWriteFunction)(const OutCharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  375. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, OutCharT* pScratchBuffer, const InCharT* pInBufferData)
  376. {
  377. // We have a problem here. We are converting from one encoding to another.
  378. // The only encoding that are supported are UTF-8, UCS-2 and UCS-4. Any
  379. // other encoding can result in a loss of data or failure to reencode.
  380. // Compute the input number of code units
  381. int nInCodeUnits;
  382. {
  383. const InCharT* pInBufferCurrent = pInBufferData;
  384. while(*pInBufferCurrent) // Implement a small inline strlen.
  385. ++pInBufferCurrent;
  386. nInCodeUnits = (int)(pInBufferCurrent - pInBufferData);
  387. }
  388. const InCharT* pInBufferDataEnd = pInBufferData + nInCodeUnits;
  389. int nPrecision = fd.mnPrecision == kNoPrecision ? INT_MAX : fd.mnPrecision; // Don't assume the value of kNoPrecision
  390. // If the input is empty or precision is zero, then write an empty buffer and return
  391. if(nInCodeUnits == 0 || nPrecision == 0)
  392. {
  393. return WriteBuffer(pWriteFunction, pWriteFunctionContext, fd, pScratchBuffer, 0);
  394. }
  395. int nWriteCountSum = 0;
  396. bool bFirstTime = true;
  397. while(nPrecision != 0 && pInBufferData != pInBufferDataEnd)
  398. {
  399. // Compute the required output size. Truncate if we have a precision
  400. size_t outSize = (size_t)(unsigned)kConversionBufferSize;
  401. if((size_t)nPrecision < outSize)
  402. {
  403. outSize = (size_t)(unsigned)fd.mnPrecision + 1;
  404. nPrecision = 0;
  405. }
  406. else
  407. nPrecision -= kConversionBufferSize - 1;
  408. // Convert the string
  409. size_t nOutUsed;
  410. size_t nInUsed;
  411. if(!Strlcpy(pScratchBuffer, pInBufferData, outSize, pInBufferDataEnd - pInBufferData, nOutUsed, nInUsed))
  412. break;
  413. // If we haven't done the left padding
  414. if(bFirstTime)
  415. {
  416. int nWriteCount = static_cast<int>(nOutUsed);
  417. if(nPrecision != 0 && nInUsed < (size_t)nInCodeUnits)
  418. {
  419. int nRemaining = Strlcpy((OutCharT*)nullptr, pInBufferData + nInUsed, 0, nInCodeUnits - nInUsed);
  420. if(nRemaining < 0)
  421. break;
  422. nWriteCount += nRemaining;
  423. if(fd.mnPrecision != kNoPrecision && fd.mnPrecision < nWriteCount)
  424. nWriteCount = fd.mnPrecision;
  425. }
  426. const OutCharT* pTemp = pScratchBuffer;
  427. int nFillCount = WriteLeftPadding(pWriteFunction, pWriteFunctionContext, fd, pTemp, nWriteCount);
  428. EA_ASSERT(pTemp == pScratchBuffer); // should not get adjusted
  429. if(nFillCount < 0)
  430. return -1;
  431. nWriteCountSum += nFillCount;
  432. bFirstTime = false;
  433. }
  434. // Write the converted buffer
  435. if(nOutUsed != 0 && (pWriteFunction(pScratchBuffer, nOutUsed, pWriteFunctionContext, kWFSIntermediate) == -1))
  436. return -1; // This is an error; not the same as running out of space.
  437. nWriteCountSum += static_cast<int>(nOutUsed);
  438. // Advance the input
  439. pInBufferData += nInUsed;
  440. }
  441. // If required, write the end
  442. if(!bFirstTime)
  443. {
  444. int nFillCount = WriteRightPadding(pWriteFunction, pWriteFunctionContext, fd, nWriteCountSum);
  445. if(nFillCount < 0)
  446. return -1;
  447. nWriteCountSum += nFillCount;
  448. }
  449. return nWriteCountSum;
  450. }
  451. };
  452. ///////////////////////////////////////////////////////////////////////////////
  453. // StringFormat
  454. //
  455. // Check for a null input and/or reencode the input as requred. The output string
  456. // length is returned and pointed to by ppOutBufferData.
  457. //
  458. template <typename InCharT, typename OutCharT>
  459. int StringFormat(int(*pWriteFunction)(const OutCharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs),
  460. void* EA_RESTRICT pWriteFunctionContext, const SprintfLocal::FormatData& fd, OutCharT* pScratchBuffer, const InCharT* pInBufferData)
  461. {
  462. // I don't see the C99 standard specifying the behaviour for a NULL string pointer,
  463. // but both GCC and MSVC use "(null)" when such a NULL pointer is encountered.
  464. if(pInBufferData == nullptr)
  465. {
  466. StringFormatHelper<true, OutCharT, OutCharT> helper;
  467. return helper(pWriteFunction, pWriteFunctionContext, fd, pScratchBuffer, StringNull<OutCharT>());
  468. }
  469. else
  470. {
  471. StringFormatHelper<IsSameType<InCharT, OutCharT>::value, InCharT, OutCharT> helper;
  472. return helper(pWriteFunction, pWriteFunctionContext, fd, pScratchBuffer, pInBufferData);
  473. }
  474. }
  475. ///////////////////////////////////////////////////////////////////////////////
  476. // ReadFormat
  477. //
  478. // Reads the current format into FormatData. Return value is pointer to first
  479. // char after the format data.
  480. //
  481. // To know how printf truly needs to work, see the ISO C 1999 standard, section 7.19.6.1.
  482. // See http://www.cplusplus.com/ref/cstdio/printf.html or http://www.opengroup.org/onlinepubs/007908799/xsh/fprintf.html
  483. // for decent basic online documentation about how printf is supposed to work.
  484. //
  485. // Argument pFormat is a string pointing to a % format specification of the form:
  486. // %[flags][width][.precision][modifiers]type
  487. //
  488. ///////////////////////////////////////////////////////////////////////////////
  489. //
  490. template <typename CharT>
  491. const CharT* ReadFormat(const CharT* EA_RESTRICT pFormat, SprintfLocal::FormatData* EA_RESTRICT pFormatData, va_list* EA_RESTRICT pArguments)
  492. {
  493. using namespace SprintfLocal;
  494. const CharT* pFormatCurrent = pFormat;
  495. Alignment alignmentNonZeroFill = kAlignmentLeft; // We have a chicken and egg problem in that the zero-fill alignment may or may not be ignored. So we save the value here for what the alignment would be if zero-fill needs to be ignored.
  496. FormatData fd;
  497. CharT c;
  498. // Check for "%%". This is a quick test for early exit.
  499. if((c = *++pFormatCurrent) == '%') // If the user specified "%%"...
  500. {
  501. fd.mnType = '%';
  502. *pFormatData = fd; // pFormatData->mnType = '%'; Consider instead using just this line of code.
  503. return pFormatCurrent + 1;
  504. }
  505. // Check for flags field
  506. for(; ; (c = *++pFormatCurrent)) // Check for one or more flags ('-', '+', ' ', '#', or '0')
  507. {
  508. switch(c)
  509. {
  510. case '-': // '-' controls alignment, not the +/- sign before numbers.
  511. fd.mAlignment = kAlignmentLeft;
  512. break;
  513. case '+':
  514. fd.mSign = kSignMinusPlus;
  515. break;
  516. case ' ': // The C99 language states (7.19.6.1.6): "If the space and + flags both appear, the space flag is ignored."
  517. if(fd.mSign != kSignMinusPlus)
  518. fd.mSign = kSignSpace;
  519. break;
  520. case '#': // The C99 standard states (7.19.6.1.6): The result is converted to an "alternative form."
  521. fd.mbAlternativeForm = true;
  522. break;
  523. case '\'': // Non-standard but common extension. e.g. http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/printf.3.html
  524. fd.mbDisplayThousands = true;
  525. break;
  526. case '0': // The C99 standard states (7.19.6.1.6): If the 0 and - flags both appear, the 0 flag is ignored. For d, i, o, u, x, and X conversions, if a precision is specified, the 0 flag is ignored. For other conversions, the behavior is undefined.
  527. if(fd.mAlignment != kAlignmentLeft) // Note that '0' is a flag (which can appear in any order) and not part of the number. This is a common misconception.
  528. {
  529. if(fd.mAlignment != kAlignmentZeroFill) // The C99 standard says that for string fields, 0 fill means space fill.
  530. alignmentNonZeroFill = fd.mAlignment;
  531. fd.mAlignment = kAlignmentZeroFill;
  532. }
  533. break;
  534. default:
  535. goto EndFlagCheck; // C/C++ unfortunately don't provide an efficient mechanism to break from multiple loops other than 'goto'. We could avoid the goto with alternative logic, but that would be less efficient.
  536. }
  537. }
  538. EndFlagCheck:
  539. // Check for width field.
  540. // The C99 standard states (7.19.6.1.5): A field width, or precision, or both, may be
  541. // indicated by an asterisk. In this case, an int argument supplies the field width or
  542. // precision. The arguments specifying field width, or precision, or both, shall appear
  543. // (in that order) before the argument (if any) to be converted. A negative field
  544. // width argument is taken as a - flag followed by a positive field width.
  545. // A negative precision argument is taken as if the precision were omitted.
  546. if(c == '*')
  547. {
  548. fd.mnWidth = va_arg(*pArguments, int);
  549. if(fd.mnWidth < 0)
  550. {
  551. fd.mAlignment = kAlignmentLeft; // Pretend that a '-' flag was applied, as specified by the standard.
  552. fd.mnWidth = -fd.mnWidth;
  553. }
  554. c = *++pFormatCurrent;
  555. }
  556. else
  557. {
  558. // Read the width numerical value. We don't do error checking here as it
  559. // would incur a performance penalty that just isn't worth it to us.
  560. while(((unsigned)(c - '0')) < 10) // Don't call isdigit() here because that might cause a data cache miss.
  561. {
  562. fd.mnWidth = (int)((fd.mnWidth * 10) + (c - '0')); // Consider if there is any way to make this loop more
  563. c = *++pFormatCurrent; // efficient by reducing multiplies, etc.
  564. }
  565. }
  566. if(fd.mnWidth > kMaxWidth)
  567. {
  568. // Note that we leave fd.mnType as zero, indicating an error.
  569. *pFormatData = fd; // pFormatData->mnType = 0; Consider instead using just this line of code.
  570. return pFormatCurrent + 1;
  571. }
  572. // Check for precision field.
  573. // An optional precision that gives the minimum number of digits to appear for the
  574. // d, i, o, u, x, and X conversions, the number of digits to appear after the decimal-point
  575. // character for a, A, e, E, f, and F conversions, the maximum number of significant
  576. // digits for the g and G conversions, or the maximum number of bytes to be written for
  577. // s conversions. The precision takes the form of a period (.) followed either by an
  578. // asterisk * (described later) or by an optional decimal integer; if only the period
  579. // is specified, the precision is taken as zero. If a precision appears with any other
  580. // conversion specifier, the behavior is undefined.
  581. if(c == (CharT)pFormatData->mDecimalPoint) // If precision is specified...
  582. {
  583. if((c = *++pFormatCurrent) == '*') // If the precision is set as a value passed in as an argument...
  584. {
  585. fd.mnPrecision = va_arg(*pArguments, int);
  586. if(fd.mnPrecision < 0)
  587. fd.mnPrecision = 0;
  588. c = *++pFormatCurrent;
  589. }
  590. else
  591. {
  592. fd.mnPrecision = 0;
  593. while(((unsigned)(c - '0')) < 10) // Don't call isdigit() here because that might cause a data cache miss.
  594. {
  595. // Consider doing error checking
  596. fd.mnPrecision = (int)((fd.mnPrecision * 10) + (c - '0'));
  597. c = *++pFormatCurrent;
  598. }
  599. }
  600. }
  601. // Check for length modifier field. C99 standard section 7.19.6.1.7.
  602. // We support the following modifiers, which include non-standard integer size-specific modifiers.
  603. // hh, h, l, ll, I8, I16, I32, I64, I128
  604. bool bModifierPresent = true; // True until proven false below.
  605. switch(c)
  606. {
  607. case 'h':
  608. if(pFormatCurrent[1] == 'h') // If the user specified %hh ...
  609. {
  610. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); or that a following n conversion specifier applies to a pointer to a signed char argument.
  611. fd.mModifier = kModifierChar;
  612. c = *++pFormatCurrent;
  613. }
  614. else // Else the user specified just %h
  615. {
  616. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing); or that a following n conversion specifier applies to a pointer to a short int argument.
  617. fd.mModifier = kModifierShort;
  618. }
  619. break;
  620. case 'l': // Check for ell (not one).
  621. if(pFormatCurrent[1] == 'l') // If the user specified %ll ...
  622. {
  623. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long long int or unsigned long long int argument; or that a following n conversion specifier applies to a pointer to a long long int argument.
  624. fd.mModifier = kModifierLongLong;
  625. c = *++pFormatCurrent;
  626. }
  627. else // Else the user specified just %l
  628. {
  629. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument; that a following n conversion specifier applies to a pointer to a long int argument; that a following c conversion specifier applies to a wint_t argument; that a following s conversion specifier applies to a pointer to a wchar_t argument; or has no effect on a following a, A, e, E, f, F, g, or G conversion specifier.
  630. fd.mModifier = kModifierLong;
  631. }
  632. break;
  633. case 'q':
  634. // BSD-based OS's use %q to indicate "quad int", which is the same as "long long". We need to support it because iPhone's C99 headers define PRId64 as "qd".
  635. fd.mModifier = kModifierLongLong;
  636. break;
  637. case 'j':
  638. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to an intmax_t or uintmax_t argument; or that a following n conversion specifier applies to a pointer to an intmax_t argument.
  639. fd.mModifier = kModifierMax_t;
  640. break;
  641. case 'z':
  642. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a size_t or the corresponding signed integer type argument; or that a following n conversion specifier applies to a pointer to a signed integer type corresponding to size_t argument.
  643. fd.mModifier = kModifierSize_t;
  644. break;
  645. case 't':
  646. // Specifies that a following d, i, o, u, x, or X conversion specifier applies to a ptrdiff_t or the corresponding unsigned integer type argument; or that a following n conversion specifier applies to a pointer to a ptrdiff_t argument.
  647. fd.mModifier = kModifierPtrdiff_t;
  648. break;
  649. case 'L':
  650. // Specifies that a following a, A, e, E, f, F, g, or G conversion specifier applies to a long double argument.
  651. fd.mModifier = kModifierLongDouble;
  652. break;
  653. case 'I':
  654. if(pFormatCurrent[1] == '8') // If the user specified %I8 ...
  655. {
  656. fd.mModifier = kModifierInt8;
  657. c = *++pFormatCurrent; // Account for the '8' part of I8. We'll account for the 'I' part below for all formats.
  658. }
  659. else if((pFormatCurrent[1] == '1') && (pFormatCurrent[2] == '6'))
  660. {
  661. fd.mModifier = kModifierInt16;
  662. c = *(pFormatCurrent += 2);
  663. }
  664. else if((pFormatCurrent[1] == '3') && (pFormatCurrent[2] == '2'))
  665. {
  666. fd.mModifier = kModifierInt32;
  667. c = *(pFormatCurrent += 2);
  668. }
  669. else if((pFormatCurrent[1] == '6') && (pFormatCurrent[2] == '4'))
  670. {
  671. fd.mModifier = kModifierInt64;
  672. c = *(pFormatCurrent += 2); // Account for the '64' part of I64. We'll account for the 'I' part below for all formats.
  673. }
  674. else if((pFormatCurrent[1] == '1') && (pFormatCurrent[2] == '2') && (pFormatCurrent[3] == '8'))
  675. {
  676. fd.mModifier = kModifierInt128;
  677. c = *(pFormatCurrent += 3);
  678. }
  679. else // Else the specified modifier was invalid.
  680. {
  681. // Note that we leave fd.mnType as zero, indicating an error.
  682. *pFormatData = fd; // pFormatData->mnType = kFormatError; // Consider instead using just this line of code.
  683. return pFormatCurrent + 1;
  684. }
  685. break;
  686. default:
  687. bModifierPresent = false;
  688. }
  689. if(bModifierPresent)
  690. c = *++pFormatCurrent; // Move the pointer past the format (e.g. the 'f' in "%3.1f")
  691. // Read the conversion type. This must be present.
  692. fd.mnType = (int)c;
  693. switch(c)
  694. {
  695. case 'b': // unsigned binary. This is a convenient extension that we add.
  696. case 'd': // signed
  697. case 'i': // signed
  698. case 'u': // unsigned
  699. case 'o': // unsigned
  700. case 'x': // unsigned
  701. case 'X': // unsigned
  702. if(fd.mnPrecision == kNoPrecision)
  703. fd.mnPrecision = 1;
  704. else if(fd.mAlignment == kAlignmentZeroFill)
  705. fd.mAlignment = kAlignmentRight;
  706. break;
  707. case 'g':
  708. case 'G':
  709. if(fd.mnPrecision == 0) // For %g, if the precision is zero, it is taken as 1.
  710. fd.mnPrecision = 1;
  711. // fall through
  712. case 'e':
  713. case 'E':
  714. case 'f':
  715. case 'F':
  716. case 'a': // See the C99 standard, section 7.19.6.1.8, for details on 'a' formatting.
  717. case 'A':
  718. if(fd.mnPrecision == kNoPrecision)
  719. fd.mnPrecision = 6; // The C99 standard explicitly states that this defaults to 6.
  720. break;
  721. case 'p':
  722. if(sizeof(void*) == 2)
  723. fd.mModifier = kModifierInt16;
  724. else if(sizeof(void*) == 4)
  725. fd.mModifier = kModifierInt32;
  726. else
  727. fd.mModifier = kModifierInt64;
  728. fd.mnPrecision = sizeof(void*) / 4; // This is 8 for a 32 bit pointer, 16 for a 64 bit pointer.
  729. fd.mnType = 'x';
  730. // For the "alternative form" of x (or X) conversion, a nonzero result has 0x (or 0X) prefixed to it.
  731. // So if the user uses %#p, then the user gets something like 0x12345678, whereas otherwise the
  732. // user gets just 12345678.
  733. break;
  734. case 'c': // We accept %hc, %c, %lc, %I8c, %I16c, %I32c (regular, regular, wide, char, char16_t, char32_t)
  735. case 'C': // We accept %hC, %C, %lC, %I8C, %I16C, %I32C (regular, wide, wide, char, char16_t, char32_t)
  736. case 's': // We accept %hs, %s, %ls, %I8s, %I16s, %I32s (regular, regular, wide, char, char16_t, char32_t)
  737. case 'S': // We accept %hS, %S, %lS, %I8s, %I16s, %I32s (regular, wide, wide, char, char16_t, char32_t)
  738. // If the user specified zero-fill above, then it is a mistake and we
  739. // need to use spaces instead. So we restore the fallback alignment.
  740. if(fd.mAlignment == kAlignmentZeroFill)
  741. fd.mAlignment = alignmentNonZeroFill;
  742. // Microsoft's library goes against the standard: %s is
  743. // interpreted to mean char string but instead is interpreted
  744. // to be either char or wchar_t depending on what the output
  745. // text format is. This is non-standard but has the convenience
  746. // of allowing users to migrate between char and wchar_t usage
  747. // more easily. So we allow EASPRINTF_MS_STYLE_S_FORMAT to control this.
  748. if(fd.mModifier == kModifierShort)
  749. fd.mModifier = kModifierChar;
  750. else if(fd.mModifier == kModifierLong)
  751. fd.mModifier = kModifierWChar;
  752. else if(fd.mModifier == kModifierNone) // If the user hasn't already specified, for example %I16.
  753. {
  754. #if EASPRINTF_MS_STYLE_S_FORMAT
  755. if((c == 's') || (c == 'c'))
  756. fd.mModifier = (sizeof(*pFormat) == sizeof(char)) ? kModifierChar : kModifierWChar;
  757. else
  758. fd.mModifier = (sizeof(*pFormat) == sizeof(char)) ? kModifierWChar : kModifierChar;
  759. #else
  760. if((c == 's') || (c == 'c'))
  761. fd.mModifier = kModifierChar;
  762. else
  763. fd.mModifier = kModifierWChar;
  764. #endif
  765. }
  766. //else if((fd.mModifier < kModifierInt8) || (fd.mModifier > kModifierInt32)) // This expression assumes that Int8, Int16, Int32 are contiguous enum values.
  767. //{
  768. // EA_FAIL_MSG("Printf: Invalid %s modifier");
  769. //}
  770. break;
  771. case 'n':
  772. // The argument shall be a pointer to signed integer into which is written the
  773. // number of characters written to the output stream so far by this call to printf.
  774. // No argument is converted, but one is consumed. If the conversion specification
  775. // includes any flags, a field width, or a precision, the behavior is undefined.
  776. // We don't really have anything to do here, as this function is merely reading
  777. // the format and not acting on it. The caller will act on this appropriately.
  778. break;
  779. }
  780. // If the field width is too long and it's not a string field...
  781. if((fd.mnPrecision > kMaxPrecision) && (fd.mnPrecision != kNoPrecision) && ((fd.mnType != 's') && (fd.mnType != 'S')))
  782. fd.mnType = kFormatError;
  783. // Note that at his point we haven't read the argument corresponding to the formatted value.
  784. // We save this for the parent function, as otherwise we'd need some kind of union here to
  785. // hold all value types.
  786. *pFormatData = fd;
  787. return pFormatCurrent + 1;
  788. }
  789. ///////////////////////////////////////////////////////////////////////////////
  790. // WriteLongHelper
  791. //
  792. // Writes the given lValue to the given buffer and returns the start of the
  793. // data or returns NULL for error. Note that the buffer is passed in as the
  794. // end of the buffer and not the beginning. This is a common trick used when
  795. // converting integer values to strings, as the conversion algorithm needs
  796. // to work backwards as it is and it's quicker to simply start with the end
  797. // of the buffer and move backwards.
  798. //
  799. template <typename CharT, typename ValueT, typename UValueT>
  800. CharT* WriteLongHelper(const SprintfLocal::FormatData& fd, ValueT lValue, CharT* EA_RESTRICT pBufferEnd)
  801. {
  802. using namespace SprintfLocal;
  803. UValueT ulValue = (UValueT)lValue;
  804. unsigned int nBase;
  805. unsigned int nShift = 0;
  806. unsigned int nAnd = 0;
  807. Sign sign = kSignNone;
  808. CharT* pCurrent = pBufferEnd;
  809. int nDigitCount = 0;
  810. int nDigitCountSum = fd.mnPrecision;
  811. bool bNegative = false;
  812. *--pCurrent = 0;
  813. if((lValue > 0) || (fd.mnPrecision > 0) || fd.mbAlternativeForm)
  814. {
  815. // Do initial setup.
  816. switch(fd.mnType)
  817. {
  818. case 'b': // Binary (this is non-standard, though many would like it to be so)
  819. nBase = 2;
  820. nShift = 0x01;
  821. nAnd = 0x01;
  822. break;
  823. case 'o': // Octal
  824. nBase = 8;
  825. nShift = 0x03;
  826. nAnd = 0x07;
  827. break;
  828. case 'd': // Decimal (signed)
  829. case 'i': // i and d are defined by the standard to be the same.
  830. default:
  831. nBase = 10;
  832. sign = fd.mSign;
  833. if(lValue < 0)
  834. {
  835. ulValue = (UValueT)-lValue;
  836. bNegative = true;
  837. }
  838. break;
  839. case 'u': // Decimal (unsigned)
  840. nBase = 10;
  841. break;
  842. case 'x': // Hexidecimal
  843. case 'X':
  844. nBase = 16;
  845. nShift = 0x04;
  846. nAnd = 0x0f;
  847. break;
  848. }
  849. // Write the individual digits.
  850. // To do: Use the optimization in EAString.cpp's X64toaCommon10 function
  851. // to significantly improve writing base 10 strings.
  852. // Optimization: Replace the % and / below with >> and & for cases where
  853. // we can do this (i.e. nBase = even power of two).
  854. do
  855. {
  856. int nDigit;
  857. if(nBase == 10)
  858. {
  859. nDigit = (int)(ulValue % nBase);
  860. ulValue /= nBase;
  861. }
  862. else // Else take faster pathway.
  863. {
  864. nDigit = (int)(ulValue & nAnd);
  865. ulValue >>= nShift;
  866. }
  867. if(nDigit < 10)
  868. nDigit = '0' + nDigit;
  869. else
  870. {
  871. nDigit -= 10;
  872. if(fd.mnType == 'x')
  873. nDigit = 'a' + nDigit;
  874. else
  875. nDigit = 'A' + nDigit;
  876. }
  877. *--pCurrent = (CharT)nDigit;
  878. ++nDigitCount;
  879. if((nBase == 10) && (fd.mbDisplayThousands) && (ulValue > 0) && (((nDigitCount + 1) % 4) == 0))
  880. {
  881. *--pCurrent = (CharT)fd.mThousandsSeparator;
  882. ++nDigitCount; // Even though the thousands separator isn't strictly a digit, it counts towards the space used by the number, which is what matters here.
  883. }
  884. } while(ulValue > 0);
  885. // For octal mode, the standard specifies that when 'alternative form' is enabled,
  886. // the number is prefixed with a zero. This is like how the C language interprets
  887. // integers that begin with zero as octal.
  888. if((nBase == 8) && fd.mbAlternativeForm && (*pCurrent != (CharT)'0'))
  889. {
  890. *--pCurrent = (CharT)'0';
  891. ++nDigitCount;
  892. }
  893. // Calculate any leading zeroes required by the 'zero fill' alignment option.
  894. if(fd.mAlignment == kAlignmentZeroFill) // If we are to precede the number with zeroes...
  895. {
  896. if(bNegative || (sign != kSignNone))
  897. nDigitCountSum = fd.mnWidth - 1; // Take into account the leading sign that we'll need to write.
  898. else if(fd.mbAlternativeForm && ((nBase == 2) || (nBase == 16)))
  899. nDigitCountSum = fd.mnWidth - 2; // Take into account the leading "0x" that we'll need to write.
  900. else
  901. nDigitCountSum = fd.mnWidth;
  902. }
  903. // Write in any leading zeroes as required by the precision specifier(or the zero fill alignment option).
  904. while(nDigitCount < nDigitCountSum)
  905. {
  906. *--pCurrent = (CharT)'0';
  907. ++nDigitCount;
  908. }
  909. // Potentially add the sign prefix, which might be either nothing, '-', '+', or ' '.
  910. if(nBase == 10) // Signs can only apply to decimal types.
  911. {
  912. if((fd.mnType == 'd') || (fd.mnType == 'i')) // The standard seems to say that only signed decimal types can have signs.
  913. {
  914. if(bNegative)
  915. *--pCurrent = (CharT)'-';
  916. else if(fd.mSign == kSignMinusPlus)
  917. *--pCurrent = (CharT)'+';
  918. else if(fd.mSign == kSignSpace)
  919. *--pCurrent = (CharT)' ';
  920. }
  921. }
  922. else if(fd.mbAlternativeForm && ((nBase == 2) || (nBase == 16)))
  923. {
  924. // Add the leading 0x, 0X, 0b, or 0B (for our binary extension).
  925. *--pCurrent = (CharT)fd.mnType;
  926. *--pCurrent = (CharT)'0';
  927. }
  928. }
  929. return pCurrent;
  930. }
  931. ///////////////////////////////////////////////////////////////////////////////
  932. // WriteLong
  933. //
  934. // Writes the given lValue to the given buffer and returns the start of the
  935. // data or returns NULL for error. Note that the buffer is passed in as the
  936. // end of the buffer and not the beginning. This is a common trick used when
  937. // converting integer values to strings, as the conversion algorithm needs
  938. // to work backwards as it is and it's quicker to simply start with the end
  939. // of the buffer and move backwards.
  940. //
  941. template <typename CharT>
  942. CharT* WriteLong(const SprintfLocal::FormatData& fd, long lValue, CharT* EA_RESTRICT pBufferEnd)
  943. {
  944. return WriteLongHelper<CharT, long, unsigned long>(fd, lValue, pBufferEnd);
  945. }
  946. ///////////////////////////////////////////////////////////////////////////////
  947. // WriteLongLong
  948. //
  949. // This function is identical to WriteLong except that it works with long long
  950. // instead of long. It is a separate function because on many platforms the
  951. // long long data type is larger than the (efficient) machine word size and is
  952. // thus to be avoided if possible.
  953. //
  954. template <typename CharT>
  955. CharT* WriteLongLong(const SprintfLocal::FormatData& fd, long long lValue, CharT* EA_RESTRICT pBufferEnd)
  956. {
  957. return WriteLongHelper<CharT, long long, unsigned long long> (fd, lValue, pBufferEnd);
  958. }
  959. ///////////////////////////////////////////////////////////////////////////////
  960. // WriteDouble
  961. //
  962. template <typename CharT>
  963. CharT* WriteDouble(const SprintfLocal::FormatData& fd, double dValue, CharT* EA_RESTRICT pBufferEnd)
  964. {
  965. using namespace SprintfLocal;
  966. // Check for nan or inf strings.
  967. if(IsNAN(dValue))
  968. {
  969. *--pBufferEnd = 0;
  970. if(fd.mnType >= 'a') // If type is f, e, g, a, and not F, E, G, A.
  971. {
  972. *--pBufferEnd = 'n';
  973. *--pBufferEnd = 'a';
  974. *--pBufferEnd = 'n';
  975. }
  976. else
  977. {
  978. *--pBufferEnd = 'N';
  979. *--pBufferEnd = 'A';
  980. *--pBufferEnd = 'N';
  981. }
  982. if(IsNeg(dValue))
  983. *--pBufferEnd = '-';
  984. return pBufferEnd;
  985. }
  986. else if(IsInfinite(dValue))
  987. {
  988. *--pBufferEnd = 0;
  989. if(fd.mnType >= 'a') // If type is f, e, g, a, and not F, E, G, A.
  990. {
  991. *--pBufferEnd = 'f';
  992. *--pBufferEnd = 'n';
  993. *--pBufferEnd = 'i';
  994. }
  995. else
  996. {
  997. *--pBufferEnd = 'F';
  998. *--pBufferEnd = 'N';
  999. *--pBufferEnd = 'I';
  1000. }
  1001. if(IsNeg(dValue))
  1002. *--pBufferEnd = '-';
  1003. return pBufferEnd;
  1004. }
  1005. // Regular processing.
  1006. int nType = fd.mnType;
  1007. int nPrecision = fd.mnPrecision;
  1008. bool bStripTrailingZeroes = false; // If true, then don't write useless trailing zeroes, a with the three at the end of: "1.23000"
  1009. bool bStripPointlessDecimal = false; // If true, then don't write a decimal point that has no digits after it, as with: "13."
  1010. CharT* pResult = NULL;
  1011. *--pBufferEnd = 0;
  1012. if (nPrecision <= kConversionBufferSize) // If there is enough space for the data...
  1013. {
  1014. int nDecimalPoint, nSign, nExponent;
  1015. CharT pBufferCvt[kFcvtBufMaxSize]; pBufferCvt[0] = 0;
  1016. int nBufferLength;
  1017. CharT* pCurrent = pBufferEnd;
  1018. switch(nType)
  1019. {
  1020. default :
  1021. case 'g':
  1022. case 'G':
  1023. {
  1024. // From section 7.19.6.1.8:
  1025. // A double argument representing a floating-point number is converted in
  1026. // style f or e (or in style F or E in the case of a G conversion specifier), with
  1027. // the precision specifying the number of significant digits. If the precision is
  1028. // zero, it is taken as 1. The style used depends on the value converted; style e
  1029. // (or E) is used only if the exponent resulting from such a conversion is less
  1030. // than -4 or greater than or equal to the precision. Trailing zeros are removed
  1031. // from the fractional portion of the result unless the # flag is specified; a
  1032. // decimal-point character appears only if it is followed by a digit.
  1033. //
  1034. // A double argument representing an infinity or NaN is converted in the style
  1035. // of an f or F conversion specifier.
  1036. // %g differs from %e how we pass nPrecision to EcvtBuf.
  1037. EcvtBuf(dValue, nPrecision, &nDecimalPoint, &nSign, pBufferCvt);
  1038. nExponent = nDecimalPoint - 1; // Exponent can be a positive, zero, or negative value.
  1039. if(!fd.mbAlternativeForm)
  1040. bStripTrailingZeroes = true;
  1041. bStripPointlessDecimal = true;
  1042. if(!((nExponent < -4) || (nExponent >= nPrecision)))
  1043. {
  1044. if(!IsSameType<CharT, char>::value)
  1045. {
  1046. if(nExponent >= 0) // If there are any digits to the left of the decimal...
  1047. nPrecision -= (nExponent + 1);
  1048. }
  1049. goto FType;
  1050. }
  1051. if(nType == 'g')
  1052. nType = 'e';
  1053. else
  1054. nType = 'E';
  1055. goto EContinuation;
  1056. } // case g:
  1057. case 'e':
  1058. case 'E':
  1059. {
  1060. // From section 7.19.6.1.8:
  1061. // A double argument representing a floating-point number is converted in the
  1062. // style [-]d.ddd edd, where there is one digit (which is nonzero if the
  1063. // argument is nonzero) before the decimal-point character and the number of
  1064. // digits after it is equal to the precision; if the precision is missing, it is
  1065. // taken as 6; if the precision is zero and the # flag is not specified, no decimal-point
  1066. // character appears. The value is rounded to the appropriate number of digits.
  1067. // The E conversion specifier produces a number with E instead of e
  1068. // introducing the exponent. The exponent always contains at least two digits,
  1069. // and only as many more digits as necessary to represent the exponent. If the
  1070. // value is zero, the exponent is zero.
  1071. //
  1072. // A double argument representing an infinity or NaN is converted in the style
  1073. // of an f or F conversion specifier.
  1074. EcvtBuf(dValue, nPrecision + 1, &nDecimalPoint, &nSign, pBufferCvt);
  1075. nExponent = nDecimalPoint - 1; // Exponent can be a positive, zero, or negative value.
  1076. if(dValue == 0) // Should we instead compare dValue to a very small value?
  1077. nExponent = 0; // In this case we are working with the value 0, which is always displayed as 0.???e+00
  1078. EContinuation:
  1079. nBufferLength = (int)Strlen(pBufferCvt);
  1080. // Write the exponent digits, at least two of them.
  1081. int nExponentAbs = abs(nExponent);
  1082. while(nExponentAbs > 0)
  1083. {
  1084. *--pCurrent = (CharT)('0' + (nExponentAbs % 10));
  1085. nExponentAbs /= 10;
  1086. }
  1087. if(pCurrent >= (pBufferEnd - 1)) // The C99 standard states that at least two digits are present in the exponent, even if they are either or both zeroes.
  1088. *--pCurrent = '0';
  1089. if(pCurrent >= (pBufferEnd - 1))
  1090. *--pCurrent = '0';
  1091. // Write the decimal point sign, always + or -.
  1092. if(nExponent >= 0)
  1093. *--pCurrent = '+';
  1094. else
  1095. *--pCurrent = '-';
  1096. // Write 'e' or 'E'.
  1097. *--pCurrent = (CharT)nType;
  1098. // Write all digits but the first one.
  1099. for(CharT* pTemp = pBufferCvt + nBufferLength; pTemp > pBufferCvt + 1; )
  1100. {
  1101. const CharT c = *--pTemp;
  1102. if(c != '0') // As we move right to left, as soon as we encounter a non-'0', we are done with trialing zeroes.
  1103. bStripTrailingZeroes = false;
  1104. if((c != '0') || !bStripTrailingZeroes)
  1105. *--pCurrent = c;
  1106. }
  1107. // Write the decimal point.
  1108. if((*pCurrent != (CharT)nType) || !bStripPointlessDecimal) // If bStripPointlessDecimal is true, then draw decimal only if there are digits after it.
  1109. {
  1110. if((nBufferLength > 1) || fd.mbAlternativeForm) // If the 'alternative form' is set, then always show a decimal.
  1111. *--pCurrent = (CharT)fd.mDecimalPoint;
  1112. }
  1113. // Write the first digit.
  1114. *--pCurrent = pBufferCvt[0];
  1115. break;
  1116. } // case e:
  1117. case 'f':
  1118. case 'F':
  1119. FType:
  1120. {
  1121. // From section 7.19.6.1.8:
  1122. // A double argument representing a floating-point number is converted to
  1123. // decimal notation in the style [-]ddd.ddd, where the number of digits after
  1124. // the decimal-point character is equal to the precision specification.
  1125. // If the precision is missing, it is taken as 6; if the precision is zero
  1126. // and the # flag is not specified, no decimal-point character appears.
  1127. // If a decimal-point character appears, at least one digit appears before it.
  1128. // The value is rounded to the appropriate number of digits.
  1129. //
  1130. // A double argument representing an infinity is converted in one of the
  1131. // styles [-]inf or [-]infinity which style is implementation-defined.
  1132. // A double argument representing a NaN is converted in one of the styles
  1133. // [-]nan or [-]nan(n-char-sequence) which style, and the meaning of
  1134. // any n-char-sequence, is implementation-defined. The F conversion specifier
  1135. // produces INF, INFINITY, or NAN instead of inf, infinity, or nan,
  1136. // respectively.)
  1137. FcvtBuf(dValue, nPrecision, &nDecimalPoint, &nSign, pBufferCvt);
  1138. nBufferLength = (int)Strlen(pBufferCvt);
  1139. // If the 'alternative form' is set, then always show a decimal.
  1140. if(fd.mbAlternativeForm && (nDecimalPoint >= nBufferLength) && !bStripPointlessDecimal)
  1141. *--pCurrent = (CharT)fd.mDecimalPoint;
  1142. // Write the values that are after the decimal point.
  1143. const CharT* const pDecimalPoint = pBufferCvt + nDecimalPoint - 1;
  1144. const CharT* pCurrentSource = pBufferCvt + nBufferLength - 1;
  1145. if((pCurrentSource - pDecimalPoint) > nPrecision) // If dValue is very small, this may be true.
  1146. pCurrentSource = pDecimalPoint + nPrecision;
  1147. while(pCurrentSource > pDecimalPoint)
  1148. {
  1149. CharT c;
  1150. if((pCurrentSource >= pBufferCvt) && (pCurrentSource <= (pBufferCvt + nBufferLength)))
  1151. c = *pCurrentSource;
  1152. else
  1153. c = '0';
  1154. if(c != '0') // As we move right to left, as soon as we encounter a non-'0', we are done with trialing zeroes.
  1155. bStripTrailingZeroes = false;
  1156. if((c != '0') || !bStripTrailingZeroes)
  1157. *--pCurrent = c;
  1158. --pCurrentSource;
  1159. }
  1160. // Write the decimal point.
  1161. if(*pCurrent || !bStripPointlessDecimal) // If bStripPointlessDecimal is true, then draw decimal only if there is something after it.
  1162. {
  1163. if(nDecimalPoint < nBufferLength) // The standard specifies to not write the decimal point if the precision is zero.
  1164. *--pCurrent = (CharT)fd.mDecimalPoint;
  1165. }
  1166. // Write the values that are before the decimal point.
  1167. if(nDecimalPoint > 0) // If there is any integral part to this number...
  1168. {
  1169. int nDigitCount = 0;
  1170. pCurrentSource = pBufferCvt + nDecimalPoint;
  1171. while(pCurrentSource > pBufferCvt)
  1172. {
  1173. *--pCurrent = *--pCurrentSource;
  1174. ++nDigitCount;
  1175. if((fd.mbDisplayThousands) && (pCurrentSource > pBufferCvt) && ((nDigitCount % 3) == 0))
  1176. *--pCurrent = (CharT)fd.mThousandsSeparator;
  1177. }
  1178. }
  1179. else
  1180. *--pCurrent = '0'; // Write the "0" before the decimal point, as in "0.1234".
  1181. break;
  1182. } // case f:
  1183. } // switch
  1184. // Write a sign character.
  1185. if(nSign)
  1186. *--pCurrent = '-';
  1187. else if(fd.mSign == kSignMinusPlus)
  1188. *--pCurrent = '+';
  1189. else if(fd.mSign == kSignSpace)
  1190. *--pCurrent = ' ';
  1191. // Write leading spaces.
  1192. if(fd.mAlignment == kAlignmentRight)
  1193. {
  1194. // Write in any leading spaces as required by the width specifier (or the zero fill alignment option).
  1195. int nWidth = (int)(intptr_t)(pBufferEnd - pCurrent);
  1196. while(nWidth < fd.mnWidth)
  1197. {
  1198. *--pCurrent = (CharT)' ';
  1199. ++nWidth;
  1200. }
  1201. }
  1202. pResult = pCurrent;
  1203. }
  1204. return pResult;
  1205. }
  1206. ///////////////////////////////////////////////////////////////////////////////
  1207. // VprintfCore
  1208. //
  1209. template <typename CharT>
  1210. int VprintfCoreInternal(int(*pWriteFunction)(const CharT* EA_RESTRICT pData, size_t nCount, void* EA_RESTRICT pContext, WriteFunctionState wfs), void* EA_RESTRICT pWriteFunctionContext, const CharT* EA_RESTRICT pFormat, va_list arguments)
  1211. {
  1212. using namespace SprintfLocal;
  1213. const CharT* pFormatCurrent = pFormat; // Current position within entire format string.
  1214. const CharT* pFormatSpec; // Current format specification (e.g. "%3.2f").
  1215. FormatData fd;
  1216. int nWriteCount;
  1217. int nWriteCountSum = 0;
  1218. int nWriteCountCurrent;
  1219. CharT pBuffer[kConversionBufferSize + 1]; // The +1 isn't necessary but placates code analysis tools.
  1220. CharT* const pBufferEnd = pBuffer + kConversionBufferSize;
  1221. const CharT* pBufferData = NULL; // Where within pBuffer8 the data we are interested in begins.
  1222. long lValue = 0; // All known supported platforms have 'long' support in hardware. 'int' is always only 32 bits (even on 64 bit systems).
  1223. unsigned long ulValue = 0; //
  1224. long long llValue = 0; // Most compilers support 'long long' at this point. VC++ v6 and earlier are notable exceptions.
  1225. unsigned long long ullValue = 0; //
  1226. pWriteFunction(NULL, 0, pWriteFunctionContext, kWFSBegin);
  1227. // We walk through the format string and echo characters to the output until we
  1228. // come across a % specifier, at which point we process it and then move on as before.
  1229. while(*pFormatCurrent)
  1230. {
  1231. // Find the next format specification (or end of the string).
  1232. pFormatSpec = pFormatCurrent;
  1233. while(*pFormatSpec && (*pFormatSpec != '%'))
  1234. ++pFormatSpec;
  1235. // Write out non-formatted text
  1236. nWriteCount = (int)(pFormatSpec - pFormatCurrent);
  1237. if(nWriteCount)
  1238. {
  1239. if(pWriteFunction(pFormatCurrent, (size_t)nWriteCount, pWriteFunctionContext, kWFSIntermediate) == -1)
  1240. goto FunctionError; // This is an error; not the same as running out of space.
  1241. nWriteCountSum += nWriteCount;
  1242. pFormatCurrent = pFormatSpec;
  1243. }
  1244. if(*pFormatSpec)
  1245. {
  1246. pFormatCurrent = ReadFormat(pFormatSpec, &fd, VA_LIST_REFERENCE(arguments));
  1247. switch(fd.mnType)
  1248. {
  1249. case 'd': // These are signed values.
  1250. case 'i': // The standard specifies that 'd' and 'i' are identical.
  1251. {
  1252. if(fd.mModifier == kModifierLongLong)
  1253. llValue = va_arg(arguments, long long); // If the user didn't pass a long long, unexpected behaviour will occur.
  1254. else if((fd.mModifier == kModifierLong) || (fd.mModifier == kModifierLongDouble)) // It is questionable whether we should allow %Ld here as we do. The standard doesn't define this behaviour.
  1255. lValue = va_arg(arguments, long);
  1256. else if(fd.mModifier == kModifierInt64)
  1257. {
  1258. if(sizeof(int64_t) == sizeof(long))
  1259. {
  1260. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1261. lValue = va_arg(arguments, long);
  1262. }
  1263. else if(sizeof(int64_t) == sizeof(long long))
  1264. {
  1265. fd.mModifier = kModifierLongLong;
  1266. llValue = va_arg(arguments, long long);
  1267. }
  1268. }
  1269. else if (fd.mModifier == kModifierMax_t)
  1270. {
  1271. if (sizeof(intmax_t) == sizeof(long))
  1272. {
  1273. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1274. lValue = va_arg(arguments, long);
  1275. }
  1276. else if (sizeof(intmax_t) == sizeof(long long))
  1277. {
  1278. fd.mModifier = kModifierLongLong;
  1279. llValue = va_arg(arguments, long long);
  1280. }
  1281. }
  1282. else if (fd.mModifier == kModifierSize_t)
  1283. {
  1284. if (sizeof(size_t) == sizeof(long))
  1285. {
  1286. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1287. lValue = (long) va_arg(arguments, unsigned long);
  1288. }
  1289. else if (sizeof(size_t) == sizeof(long long))
  1290. {
  1291. fd.mModifier = kModifierLongLong;
  1292. llValue = (long) va_arg(arguments, unsigned long long);
  1293. }
  1294. }
  1295. else if (fd.mModifier == kModifierPtrdiff_t)
  1296. {
  1297. if (sizeof(ptrdiff_t) == sizeof(long))
  1298. {
  1299. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1300. lValue = va_arg(arguments, long);
  1301. }
  1302. else if (sizeof(ptrdiff_t) == sizeof(long long))
  1303. {
  1304. fd.mModifier = kModifierLongLong;
  1305. llValue = va_arg(arguments, long long);
  1306. }
  1307. }
  1308. else if(fd.mModifier == kModifierInt128)
  1309. {
  1310. if(sizeof(int64_t) < sizeof(long long)) // If long long is 128 bits... (we don't test sizeof(int128_t) because there may be no such thing. Hopefully there is no int96_t.
  1311. llValue = va_arg(arguments, long long);
  1312. else
  1313. {
  1314. // We have a problem here. The user wants to print a 128 bit value but
  1315. // there is no built-in type to support this. For the time being, we
  1316. // simply use only 64 bits of data. If we really need this, we can
  1317. // add the functionality later. We have the EAStdC int128_t type we can use.
  1318. // I don't think calling two 64 bit va_args is the same as what a single
  1319. // 128 bit arg would be. If we are using EAStdC int128_t then we handle the
  1320. // value the same as passing a struct by value. And that's compiler/ABI-specific.
  1321. llValue = va_arg(arguments, long long);
  1322. llValue = va_arg(arguments, long long);
  1323. }
  1324. }
  1325. else // else we have kModifierChar, kModifierShort, kModifierInt8, kModifierInt16, kModifierInt32.
  1326. {
  1327. // COMPILE_TIME_ASSERT(sizeof(int32_t) <= sizeof(int));
  1328. lValue = va_arg(arguments, int);
  1329. if((fd.mModifier == kModifierShort) || (fd.mModifier == kModifierInt16))
  1330. lValue = (long)(signed short)lValue; // We carefully do our casting here in order to preserve intent.
  1331. else if((fd.mModifier == kModifierChar) || (fd.mModifier == kModifierInt8))
  1332. lValue = (long)(signed char)lValue; // We carefully do our casting here in order to preserve intent.
  1333. }
  1334. if(fd.mModifier == kModifierLongLong)
  1335. {
  1336. pBufferData = WriteLongLong(fd, llValue, pBufferEnd);
  1337. if(!pBufferData)
  1338. goto FormatError;
  1339. }
  1340. else
  1341. {
  1342. pBufferData = WriteLong(fd, lValue, pBufferEnd);
  1343. if(!pBufferData)
  1344. goto FormatError;
  1345. }
  1346. nWriteCount = (int)((pBufferEnd - pBufferData) - 1); // -1 because the written string is 0-terminated and we don't want to write the final 0.
  1347. break;
  1348. }
  1349. case 'b': // 'b' means binary. This is a convenient extension that we provide.
  1350. case 'o': // These are unsigned values.
  1351. case 'u':
  1352. case 'x':
  1353. case 'X':
  1354. {
  1355. if(fd.mModifier == kModifierLong)
  1356. ulValue = va_arg(arguments, unsigned long);
  1357. else if(fd.mModifier == kModifierLongLong)
  1358. ullValue = va_arg(arguments, unsigned long long);
  1359. else if(fd.mModifier == kModifierInt64)
  1360. {
  1361. if(sizeof(uint64_t) == sizeof(unsigned long))
  1362. {
  1363. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1364. ulValue = va_arg(arguments, unsigned long);
  1365. }
  1366. else if(sizeof(uint64_t) == sizeof(unsigned long long))
  1367. {
  1368. fd.mModifier = kModifierLongLong;
  1369. ullValue = va_arg(arguments, unsigned long long);
  1370. }
  1371. }
  1372. else if (fd.mModifier == kModifierMax_t)
  1373. {
  1374. if (sizeof(uintmax_t) == sizeof(unsigned long))
  1375. {
  1376. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1377. ulValue = va_arg(arguments, unsigned long);
  1378. }
  1379. else if (sizeof(uintmax_t) == sizeof(unsigned long long))
  1380. {
  1381. fd.mModifier = kModifierLongLong;
  1382. ullValue = va_arg(arguments, unsigned long long);
  1383. }
  1384. }
  1385. else if (fd.mModifier == kModifierSize_t)
  1386. {
  1387. if (sizeof(size_t) == sizeof(unsigned long))
  1388. {
  1389. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1390. ulValue = va_arg(arguments, unsigned long);
  1391. }
  1392. else if (sizeof(size_t) == sizeof(unsigned long long))
  1393. {
  1394. fd.mModifier = kModifierLongLong;
  1395. ullValue = va_arg(arguments, unsigned long long);
  1396. }
  1397. }
  1398. else if (fd.mModifier == kModifierPtrdiff_t)
  1399. {
  1400. if (sizeof(ptrdiff_t) == sizeof(unsigned long))
  1401. {
  1402. // fd.mModifier == kModifierLong; -- Not necessary, as the logic below doesn't need this.
  1403. ulValue = (unsigned long long) va_arg(arguments, long);
  1404. }
  1405. else if (sizeof(ptrdiff_t) == sizeof(unsigned long long))
  1406. {
  1407. fd.mModifier = kModifierLongLong;
  1408. ullValue = (unsigned long long) va_arg(arguments, long long);
  1409. }
  1410. }
  1411. else if(fd.mModifier == kModifierInt128)
  1412. {
  1413. if(sizeof(uint64_t) < sizeof(unsigned long long)) // If long long is 128 bits... (we don't test sizeof(int128_t) because there may be no such thing. Hopefully there is no int96_t.
  1414. ullValue = va_arg(arguments, unsigned long long);
  1415. else
  1416. {
  1417. // We have a problem here. The user wants to print a 128 bit value but
  1418. // there is no built-in type to support this. For the time being, we
  1419. // simply use only 64 bits of data. If we really need this, we can
  1420. // add the functionality later.
  1421. #ifdef EA_SYSTEM_BIG_ENDIAN
  1422. (void)va_arg(arguments, unsigned long long);
  1423. ullValue = va_arg(arguments, unsigned long long);
  1424. #else
  1425. ullValue = va_arg(arguments, unsigned long long);
  1426. (void)va_arg(arguments, unsigned long long);
  1427. #endif
  1428. }
  1429. }
  1430. else // else we have kModifierChar, kModifierShort, kModifierInt8, kModifierInt16, kModifierInt32.
  1431. {
  1432. ulValue = va_arg(arguments, unsigned int);
  1433. if((fd.mModifier == kModifierShort) || (fd.mModifier == kModifierInt16))
  1434. ulValue = (unsigned long)(unsigned short)ulValue; // We carefully do our casting here in order to preserve intent.
  1435. else if((fd.mModifier == kModifierChar) || (fd.mModifier == kModifierInt8))
  1436. ulValue = (unsigned long)(unsigned char)ulValue; // We carefully do our casting here in order to preserve intent.
  1437. }
  1438. // Now do the actual writing of the data.
  1439. if(fd.mModifier == kModifierLongLong)
  1440. {
  1441. pBufferData = WriteLongLong(fd, (long long)ullValue, pBufferEnd);
  1442. if(!pBufferData)
  1443. goto FormatError;
  1444. }
  1445. else
  1446. {
  1447. pBufferData = WriteLong(fd, (long)ulValue, pBufferEnd);
  1448. if(!pBufferData)
  1449. goto FormatError;
  1450. }
  1451. nWriteCount = (int)((pBufferEnd - pBufferData) - 1); // -1 because the written string is 0-terminated and we don't want to write the final 0.
  1452. break;
  1453. }
  1454. case 'e':
  1455. case 'E':
  1456. case 'f':
  1457. case 'F':
  1458. case 'g':
  1459. case 'G':
  1460. case 'a': // See the C99 standard, section 7.19.6.1.8, for details on 'a' formatting.
  1461. case 'A':
  1462. {
  1463. // Since on most systems long double is the same as double, it's really no big deal to just work
  1464. // with long double, much like we do with long int instead of int above.
  1465. if(fd.mModifier == kModifierLongDouble)
  1466. {
  1467. long double ldValue = va_arg(arguments, long double);
  1468. pBufferData = WriteDouble(fd, static_cast<double>(ldValue), pBufferEnd);
  1469. }
  1470. else
  1471. {
  1472. double dValue = va_arg(arguments, double);
  1473. pBufferData = WriteDouble(fd, dValue, pBufferEnd);
  1474. }
  1475. if(!pBufferData)
  1476. goto FormatError;
  1477. nWriteCount = (int)((pBufferEnd - pBufferData) - 1); // -1 because the written string is 0-terminated and we don't want to write the final 0.
  1478. break;
  1479. }
  1480. case 's':
  1481. case 'S':
  1482. {
  1483. int stringTypeSize;
  1484. switch (fd.mModifier)
  1485. {
  1486. case kModifierInt8: // If the user specified %I8s or %I8S
  1487. case kModifierChar: // If the user specified %hs or %hS or kModifierWChar was chosen implicitly for other reasons.
  1488. stringTypeSize = 1;
  1489. break;
  1490. case kModifierInt16: // If the user specified %I16s or %I16S
  1491. stringTypeSize = 2;
  1492. break;
  1493. case kModifierInt32: // If the user specified %I32s or %I32S
  1494. stringTypeSize = 4;
  1495. break;
  1496. case kModifierWChar: // If the user specified %ls or %lS or kModifierWChar was chosen implicitly for other reasons.
  1497. stringTypeSize = sizeof(wchar_t);
  1498. break;
  1499. default: // If the user specified %I64s or %I64S or another invalid size.
  1500. goto FormatError;
  1501. }
  1502. switch (stringTypeSize)
  1503. {
  1504. case 1:
  1505. {
  1506. const char* pBufferData8 = va_arg(arguments, char*);
  1507. nWriteCount = StringFormat<char, CharT>(pWriteFunction, pWriteFunctionContext, fd, pBuffer, pBufferData8);
  1508. if (nWriteCount < 0)
  1509. goto FormatError;
  1510. nWriteCountSum += nWriteCount;
  1511. break;
  1512. } // case 1
  1513. case 2:
  1514. {
  1515. const char16_t* pBufferData16 = va_arg(arguments, char16_t*);
  1516. nWriteCount = StringFormat<char16_t, CharT>(pWriteFunction, pWriteFunctionContext, fd, pBuffer, pBufferData16);
  1517. if (nWriteCount < 0)
  1518. goto FormatError;
  1519. nWriteCountSum += nWriteCount;
  1520. break;
  1521. } // case 2
  1522. case 4:
  1523. {
  1524. const char32_t* pBufferData32 = va_arg(arguments, char32_t*);
  1525. nWriteCount = StringFormat<char32_t, CharT>(pWriteFunction, pWriteFunctionContext, fd, pBuffer, pBufferData32);
  1526. if (nWriteCount < 0)
  1527. goto FormatError;
  1528. nWriteCountSum += nWriteCount;
  1529. break;
  1530. } // case 4
  1531. } // switch (stringTypeSize)
  1532. continue; // Skip the appending of the buffer. This is being done inside the StringFormat routine
  1533. } // case 's'
  1534. case 'n': // %n %hn %ln %lln %I64n %I32n %I16n, %I8n, %jn, %tn, %zn etc.
  1535. {
  1536. // In this case, we write the number of chars written so far to the passed in argument.
  1537. void* pCountBufferData = va_arg(arguments, void*);
  1538. switch (fd.mModifier)
  1539. {
  1540. case kModifierInt8:
  1541. case kModifierChar:
  1542. *(char*)pCountBufferData = (char)nWriteCountSum;
  1543. break;
  1544. case kModifierInt16:
  1545. case kModifierShort:
  1546. *(int16_t*)pCountBufferData = (int16_t)nWriteCountSum;
  1547. break;
  1548. case kModifierInt32:
  1549. *(int32_t*)pCountBufferData = (int32_t)nWriteCountSum;
  1550. break;
  1551. case kModifierInt64:
  1552. *(int64_t*)pCountBufferData = (int32_t)nWriteCountSum;
  1553. break;
  1554. case kModifierLong:
  1555. *(long*)pCountBufferData = (long)nWriteCountSum;
  1556. break;
  1557. case kModifierLongLong:
  1558. *(long long*)pCountBufferData = (long long)nWriteCountSum;
  1559. break;
  1560. case kModifierPtrdiff_t:
  1561. *(ptrdiff_t*)pCountBufferData = (ptrdiff_t)nWriteCountSum;
  1562. break;
  1563. case kModifierSize_t:
  1564. *(size_t*)pCountBufferData = (size_t)nWriteCountSum;
  1565. break;
  1566. case kModifierMax_t:
  1567. *(intmax_t*)pCountBufferData = (intmax_t)nWriteCountSum;
  1568. break;
  1569. //case kModifierInt128: // We really should generate an error with this. It's nearly pointless to support it.
  1570. // // Fall through
  1571. //
  1572. //case kModifierWChar: // This should be impossible to encounter.
  1573. //case kModifierLongDouble: // This should be impossible to encounter.
  1574. // // Fall through
  1575. case kModifierNone:
  1576. default:
  1577. *(int*)pCountBufferData = (int)nWriteCountSum;
  1578. break;
  1579. }
  1580. continue; // Intentionally continue instead break.
  1581. } // case 'n'
  1582. case 'c':
  1583. case 'C':
  1584. {
  1585. int charTypeSize;
  1586. switch (fd.mModifier)
  1587. {
  1588. case kModifierInt8: // If the user specified %I8c or %I8c
  1589. case kModifierChar: // If the user specified %hc or %hC or kModifierWChar was chosen implicitly for other reasons.
  1590. charTypeSize = 1;
  1591. break;
  1592. case kModifierInt16: // If the user specified %I16c or %I16C
  1593. charTypeSize = 2;
  1594. break;
  1595. case kModifierInt32: // If the user specified %I32c or %I32C
  1596. charTypeSize = 4;
  1597. break;
  1598. case kModifierWChar: // If the user specified %lc or %lC or kModifierWChar was chosen implicitly for other reasons.
  1599. charTypeSize = sizeof(wchar_t);
  1600. break;
  1601. default: // If the user specified %I64c or %I64C or another invalid size.
  1602. goto FormatError;
  1603. }
  1604. // In some cases, we are losing data here or doing an improper or incomplete encoding conversion.
  1605. switch (charTypeSize)
  1606. {
  1607. case 1:
  1608. {
  1609. const char c8 = (char)va_arg(arguments, int); // We make the assumption here that sizeof(char16_t) is <= sizeof(int) and thus that a char16_t argument was promoted to int.
  1610. pBuffer[0] = (CharT)(uint32_t)c8;
  1611. pBufferData = pBuffer;
  1612. nWriteCount = 1;
  1613. break;
  1614. }
  1615. case 2:
  1616. {
  1617. const char16_t c16 = (char16_t)va_arg(arguments, unsigned int);
  1618. pBuffer[0] = (CharT)(uint32_t)c16;
  1619. pBufferData = pBuffer;
  1620. nWriteCount = 1;
  1621. break;
  1622. }
  1623. case 4:
  1624. {
  1625. const char32_t c32 = (char32_t)va_arg(arguments, unsigned int);
  1626. pBuffer[0] = (CharT)(uint32_t)c32;
  1627. pBufferData = pBuffer;
  1628. nWriteCount = 1;
  1629. break;
  1630. }
  1631. }
  1632. break;
  1633. } // case 'c'
  1634. case '%':
  1635. {
  1636. // In this case we just write a single '%' char to the output.
  1637. pBuffer[0] = '%';
  1638. pBufferData = pBuffer;
  1639. nWriteCount = 1;
  1640. break;
  1641. }
  1642. case kFormatError:
  1643. default:
  1644. FormatError:
  1645. // We do what many printf implementations do here and simply print out the text
  1646. // as-is -- as if there wasn't any formatting specifier. This at least lets the
  1647. // user see what was (incorrectly) specified.
  1648. nWriteCount = (int)(pFormatCurrent - pFormatSpec);
  1649. nWriteCountSum += nWriteCount;
  1650. if(nWriteCount && (pWriteFunction(pFormatSpec, (size_t)nWriteCount, pWriteFunctionContext, kWFSIntermediate) == -1))
  1651. goto FunctionError; // This is an error; not the same as running out of space.
  1652. continue; // Try to continue displaying further data.
  1653. }
  1654. nWriteCountCurrent = WriteBuffer(pWriteFunction, pWriteFunctionContext, fd, pBufferData, nWriteCount);
  1655. if (nWriteCountCurrent < 0)
  1656. goto FunctionError; // This is an error; not the same as running out of space.
  1657. nWriteCountSum += nWriteCountCurrent;
  1658. } // if(*pFormatSpec)
  1659. } // while(*pFormatCurrent)
  1660. pWriteFunction(NULL, 0, pWriteFunctionContext, kWFSEnd);
  1661. return nWriteCountSum;
  1662. FunctionError:
  1663. pWriteFunction(NULL, 0, pWriteFunctionContext, kWFSEnd);
  1664. return -1;
  1665. }
  1666. ///////////////////////////////////////////////////////////////////////////////
  1667. // VprintfCore
  1668. //
  1669. int VprintfCore(WriteFunction8 pWriteFunction8, void* EA_RESTRICT pWriteFunctionContext8, const char* EA_RESTRICT pFormat, va_list arguments)
  1670. {
  1671. return VprintfCoreInternal(pWriteFunction8, pWriteFunctionContext8, pFormat, arguments);
  1672. }
  1673. int VprintfCore(WriteFunction16 pWriteFunction16, void* EA_RESTRICT pWriteFunctionContext16, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1674. {
  1675. return VprintfCoreInternal(pWriteFunction16, pWriteFunctionContext16, pFormat, arguments);
  1676. }
  1677. int VprintfCore(WriteFunction32 pWriteFunction32, void* EA_RESTRICT pWriteFunctionContext32, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1678. {
  1679. return VprintfCoreInternal(pWriteFunction32, pWriteFunctionContext32, pFormat, arguments);
  1680. }
  1681. } // namespace SprintfLocal
  1682. } // namespace StdC
  1683. } // namespace EA
  1684. // For bulk build friendliness, undef all local #defines.
  1685. #undef IsNeg
  1686. #undef EASPRINTF_MIN
  1687. #undef EASPRINTF_MAX
  1688. #ifdef _MSC_VER
  1689. #pragma warning(pop)
  1690. #endif