EASprintfOrdered.cpp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560
  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/EASprintfOrdered.h>
  7. #include <EAStdC/EASprintf.h>
  8. #include <EAStdC/EABitTricks.h>
  9. #include <EAAssert/eaassert.h>
  10. #include <stdarg.h>
  11. #include <string.h>
  12. #ifdef _MSC_VER
  13. #pragma warning(push)
  14. #pragma warning(disable: 4127) // conditional expression is constant.
  15. #endif
  16. // GCC has va_copy, but VC++ does not. However, VC++ implements
  17. // va_list in such a way that it can simply be memcpyd.
  18. #ifndef va_copy
  19. #ifdef __va_copy
  20. #define va_copy(dest, src) __va_copy((dest), (src))
  21. #else
  22. #define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
  23. #endif
  24. #endif
  25. namespace EA
  26. {
  27. namespace StdC
  28. {
  29. namespace SprintfLocal
  30. {
  31. static const int kSpanFormatCapacity = 16;
  32. struct Span8
  33. {
  34. const char8_t* mpBegin; // The first char in the span.
  35. const char8_t* mpEnd; // One-past the last used char.
  36. Modifier mType; // This tells us what the type of the argument is (e.g. kModifierInt).
  37. AllTypes mValue; // This stores the value, which is of type mType.
  38. char8_t mFormat[kSpanFormatCapacity]; // The format to use (e.g. %5.3f). If empty then this is a string span.
  39. char8_t mFormatChar; // The last char in the mFormat string.
  40. int mUserIndex; // The index the user assigned to this format. Negative value if this is a string span.
  41. bool mbEscapePresent; // True if the span is a string and it has a %% sequence. We can optimize writes if we know that it doesn't.
  42. Span8() : mpBegin(NULL),
  43. mpEnd(NULL),
  44. mType(kModifierNone),
  45. mValue(),
  46. mFormatChar(0),
  47. mUserIndex(0),
  48. mbEscapePresent(false)
  49. { mFormat[0] = 0; }
  50. };
  51. struct Span16
  52. {
  53. const char16_t* mpBegin; // The first char in the span.
  54. const char16_t* mpEnd; // One-past the last used char.
  55. Modifier mType; // This tells us what the type of the argument is (e.g. kModifierInt).
  56. AllTypes mValue; // This stores the value, which is of type mType.
  57. char16_t mFormat[kSpanFormatCapacity]; // The format to use (e.g. %5.3f). If empty then this is a string span.
  58. char16_t mFormatChar; // The last char in the mFormat string.
  59. int mUserIndex; // The index the user assigned to this format. Negative value if this is a string span.
  60. bool mbEscapePresent; // True if the span is a string and it has a %% sequence. We can optimize writes if we know that it doesn't.
  61. Span16(): mpBegin(NULL),
  62. mpEnd(NULL),
  63. mType(kModifierNone),
  64. mValue(),
  65. mFormatChar(0),
  66. mUserIndex(0),
  67. mbEscapePresent(false)
  68. { mFormat[0] = 0; }
  69. };
  70. struct Span32
  71. {
  72. const char32_t* mpBegin; // The first char in the span.
  73. const char32_t* mpEnd; // One-past the last used char.
  74. Modifier mType; // This tells us what the type of the argument is (e.g. kModifierInt).
  75. AllTypes mValue; // This stores the value, which is of type mType.
  76. char32_t mFormat[kSpanFormatCapacity]; // The format to use (e.g. %5.3f). If empty then this is a string span.
  77. char32_t mFormatChar; // The last char in the mFormat string.
  78. int mUserIndex; // The index the user assigned to this format. Negative value if this is a string span.
  79. bool mbEscapePresent; // True if the span is a string and it has a %% sequence. We can optimize writes if we know that it doesn't.
  80. Span32(): mpBegin(NULL),
  81. mpEnd(NULL),
  82. mType(kModifierNone),
  83. mValue(),
  84. mFormatChar(0),
  85. mUserIndex(0),
  86. mbEscapePresent(false)
  87. { mFormat[0] = 0; }
  88. };
  89. // This function exists for the sole purpose of passing an arbitrary argument to VprintfCore
  90. // along with an existing WriteFunction8/pWriteFunctionContext8.
  91. static int CallVprintfCore(WriteFunction8 pWriteFunction8, void* EA_RESTRICT pWriteFunctionContext8, const char8_t* EA_RESTRICT pFormat, ...)
  92. {
  93. va_list arguments;
  94. va_start(arguments, pFormat);
  95. return VprintfCore(pWriteFunction8, pWriteFunctionContext8, pFormat, arguments);
  96. }
  97. static int CallVprintfCore(WriteFunction16 pWriteFunction16, void* EA_RESTRICT pWriteFunctionContext16, const char16_t* EA_RESTRICT pFormat, ...)
  98. {
  99. va_list arguments;
  100. va_start(arguments, pFormat);
  101. return VprintfCore(pWriteFunction16, pWriteFunctionContext16, pFormat, arguments);
  102. }
  103. static int CallVprintfCore(WriteFunction32 pWriteFunction32, void* EA_RESTRICT pWriteFunctionContext32, const char32_t* EA_RESTRICT pFormat, ...)
  104. {
  105. va_list arguments;
  106. va_start(arguments, pFormat);
  107. return VprintfCore(pWriteFunction32, pWriteFunctionContext32, pFormat, arguments);
  108. }
  109. // This function is a copy of the 16 bit version below.
  110. //
  111. // The way this function works is as follows: We walk through the pFormat string and identify all
  112. // format spans and non-format spans (i.e. literal text) between format spans. Thus for the string
  113. // " %1:f %0:d " we have five spans: three non-format spans, and two format spans. The we
  114. // read the va_list arguments in the user-specified order into a union that can hold any type.
  115. // It's important that we read the arguments in user-specified order and not format string order.
  116. // So the %d would be read first as an int, and the %f would be read second as a double.
  117. // Finally we walk through the format in string order and write out each span to the output.
  118. // Non-format segments are simply copied to the output. Format segments are written to the output
  119. // by a call to VPrintfCore each.
  120. //
  121. static int OVprintfCore(WriteFunction8 pWriteFunction8, void* EA_RESTRICT pWriteFunctionContext8, const char8_t* EA_RESTRICT pFormat, va_list arguments)
  122. {
  123. const int kArgCapacity = 10; // Currently only single digit ('0'-'9') order values are supported.
  124. const int kSpanCapacity = 21; // Worst case scenario of 21 spans. For example: " %2:d %7:d %1:d %6:d %3:d %5:d %4:d %0:d %8:d %9:d " or "%0:d%1:d%2:d%3:d%4:d%5:d%6:d%7:d%8:d%9:d"
  125. Span8 spans[kSpanCapacity];
  126. int spanArgOrder[kArgCapacity] = { -1 }; // Each entry is the index into 'spans' of that argument. This allows us to quickly find formats in the order the user passed them to this function. For the example directly above, the contents would be: 5, 1, 9, 13, 11, 7, 3, 17, 15. We initialize it to -1 in order to avoid compiler warnings about it being used before set.
  127. int spanIndex = 0;
  128. int formattedSpanCount = 0;
  129. bool bInFormat = false; // State variable indicating if we are within a % format sequence.
  130. int nFormatLength = 0;
  131. int nWriteCountSum = 0;
  132. int startIndex = 1; // This is 1 or 0, and it defaults to 1 (but may change below) in order to mean that user formats start at 1, as in "%1:d". However, we have a feature whereby we detect that the user is using %0 as the start index.
  133. const char8_t* p;
  134. const char8_t* pEnd;
  135. int result;
  136. static_assert((EAArrayCount(spans) == kSpanCapacity) && (EAArrayCount(spanArgOrder) == kArgCapacity), "spans and spanArgOrder are not using constants for their array size.");
  137. #ifdef EA_DEBUG
  138. for(int s = 0; s < kArgCapacity; ++s)
  139. spanArgOrder[s] = -1;
  140. #else
  141. memset(spanArgOrder, 0, sizeof(spanArgOrder));
  142. #endif
  143. pWriteFunction8(NULL, 0, pWriteFunctionContext8, kWFSBegin);
  144. // Initialize the first span. We always have a beginning sequence that is
  145. // a string, even if it is empty. Actually, there may be an empty string
  146. // span between any two format spans. We'll ignore them later.
  147. spans[0].mpBegin = pFormat;
  148. spans[0].mUserIndex = -1;
  149. // Build the list of spans.
  150. // Read each format string character while maintaining a little state machine.
  151. for(p = pFormat; *p; ++p)
  152. {
  153. if(*p == '%')
  154. {
  155. // A % char within a format is invalid (though %% is valid), and any '%' char that
  156. // begins a format must be followed by at least three more chars, two for the user
  157. // index plus colon and at least one for the actual format (e.g. %4:d).
  158. EA_ASSERT(!bInFormat && p[1] && p[2] && p[3]);
  159. if(p[1] == '%')
  160. {
  161. spans[spanIndex].mbEscapePresent = true;
  162. p++; // Skip past the second % char.
  163. }
  164. else // else we don't have a %% sequence and thus have the start of a format...
  165. {
  166. // Finalize the current span (the one before the % char), before starting a new span for this % sequence.
  167. spans[spanIndex].mpEnd = p;
  168. spans[spanIndex].mFormat[nFormatLength] = 0;
  169. spans[spanIndex].mFormatChar = 0; // This is redundant.
  170. if(++spanIndex == kSpanCapacity)
  171. break;
  172. // Intialize the next span.
  173. if((p[1] < '0') || (p[1] > '9'))
  174. return -1; // Invalid format. User specified a format like "%X:d" or just "%"
  175. const int userIndex = (int)(p[1] - '0');
  176. if((userIndex == 0) && (startIndex != 0)) // If it appears that the user is using argument numbering that is 0-based (e.g. "%0:d") instead of 1-based...
  177. {
  178. startIndex = 0;
  179. for(int i = kArgCapacity - 1; i > 0; --i)
  180. spanArgOrder[i] = spanArgOrder[i - 1]; // Convert any existing indexes from what we originally assumed to be 1-based values 'up' to being 0-based values.
  181. }
  182. bInFormat = true;
  183. nFormatLength = 1; // For the % char we write into mFormat.
  184. spans[spanIndex].mpBegin = p;
  185. spans[spanIndex].mFormat[0] = '%';
  186. spans[spanIndex].mUserIndex = userIndex; // We don't write the user index or the colon into the format string, which is a standard C format specifier sequence.
  187. spanArgOrder[userIndex - startIndex] = spanIndex; // startIndex is normally 1, because usually users specify argument indexes in a 1:based way.
  188. formattedSpanCount++;
  189. EA_ASSERT(p[2] == ':'); // We expect formats to have a N: sequence after the % in order to indicate order (e.g. %4:3.1f means %3.1f as 4th argument)
  190. if(p[2] != ':')
  191. return -1; // Invalid format. User specified a format like "%00:d" or just "%0"
  192. p += 2; // Skip past the user index and the colon.
  193. }
  194. }
  195. else if(bInFormat)
  196. {
  197. EA_ASSERT(nFormatLength < kSpanFormatCapacity);
  198. if(nFormatLength < kSpanFormatCapacity)
  199. spans[spanIndex].mFormat[nFormatLength++] = *p;
  200. else
  201. return -1; // Invalid format. User specified a format like "%0:000000000000001d" (too long a printf format)
  202. switch(*p)
  203. {
  204. case 'b': case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': // If this character is the last posible character of a format specifier...
  205. case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'a':
  206. case 'A': case 'p': case 'c': case 'C': case 's': case 'S': case 'n':
  207. {
  208. // Finalize the current span.
  209. spans[spanIndex].mpEnd = p + 1;
  210. spans[spanIndex].mFormat[nFormatLength] = 0;
  211. spans[spanIndex].mFormatChar = *p;
  212. if(++spanIndex == kSpanCapacity)
  213. break;
  214. // Intialize the next span.
  215. bInFormat = false;
  216. nFormatLength = 0;
  217. spans[spanIndex].mpBegin = p + 1;
  218. spans[spanIndex].mUserIndex = -1; // This is a string span. If a format sequence or end-of-string immediately follows then this will be an empty string span.
  219. break;
  220. }
  221. default:
  222. // To do: Handle the case of an invalid format character.
  223. break;
  224. }
  225. }
  226. // Else we are in the middle of a string portion of the format and we need do nothing here.
  227. }
  228. // Finalize the last span, which by definition ends at the end of our input.
  229. EA_ASSERT(spanIndex < kSpanCapacity);
  230. if((spanIndex == kSpanCapacity) && *p) // If the user somehow specified more format spans than possible...
  231. return -1; // Invalid format. Too many format spans.
  232. spans[spanIndex].mpEnd = p; // p Should always point to the terminating 0 char of pFormat.
  233. spans[spanIndex].mFormat[nFormatLength] = 0;
  234. spanIndex++;
  235. // Now we read the arguments into span[s].mValue in the order they were passed by the caller.
  236. for(int i = 0; i < formattedSpanCount; ++i)
  237. {
  238. EA_ASSERT((spanArgOrder[i] >= 0) && (spanArgOrder[i] < kSpanCapacity));
  239. Span8& span = spans[spanArgOrder[i]];
  240. FormatData formatData;
  241. // We call ReadFormat in order to get the argument type. We don't need the other information from FormatData.
  242. // ReadFormat returns the pointer to the next char after the format sequence. If there is an error then it
  243. // returns a pointer to where it failed. We can use this to tell if ReadFormat failed by testing *pEnd == 0.
  244. pEnd = ReadFormat(span.mFormat, &formatData, (va_list*)&arguments);
  245. if(*pEnd != 0) // If ReadFormat bailed before processing the entire format...
  246. return -1;
  247. // Unfortunately, ReadFormat tells us the type only if it is a modified type (e.g. %ld as opposed to %d).
  248. // We could go and modify ReadFormat to store the full type all the time, but that would be messing with
  249. // that function and its performance and we'd rather stay away from that. We can solve this with a simple
  250. // switch statement here.
  251. if(formatData.mModifier == kModifierNone)
  252. {
  253. switch (pEnd[-1])
  254. {
  255. case 'b':
  256. case 'd':
  257. case 'i':
  258. case 'u':
  259. case 'o':
  260. case 'x':
  261. case 'X':
  262. formatData.mModifier = kModifierInt;
  263. break;
  264. case 'g':
  265. case 'G':
  266. case 'e':
  267. case 'E':
  268. case 'f':
  269. case 'F':
  270. case 'a':
  271. case 'A':
  272. formatData.mModifier = kModifierDouble;
  273. break;
  274. case 'p':
  275. case 's':
  276. case 'S':
  277. case 'n':
  278. EA_COMPILETIME_ASSERT(sizeof(size_t) == sizeof(void*)); // If this fails then we need to modify this statement.
  279. formatData.mModifier = kModifierSize_t;
  280. break;
  281. case 'c':
  282. formatData.mModifier = kModifierChar;
  283. break;
  284. case 'C':
  285. formatData.mModifier = kModifierWChar;
  286. break;
  287. default:
  288. EA_FAIL_M("EAStdC OVprintfCore"); // This shouldn't occur unless ReadFormat started supporting some new format that we aren't yet aware of and it is being used here.
  289. break;
  290. }
  291. }
  292. span.mType = formatData.mModifier;
  293. switch (span.mType)
  294. {
  295. case kModifierChar:
  296. span.mValue.mChar = (char)va_arg(arguments, int); // Recall that C++ promotes types less than int to int.
  297. break;
  298. case kModifierShort:
  299. span.mValue.mShort = (short)va_arg(arguments, int);
  300. break;
  301. case kModifierInt:
  302. span.mValue.mInt = va_arg(arguments, int);
  303. break;
  304. case kModifierLong:
  305. span.mValue.mLong = va_arg(arguments, long);
  306. break;
  307. case kModifierLongLong:
  308. span.mValue.mLongLong = va_arg(arguments, long long);
  309. break;
  310. case kModifierMax_t:
  311. span.mValue.mMax = va_arg(arguments, intmax_t);
  312. break;
  313. case kModifierSize_t:
  314. span.mValue.mSize = va_arg(arguments, size_t);
  315. break;
  316. case kModifierPtrdiff_t:
  317. span.mValue.mPtrDiff = va_arg(arguments, ptrdiff_t);
  318. break;
  319. case kModifierDouble:
  320. span.mValue.mDouble = va_arg(arguments, double);
  321. break;
  322. case kModifierLongDouble:
  323. span.mValue.mLongDouble = va_arg(arguments, long double);
  324. break;
  325. case kModifierWChar:
  326. span.mValue.mWChar = (wchar_t)va_arg(arguments, unsigned int);
  327. break;
  328. case kModifierInt8:
  329. span.mValue.mInt8 = (int8_t)va_arg(arguments, int);
  330. break;
  331. case kModifierInt16:
  332. span.mValue.mInt16 = (int16_t)va_arg(arguments, int);
  333. break;
  334. case kModifierInt32:
  335. span.mValue.mInt32 = va_arg(arguments, int32_t);
  336. break;
  337. case kModifierInt64:
  338. span.mValue.mInt64 = va_arg(arguments, int64_t);
  339. break;
  340. case kModifierInt128:
  341. span.mValue.mLongLong = 0;
  342. EA_FAIL_M("EAStdC OVprintfCore"); // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  343. break;
  344. case kModifierNone:
  345. default:
  346. // If this occurs, then our ReadFormat function seems to have a bug. We already have an assertion failure for this case above.
  347. span.mValue.mLongLong = 0;
  348. break;
  349. }
  350. }
  351. // Now we have an array of spans. Now we print the spans one by one.
  352. for(int s = 0; s < spanIndex; ++s)
  353. {
  354. const Span8& span = spans[s];
  355. if(span.mpEnd != span.mpBegin) // If non-empty...
  356. {
  357. if(span.mUserIndex >= 0) // If this is a format span as opposed to a string span...
  358. {
  359. switch (span.mType)
  360. {
  361. case kModifierChar:
  362. // We can't call VprintfCore directly because it expects a va_list, whereas we have just a single value.
  363. // We can't call Sprintf because we need to pass the current pWriteFunction, pWriteFunctionContext.
  364. // To do: We have a problem here: VprintfCore will call the write function
  365. // with kWFSBegin, kWFSIntermediate, and kWFSEnd. We need it to use
  366. // just kFSIntermediate. Currently this affects only writing on
  367. // some mobile platforms to their custom log formats and it's unlikely
  368. // anybody will ever use ordered sprintf to such a destination.
  369. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mChar);
  370. break;
  371. case kModifierShort:
  372. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mShort);
  373. break;
  374. case kModifierInt:
  375. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mInt);
  376. break;
  377. case kModifierLong:
  378. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mLong);
  379. break;
  380. case kModifierLongLong:
  381. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mLongLong);
  382. break;
  383. case kModifierMax_t:
  384. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mMax);
  385. break;
  386. case kModifierSize_t:
  387. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mSize);
  388. break;
  389. case kModifierPtrdiff_t:
  390. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mPtrDiff);
  391. break;
  392. case kModifierDouble:
  393. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mDouble);
  394. break;
  395. case kModifierLongDouble:
  396. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mLongDouble);
  397. break;
  398. case kModifierWChar:
  399. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mWChar);
  400. break;
  401. case kModifierInt8:
  402. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mInt8);
  403. break;
  404. case kModifierInt16:
  405. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mInt16);
  406. break;
  407. case kModifierInt32:
  408. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mInt32);
  409. break;
  410. case kModifierInt64:
  411. result = CallVprintfCore(pWriteFunction8, pWriteFunctionContext8, span.mFormat, span.mValue.mInt64);
  412. break;
  413. case kModifierInt128:
  414. result = -1; // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  415. break;
  416. case kModifierNone:
  417. default:
  418. result = -1; // If this fails, then our ReadFormat function seems to have a bug.
  419. break;
  420. }
  421. if(result < 0)
  422. return -1;
  423. nWriteCountSum += result;
  424. }
  425. else
  426. {
  427. // We simply copy the span to the pWriteFunction, while taking care of %% escape sequences.
  428. p = span.mpBegin;
  429. pEnd = span.mpEnd;
  430. if(span.mbEscapePresent) // If somewhere in the string span there is at least one %% sequence, we must copy the slow way: one by one.
  431. {
  432. for(result = 1; (result >= 0) && (p < pEnd); ++p)
  433. {
  434. if(pWriteFunction8(p, 1, pWriteFunctionContext8, kWFSIntermediate) < 0)
  435. return -1;
  436. nWriteCountSum += result;
  437. }
  438. }
  439. else
  440. {
  441. if(pWriteFunction8(p, (size_t)(pEnd - p), pWriteFunctionContext8, kWFSIntermediate) < 0)
  442. return -1;
  443. nWriteCountSum += (int)(pEnd - p);
  444. }
  445. }
  446. }
  447. }
  448. pWriteFunction8(NULL, 0, pWriteFunctionContext8, kWFSEnd);
  449. return nWriteCountSum;
  450. }
  451. // This function is a copy of the 8 bit version above.
  452. static int OVprintfCore(WriteFunction16 pWriteFunction16, void* EA_RESTRICT pWriteFunctionContext16, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  453. {
  454. const int kArgCapacity = 10; // Currently only single digit ('0'-'9') order values are supported.
  455. const int kSpanCapacity = 21; // Worst case scenario of 21 spans. For example: " %2:d %7:d %1:d %6:d %3:d %5:d %4:d %0:d %8:d %9:d " or "%0:d%1:d%2:d%3:d%4:d%5:d%6:d%7:d%8:d%9:d"
  456. Span16 spans[kSpanCapacity];
  457. int spanArgOrder[kArgCapacity] = { -1 }; // Each entry is the index into 'spans' of that argument. This allows us to quickly find formats in the order the user passed them to this function. For the example directly above, the contents would be: 5, 1, 9, 13, 11, 7, 3, 17, 15. We initialize it to -1 in order to avoid compiler warnings about it being used before set.
  458. int spanIndex = 0;
  459. int formattedSpanCount = 0;
  460. bool bInFormat = false; // State variable indicating if we are within a % format sequence.
  461. int nFormatLength = 0;
  462. int nWriteCountSum = 0;
  463. int startIndex = 1; // This is 1 or 0, and it defaults to 1 (but may change below) in order to mean that user formats start at 1, as in "%1:d". However, we have a feature whereby we detect that the user is using %0 as the start index.
  464. const char16_t* p;
  465. const char16_t* pEnd;
  466. int result;
  467. static_assert((EAArrayCount(spans) == kSpanCapacity) && (EAArrayCount(spanArgOrder) == kArgCapacity), "spans and spanArgOrder are not using constants for their array size.");
  468. #ifdef EA_DEBUG
  469. for(int s = 0; s < kArgCapacity; ++s)
  470. spanArgOrder[s] = -1;
  471. #else
  472. memset(spanArgOrder, 0, sizeof(spanArgOrder));
  473. #endif
  474. pWriteFunction16(NULL, 0, pWriteFunctionContext16, kWFSBegin);
  475. // Initialize the first span. We always have a beginning sequence that is
  476. // a string, even if it is empty. Actually, there may be an empty string
  477. // span between any two format spans. We'll ignore them later.
  478. spans[0].mpBegin = pFormat;
  479. spans[0].mUserIndex = -1;
  480. // Build the list of spans.
  481. // Read each format string character while maintaining a little state machine.
  482. for(p = pFormat; *p; ++p)
  483. {
  484. if(*p == '%')
  485. {
  486. // A % char within a format is invalid (though %% is valid), and any '%' char that
  487. // begins a format must be followed by at least three more chars, two for the user
  488. // index plus colon and at least one for the actual format (e.g. %4:d).
  489. EA_ASSERT(!bInFormat && p[1] && p[2] && p[3]);
  490. if(p[1] == '%')
  491. {
  492. spans[spanIndex].mbEscapePresent = true;
  493. p++; // Skip past the second % char.
  494. }
  495. else // else we don't have a %% sequence and thus have the start of a format...
  496. {
  497. // Finalize the current span (the one before the % char), before starting a new span for this % sequence.
  498. spans[spanIndex].mpEnd = p;
  499. spans[spanIndex].mFormat[nFormatLength] = 0;
  500. spans[spanIndex].mFormatChar = 0; // This is redundant.
  501. if(++spanIndex == kSpanCapacity)
  502. break;
  503. // Intialize the next span.
  504. if((p[1] < '0') || (p[1] > '9'))
  505. return -1; // Invalid format. User specified a format like "%X:d" or just "%"
  506. const int userIndex = (int)(p[1] - '0');
  507. if((userIndex == 0) && (startIndex != 0)) // If it appears that the user is using argument numbering that is 0-based (e.g. "%0:d") instead of 1-based...
  508. {
  509. startIndex = 0;
  510. for(int i = kArgCapacity - 1; i > 0; --i)
  511. spanArgOrder[i] = spanArgOrder[i - 1]; // Convert any existing indexes from what we originally assumed to be 1-based values 'up' to being 0-based values.
  512. }
  513. bInFormat = true;
  514. nFormatLength = 1; // For the % char we write into mFormat.
  515. spans[spanIndex].mpBegin = p;
  516. spans[spanIndex].mFormat[0] = '%';
  517. spans[spanIndex].mUserIndex = userIndex; // We don't write the user index or the colon into the format string, which is a standard C format specifier sequence.
  518. spanArgOrder[userIndex - startIndex] = spanIndex; // startIndex is normally 1, because usually users specify argument indexes in a 1:based way.
  519. formattedSpanCount++;
  520. EA_ASSERT(p[2] == ':'); // We expect formats to have a N: sequence after the % in order to indicate order (e.g. %4:3.1f means %3.1f as 4th argument)
  521. if(p[2] != ':')
  522. return -1; // Invalid format. User specified a format like "%00:d" or just "%0"
  523. p += 2; // Skip past the user index and the colon.
  524. }
  525. }
  526. else if(bInFormat)
  527. {
  528. EA_ASSERT(nFormatLength < kSpanFormatCapacity);
  529. if(nFormatLength < kSpanFormatCapacity)
  530. spans[spanIndex].mFormat[nFormatLength++] = *p;
  531. else
  532. return -1; // Invalid format. User specified a format like "%0:000000000000001d" (too long a printf format)
  533. switch(*p)
  534. {
  535. case 'b': case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': // If this character is the last posible character of a format specifier...
  536. case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'a':
  537. case 'A': case 'p': case 'c': case 'C': case 's': case 'S': case 'n':
  538. {
  539. // Finalize the current span.
  540. spans[spanIndex].mpEnd = p + 1;
  541. spans[spanIndex].mFormat[nFormatLength] = 0;
  542. spans[spanIndex].mFormatChar = *p;
  543. if(++spanIndex == kSpanCapacity)
  544. break;
  545. // Intialize the next span.
  546. bInFormat = false;
  547. nFormatLength = 0;
  548. spans[spanIndex].mpBegin = p + 1;
  549. spans[spanIndex].mUserIndex = -1; // This is a string span. If a format sequence or end-of-string immediately follows then this will be an empty string span.
  550. break;
  551. }
  552. default:
  553. // To do: Handle the case of an invalid format character.
  554. break;
  555. }
  556. }
  557. // Else we are in the middle of a string portion of the format and we need do nothing here.
  558. }
  559. // Finalize the last span, which by definition ends at the end of our input.
  560. EA_ASSERT(spanIndex < kSpanCapacity);
  561. if((spanIndex == kSpanCapacity) && *p) // If the user somehow specified more format spans than possible...
  562. return -1; // Invalid format. Too many format spans.
  563. spans[spanIndex].mpEnd = p; // p Should always point to the terminating 0 char of pFormat.
  564. spans[spanIndex].mFormat[nFormatLength] = 0;
  565. spanIndex++;
  566. // Now we read the arguments into span[s].mValue in the order they were passed by the caller.
  567. for(int i = 0; i < formattedSpanCount; ++i)
  568. {
  569. EA_ASSERT((spanArgOrder[i] >= 0) && (spanArgOrder[i] < kSpanCapacity));
  570. Span16& span = spans[spanArgOrder[i]];
  571. FormatData formatData;
  572. // We call ReadFormat in order to get the argument type. We don't need the other information from FormatData.
  573. // ReadFormat returns the pointer to the next char after the format sequence. If there is an error then it
  574. // returns a pointer to where it failed. We can use this to tell if ReadFormat failed by testing *pEnd == 0.
  575. pEnd = ReadFormat(span.mFormat, &formatData, (va_list*)&arguments);
  576. if(*pEnd != 0) // If ReadFormat bailed before processing the entire format...
  577. return -1;
  578. // Unfortunately, ReadFormat tells us the type only if it is a modified type (e.g. %ld as opposed to %d).
  579. // We could go and modify ReadFormat to store the full type all the time, but that would be messing with
  580. // that function and its performance and we'd rather stay away from that. We can solve this with a simple
  581. // switch statement here.
  582. if(formatData.mModifier == kModifierNone)
  583. {
  584. switch (pEnd[-1])
  585. {
  586. case 'b':
  587. case 'd':
  588. case 'i':
  589. case 'u':
  590. case 'o':
  591. case 'x':
  592. case 'X':
  593. formatData.mModifier = kModifierInt;
  594. break;
  595. case 'g':
  596. case 'G':
  597. case 'e':
  598. case 'E':
  599. case 'f':
  600. case 'F':
  601. case 'a':
  602. case 'A':
  603. formatData.mModifier = kModifierDouble;
  604. break;
  605. case 'p':
  606. case 's':
  607. case 'S':
  608. case 'n':
  609. EA_COMPILETIME_ASSERT(sizeof(size_t) == sizeof(void*)); // If this fails then we need to modify this statement.
  610. formatData.mModifier = kModifierSize_t;
  611. break;
  612. case 'c':
  613. formatData.mModifier = kModifierChar;
  614. break;
  615. case 'C':
  616. formatData.mModifier = kModifierWChar;
  617. break;
  618. default:
  619. EA_FAIL_M("EAStdC OVprintfCore"); // This shouldn't occur unless ReadFormat started supporting some new format that we aren't yet aware of and it is being used here.
  620. break;
  621. }
  622. }
  623. span.mType = formatData.mModifier;
  624. switch (span.mType)
  625. {
  626. case kModifierChar:
  627. span.mValue.mChar = (char)va_arg(arguments, int); // Recall that C++ promotes types less than int to int.
  628. break;
  629. case kModifierShort:
  630. span.mValue.mShort = (short)va_arg(arguments, int);
  631. break;
  632. case kModifierInt:
  633. span.mValue.mInt = va_arg(arguments, int);
  634. break;
  635. case kModifierLong:
  636. span.mValue.mLong = va_arg(arguments, long);
  637. break;
  638. case kModifierLongLong:
  639. span.mValue.mLongLong = va_arg(arguments, long long);
  640. break;
  641. case kModifierMax_t:
  642. span.mValue.mMax = va_arg(arguments, intmax_t);
  643. break;
  644. case kModifierSize_t:
  645. span.mValue.mSize = va_arg(arguments, size_t);
  646. break;
  647. case kModifierPtrdiff_t:
  648. span.mValue.mPtrDiff = va_arg(arguments, ptrdiff_t);
  649. break;
  650. case kModifierDouble:
  651. span.mValue.mDouble = va_arg(arguments, double);
  652. break;
  653. case kModifierLongDouble:
  654. span.mValue.mLongDouble = va_arg(arguments, long double);
  655. break;
  656. case kModifierWChar:
  657. span.mValue.mWChar = (wchar_t)va_arg(arguments, unsigned int);
  658. break;
  659. case kModifierInt8:
  660. span.mValue.mInt8 = (int8_t)va_arg(arguments, int);
  661. break;
  662. case kModifierInt16:
  663. span.mValue.mInt16 = (int16_t)va_arg(arguments, int);
  664. break;
  665. case kModifierInt32:
  666. span.mValue.mInt32 = va_arg(arguments, int32_t);
  667. break;
  668. case kModifierInt64:
  669. span.mValue.mInt64 = va_arg(arguments, int64_t);
  670. break;
  671. case kModifierInt128:
  672. span.mValue.mLongLong = 0;
  673. EA_FAIL_M("EAStdC OVprintfCore"); // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  674. break;
  675. case kModifierNone:
  676. default:
  677. // If this occurs, then our ReadFormat function seems to have a bug. We already have an assertion failure for this case above.
  678. span.mValue.mLongLong = 0;
  679. break;
  680. }
  681. }
  682. // Now we have an array of spans. Now we print the spans one by one.
  683. for(int s = 0; s < spanIndex; ++s)
  684. {
  685. const Span16& span = spans[s];
  686. if(span.mpEnd != span.mpBegin) // If non-empty...
  687. {
  688. if(span.mUserIndex >= 0) // If this is a format span as opposed to a string span...
  689. {
  690. switch (span.mType)
  691. {
  692. case kModifierChar:
  693. // We can't call VprintfCore directly because it expects a va_list, whereas we have just a single value.
  694. // We can't call Sprintf because we need to pass the current pWriteFunction, pWriteFunctionContext.
  695. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mChar);
  696. break;
  697. case kModifierShort:
  698. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mShort);
  699. break;
  700. case kModifierInt:
  701. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mInt);
  702. break;
  703. case kModifierLong:
  704. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mLong);
  705. break;
  706. case kModifierLongLong:
  707. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mLongLong);
  708. break;
  709. case kModifierMax_t:
  710. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mMax);
  711. break;
  712. case kModifierSize_t:
  713. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mSize);
  714. break;
  715. case kModifierPtrdiff_t:
  716. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mPtrDiff);
  717. break;
  718. case kModifierDouble:
  719. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mDouble);
  720. break;
  721. case kModifierLongDouble:
  722. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mLongDouble);
  723. break;
  724. case kModifierWChar:
  725. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mWChar);
  726. break;
  727. case kModifierInt8:
  728. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mInt8);
  729. break;
  730. case kModifierInt16:
  731. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mInt16);
  732. break;
  733. case kModifierInt32:
  734. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mInt32);
  735. break;
  736. case kModifierInt64:
  737. result = CallVprintfCore(pWriteFunction16, pWriteFunctionContext16, span.mFormat, span.mValue.mInt64);
  738. break;
  739. case kModifierInt128:
  740. result = -1; // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  741. break;
  742. case kModifierNone:
  743. default:
  744. result = -1; // If this fails, then our ReadFormat function seems to have a bug.
  745. break;
  746. }
  747. if(result < 0)
  748. return -1;
  749. nWriteCountSum += result;
  750. }
  751. else
  752. {
  753. // We simply copy the span to the pWriteFunction, while taking care of %% escape sequences.
  754. p = span.mpBegin;
  755. pEnd = span.mpEnd;
  756. if(span.mbEscapePresent) // If somewhere in the string span there is at least one %% sequence, we must copy the slow way: one by one.
  757. {
  758. for(result = 1; (result >= 0) && (p < pEnd); ++p)
  759. {
  760. if(pWriteFunction16(p, 1, pWriteFunctionContext16, kWFSIntermediate) < 0)
  761. return -1;
  762. nWriteCountSum += result;
  763. }
  764. }
  765. else
  766. {
  767. if(pWriteFunction16(p, (size_t)(pEnd - p), pWriteFunctionContext16, kWFSIntermediate) < 0)
  768. return -1;
  769. nWriteCountSum += (int)(pEnd - p);
  770. }
  771. }
  772. }
  773. }
  774. pWriteFunction16(NULL, 0, pWriteFunctionContext16, kWFSEnd);
  775. return nWriteCountSum;
  776. }
  777. // This function is a copy of the 8/16 bit versions above.
  778. static int OVprintfCore(WriteFunction32 pWriteFunction32, void* EA_RESTRICT pWriteFunctionContext32, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  779. {
  780. const int kArgCapacity = 10; // Currently only single digit ('0'-'9') order values are supported.
  781. const int kSpanCapacity = 21; // Worst case scenario of 21 spans. For example: " %2:d %7:d %1:d %6:d %3:d %5:d %4:d %0:d %8:d %9:d " or "%0:d%1:d%2:d%3:d%4:d%5:d%6:d%7:d%8:d%9:d"
  782. Span32 spans[kSpanCapacity];
  783. int spanArgOrder[kArgCapacity] = { -1 }; // Each entry is the index into 'spans' of that argument. This allows us to quickly find formats in the order the user passed them to this function. For the example directly above, the contents would be: 5, 1, 9, 13, 11, 7, 3, 17, 15. We initialize it to -1 in order to avoid compiler warnings about it being used before set.
  784. int spanIndex = 0;
  785. int formattedSpanCount = 0;
  786. bool bInFormat = false; // State variable indicating if we are within a % format sequence.
  787. int nFormatLength = 0;
  788. int nWriteCountSum = 0;
  789. int startIndex = 1; // This is 1 or 0, and it defaults to 1 (but may change below) in order to mean that user formats start at 1, as in "%1:d". However, we have a feature whereby we detect that the user is using %0 as the start index.
  790. const char32_t* p;
  791. const char32_t* pEnd;
  792. int result;
  793. static_assert((EAArrayCount(spans) == kSpanCapacity) && (EAArrayCount(spanArgOrder) == kArgCapacity), "spans and spanArgOrder are not using constants for their array size.");
  794. #ifdef EA_DEBUG
  795. for(int s = 0; s < kArgCapacity; ++s)
  796. spanArgOrder[s] = -1;
  797. #else
  798. memset(spanArgOrder, 0, sizeof(spanArgOrder));
  799. #endif
  800. pWriteFunction32(NULL, 0, pWriteFunctionContext32, kWFSBegin);
  801. // Initialize the first span. We always have a beginning sequence that is
  802. // a string, even if it is empty. Actually, there may be an empty string
  803. // span between any two format spans. We'll ignore them later.
  804. spans[0].mpBegin = pFormat;
  805. spans[0].mUserIndex = -1;
  806. // Build the list of spans.
  807. // Read each format string character while maintaining a little state machine.
  808. for(p = pFormat; *p; ++p)
  809. {
  810. if(*p == '%')
  811. {
  812. // A % char within a format is invalid (though %% is valid), and any '%' char that
  813. // begins a format must be followed by at least three more chars, two for the user
  814. // index plus colon and at least one for the actual format (e.g. %4:d).
  815. EA_ASSERT(!bInFormat && p[1] && p[2] && p[3]);
  816. if(p[1] == '%')
  817. {
  818. spans[spanIndex].mbEscapePresent = true;
  819. p++; // Skip past the second % char.
  820. }
  821. else // else we don't have a %% sequence and thus have the start of a format...
  822. {
  823. // Finalize the current span (the one before the % char), before starting a new span for this % sequence.
  824. spans[spanIndex].mpEnd = p;
  825. spans[spanIndex].mFormat[nFormatLength] = 0;
  826. spans[spanIndex].mFormatChar = 0; // This is redundant.
  827. if(++spanIndex == kSpanCapacity)
  828. break;
  829. // Intialize the next span.
  830. if((p[1] < '0') || (p[1] > '9'))
  831. return -1; // Invalid format. User specified a format like "%X:d" or just "%"
  832. const int userIndex = (int)(p[1] - '0');
  833. if((userIndex == 0) && (startIndex != 0)) // If it appears that the user is using argument numbering that is 0-based (e.g. "%0:d") instead of 1-based...
  834. {
  835. startIndex = 0;
  836. for(int i = kArgCapacity - 1; i > 0; --i)
  837. spanArgOrder[i] = spanArgOrder[i - 1]; // Convert any existing indexes from what we originally assumed to be 1-based values 'up' to being 0-based values.
  838. }
  839. bInFormat = true;
  840. nFormatLength = 1; // For the % char we write into mFormat.
  841. spans[spanIndex].mpBegin = p;
  842. spans[spanIndex].mFormat[0] = '%';
  843. spans[spanIndex].mUserIndex = userIndex; // We don't write the user index or the colon into the format string, which is a standard C format specifier sequence.
  844. spanArgOrder[userIndex - startIndex] = spanIndex; // startIndex is normally 1, because usually users specify argument indexes in a 1:based way.
  845. formattedSpanCount++;
  846. EA_ASSERT(p[2] == ':'); // We expect formats to have a N: sequence after the % in order to indicate order (e.g. %4:3.1f means %3.1f as 4th argument)
  847. if(p[2] != ':')
  848. return -1; // Invalid format. User specified a format like "%00:d" or just "%0"
  849. p += 2; // Skip past the user index and the colon.
  850. }
  851. }
  852. else if(bInFormat)
  853. {
  854. EA_ASSERT(nFormatLength < kSpanFormatCapacity);
  855. if(nFormatLength < kSpanFormatCapacity)
  856. spans[spanIndex].mFormat[nFormatLength++] = *p;
  857. else
  858. return -1; // Invalid format. User specified a format like "%0:000000000000001d" (too long a printf format)
  859. switch(*p)
  860. {
  861. case 'b': case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': // If this character is the last posible character of a format specifier...
  862. case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'a':
  863. case 'A': case 'p': case 'c': case 'C': case 's': case 'S': case 'n':
  864. {
  865. // Finalize the current span.
  866. spans[spanIndex].mpEnd = p + 1;
  867. spans[spanIndex].mFormat[nFormatLength] = 0;
  868. spans[spanIndex].mFormatChar = *p;
  869. if(++spanIndex == kSpanCapacity)
  870. break;
  871. // Intialize the next span.
  872. bInFormat = false;
  873. nFormatLength = 0;
  874. spans[spanIndex].mpBegin = p + 1;
  875. spans[spanIndex].mUserIndex = -1; // This is a string span. If a format sequence or end-of-string immediately follows then this will be an empty string span.
  876. break;
  877. }
  878. default:
  879. // To do: Handle the case of an invalid format character.
  880. break;
  881. }
  882. }
  883. // Else we are in the middle of a string portion of the format and we need do nothing here.
  884. }
  885. // Finalize the last span, which by definition ends at the end of our input.
  886. EA_ASSERT(spanIndex < kSpanCapacity);
  887. if((spanIndex == kSpanCapacity) && *p) // If the user somehow specified more format spans than possible...
  888. return -1; // Invalid format. Too many format spans.
  889. spans[spanIndex].mpEnd = p; // p Should always point to the terminating 0 char of pFormat.
  890. spans[spanIndex].mFormat[nFormatLength] = 0;
  891. spanIndex++;
  892. // Now we read the arguments into span[s].mValue in the order they were passed by the caller.
  893. for(int i = 0; i < formattedSpanCount; ++i)
  894. {
  895. EA_ASSERT((spanArgOrder[i] >= 0) && (spanArgOrder[i] < kSpanCapacity));
  896. Span32& span = spans[spanArgOrder[i]];
  897. FormatData formatData;
  898. // We call ReadFormat in order to get the argument type. We don't need the other information from FormatData.
  899. // ReadFormat returns the pointer to the next char after the format sequence. If there is an error then it
  900. // returns a pointer to where it failed. We can use this to tell if ReadFormat failed by testing *pEnd == 0.
  901. pEnd = ReadFormat(span.mFormat, &formatData, (va_list*)&arguments);
  902. if(*pEnd != 0) // If ReadFormat bailed before processing the entire format...
  903. return -1;
  904. // Unfortunately, ReadFormat tells us the type only if it is a modified type (e.g. %ld as opposed to %d).
  905. // We could go and modify ReadFormat to store the full type all the time, but that would be messing with
  906. // that function and its performance and we'd rather stay away from that. We can solve this with a simple
  907. // switch statement here.
  908. if(formatData.mModifier == kModifierNone)
  909. {
  910. switch (pEnd[-1])
  911. {
  912. case 'b':
  913. case 'd':
  914. case 'i':
  915. case 'u':
  916. case 'o':
  917. case 'x':
  918. case 'X':
  919. formatData.mModifier = kModifierInt;
  920. break;
  921. case 'g':
  922. case 'G':
  923. case 'e':
  924. case 'E':
  925. case 'f':
  926. case 'F':
  927. case 'a':
  928. case 'A':
  929. formatData.mModifier = kModifierDouble;
  930. break;
  931. case 'p':
  932. case 's':
  933. case 'S':
  934. case 'n':
  935. EA_COMPILETIME_ASSERT(sizeof(size_t) == sizeof(void*)); // If this fails then we need to modify this statement.
  936. formatData.mModifier = kModifierSize_t;
  937. break;
  938. case 'c':
  939. formatData.mModifier = kModifierChar;
  940. break;
  941. case 'C':
  942. formatData.mModifier = kModifierWChar;
  943. break;
  944. default:
  945. EA_FAIL_M("EAStdC OVprintfCore"); // This shouldn't occur unless ReadFormat started supporting some new format that we aren't yet aware of and it is being used here.
  946. break;
  947. }
  948. }
  949. span.mType = formatData.mModifier;
  950. switch (span.mType)
  951. {
  952. case kModifierChar:
  953. span.mValue.mChar = (char)va_arg(arguments, int); // Recall that C++ promotes types less than int to int.
  954. break;
  955. case kModifierShort:
  956. span.mValue.mShort = (short)va_arg(arguments, int);
  957. break;
  958. case kModifierInt:
  959. span.mValue.mInt = va_arg(arguments, int);
  960. break;
  961. case kModifierLong:
  962. span.mValue.mLong = va_arg(arguments, long);
  963. break;
  964. case kModifierLongLong:
  965. span.mValue.mLongLong = va_arg(arguments, long long);
  966. break;
  967. case kModifierMax_t:
  968. span.mValue.mMax = va_arg(arguments, intmax_t);
  969. break;
  970. case kModifierSize_t:
  971. span.mValue.mSize = va_arg(arguments, size_t);
  972. break;
  973. case kModifierPtrdiff_t:
  974. span.mValue.mPtrDiff = va_arg(arguments, ptrdiff_t);
  975. break;
  976. case kModifierDouble:
  977. span.mValue.mDouble = va_arg(arguments, double);
  978. break;
  979. case kModifierLongDouble:
  980. span.mValue.mLongDouble = va_arg(arguments, long double);
  981. break;
  982. case kModifierWChar:
  983. span.mValue.mWChar = (wchar_t)va_arg(arguments, unsigned int);
  984. break;
  985. case kModifierInt8:
  986. span.mValue.mInt8 = (int8_t)va_arg(arguments, int);
  987. break;
  988. case kModifierInt16:
  989. span.mValue.mInt16 = (int16_t)va_arg(arguments, int);
  990. break;
  991. case kModifierInt32:
  992. span.mValue.mInt32 = va_arg(arguments, int32_t);
  993. break;
  994. case kModifierInt64:
  995. span.mValue.mInt64 = va_arg(arguments, int64_t);
  996. break;
  997. case kModifierInt128:
  998. span.mValue.mLongLong = 0;
  999. EA_FAIL_M("EAStdC OVprintfCore"); // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  1000. break;
  1001. case kModifierNone:
  1002. default:
  1003. // If this occurs, then our ReadFormat function seems to have a bug. We already have an assertion failure for this case above.
  1004. span.mValue.mLongLong = 0;
  1005. break;
  1006. }
  1007. }
  1008. // Now we have an array of spans. Now we print the spans one by one.
  1009. for(int s = 0; s < spanIndex; ++s)
  1010. {
  1011. const Span32& span = spans[s];
  1012. if(span.mpEnd != span.mpBegin) // If non-empty...
  1013. {
  1014. if(span.mUserIndex >= 0) // If this is a format span as opposed to a string span...
  1015. {
  1016. switch (span.mType)
  1017. {
  1018. case kModifierChar:
  1019. // We can't call VprintfCore directly because it expects a va_list, whereas we have just a single value.
  1020. // We can't call Sprintf because we need to pass the current pWriteFunction, pWriteFunctionContext.
  1021. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mChar);
  1022. break;
  1023. case kModifierShort:
  1024. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mShort);
  1025. break;
  1026. case kModifierInt:
  1027. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mInt);
  1028. break;
  1029. case kModifierLong:
  1030. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mLong);
  1031. break;
  1032. case kModifierLongLong:
  1033. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mLongLong);
  1034. break;
  1035. case kModifierMax_t:
  1036. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mMax);
  1037. break;
  1038. case kModifierSize_t:
  1039. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mSize);
  1040. break;
  1041. case kModifierPtrdiff_t:
  1042. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mPtrDiff);
  1043. break;
  1044. case kModifierDouble:
  1045. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mDouble);
  1046. break;
  1047. case kModifierLongDouble:
  1048. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mLongDouble);
  1049. break;
  1050. case kModifierWChar:
  1051. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mWChar);
  1052. break;
  1053. case kModifierInt8:
  1054. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mInt8);
  1055. break;
  1056. case kModifierInt16:
  1057. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mInt16);
  1058. break;
  1059. case kModifierInt32:
  1060. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mInt32);
  1061. break;
  1062. case kModifierInt64:
  1063. result = CallVprintfCore(pWriteFunction32, pWriteFunctionContext32, span.mFormat, span.mValue.mInt64);
  1064. break;
  1065. case kModifierInt128:
  1066. result = -1; // We don't currently support 128 bit types in this function. We do have an int128_t class in this package which could be used, though.
  1067. break;
  1068. case kModifierNone:
  1069. default:
  1070. result = -1; // If this fails, then our ReadFormat function seems to have a bug.
  1071. break;
  1072. }
  1073. if(result < 0)
  1074. return -1;
  1075. nWriteCountSum += result;
  1076. }
  1077. else
  1078. {
  1079. // We simply copy the span to the pWriteFunction, while taking care of %% escape sequences.
  1080. p = span.mpBegin;
  1081. pEnd = span.mpEnd;
  1082. if(span.mbEscapePresent) // If somewhere in the string span there is at least one %% sequence, we must copy the slow way: one by one.
  1083. {
  1084. for(result = 1; (result >= 0) && (p < pEnd); ++p)
  1085. {
  1086. if(pWriteFunction32(p, 1, pWriteFunctionContext32, kWFSIntermediate) < 0)
  1087. return -1;
  1088. nWriteCountSum += result;
  1089. }
  1090. }
  1091. else
  1092. {
  1093. if(pWriteFunction32(p, (size_t)(pEnd - p), pWriteFunctionContext32, kWFSIntermediate) < 0)
  1094. return -1;
  1095. nWriteCountSum += (int)(pEnd - p);
  1096. }
  1097. }
  1098. }
  1099. }
  1100. pWriteFunction32(NULL, 0, pWriteFunctionContext32, kWFSEnd);
  1101. return nWriteCountSum;
  1102. }
  1103. } // SprintfLocal
  1104. ///////////////////////////////////////////////////////////////////////////////
  1105. // char8_t
  1106. ///////////////////////////////////////////////////////////////////////////////
  1107. EASTDC_API int OVcprintf(WriteFunction8 pWriteFunction8, void* EA_RESTRICT pContext, const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1108. {
  1109. return SprintfLocal::OVprintfCore(pWriteFunction8, pContext, pFormat, arguments);
  1110. }
  1111. EASTDC_API int OVfprintf(FILE* EA_RESTRICT pFile, const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1112. {
  1113. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter8, pFile, pFormat, arguments);
  1114. }
  1115. EASTDC_API int OVprintf(const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1116. {
  1117. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter8, stdout, pFormat, arguments);
  1118. }
  1119. EASTDC_API int OVsprintf(char8_t* EA_RESTRICT pDestination, const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1120. {
  1121. return OVsnprintf(pDestination, (size_t)-1, pFormat, arguments);
  1122. }
  1123. EASTDC_API int OVsnprintf(char8_t* EA_RESTRICT pDestination, size_t n, const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1124. {
  1125. SprintfLocal::SnprintfContext8 sc(pDestination, 0, pDestination ? n : 0);
  1126. const int nRequiredLength = SprintfLocal::OVprintfCore(SprintfLocal::StringWriter8, &sc, pFormat, arguments);
  1127. #if EASPRINTF_SNPRINTF_C99_RETURN
  1128. if(pDestination && (nRequiredLength >= 0))
  1129. {
  1130. if((size_t)nRequiredLength < n) // If there was enough space...
  1131. pDestination[nRequiredLength] = 0;
  1132. else if(n > 0)
  1133. pDestination[n - 1] = 0;
  1134. } // Else an encoding error has occurred and we can do nothing.
  1135. return nRequiredLength;
  1136. #else
  1137. if((size_t)nRequiredLength < n)
  1138. {
  1139. if(pDestination)
  1140. pDestination[nRequiredLength] = 0;
  1141. return n;
  1142. }
  1143. else if((n > 0) && pDestination)
  1144. pDestination[n - 1] = 0;
  1145. return -1;
  1146. #endif
  1147. }
  1148. EASTDC_API int OVscprintf(const char8_t* EA_RESTRICT pFormat, va_list arguments)
  1149. {
  1150. // vscprintf returns the number of chars that are needed for a printf operation.
  1151. return OVsnprintf(NULL, 0, pFormat, arguments);
  1152. }
  1153. EASTDC_API int OCprintf(WriteFunction8 pWriteFunction, void* EA_RESTRICT pContext, const char8_t* EA_RESTRICT pFormat, ...)
  1154. {
  1155. va_list arguments;
  1156. va_start(arguments, pFormat);
  1157. return SprintfLocal::OVprintfCore(pWriteFunction, pContext, pFormat, arguments);
  1158. }
  1159. EASTDC_API int OFprintf(FILE* EA_RESTRICT pFile, const char8_t* EA_RESTRICT pFormat, ...)
  1160. {
  1161. va_list arguments;
  1162. va_start(arguments, pFormat);
  1163. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter8, pFile, pFormat, arguments);
  1164. }
  1165. EASTDC_API int OPrintf(const char8_t* EA_RESTRICT pFormat, ...)
  1166. {
  1167. va_list arguments;
  1168. va_start(arguments, pFormat);
  1169. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter8, stdout, pFormat, arguments);
  1170. }
  1171. EASTDC_API int OSprintf(char8_t* EA_RESTRICT pDestination, const char8_t* EA_RESTRICT pFormat, ...)
  1172. {
  1173. va_list arguments;
  1174. va_start(arguments, pFormat);
  1175. return OVsnprintf(pDestination, (size_t)SprintfLocal::kNoPrecision, pFormat, arguments);
  1176. }
  1177. EASTDC_API int OSnprintf(char8_t* EA_RESTRICT pDestination, size_t n, const char8_t* EA_RESTRICT pFormat, ...)
  1178. {
  1179. va_list arguments;
  1180. va_start(arguments, pFormat);
  1181. return OVsnprintf(pDestination, n, pFormat, arguments);
  1182. }
  1183. ///////////////////////////////////////////////////////////////////////////////
  1184. // char16_t
  1185. ///////////////////////////////////////////////////////////////////////////////
  1186. EASTDC_API int OVcprintf(WriteFunction16 pWriteFunction16, void* EA_RESTRICT pContext, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1187. {
  1188. return SprintfLocal::OVprintfCore(pWriteFunction16, pContext, pFormat, arguments);
  1189. }
  1190. EASTDC_API int OVfprintf(FILE* EA_RESTRICT pFile, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1191. {
  1192. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter16, pFile, pFormat, arguments);
  1193. }
  1194. EASTDC_API int OVprintf(const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1195. {
  1196. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter16, stdout, pFormat, arguments);
  1197. }
  1198. EASTDC_API int OVsprintf(char16_t* EA_RESTRICT pDestination, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1199. {
  1200. return OVsnprintf(pDestination, (size_t)-1, pFormat, arguments);
  1201. }
  1202. EASTDC_API int OVsnprintf(char16_t* EA_RESTRICT pDestination, size_t n, const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1203. {
  1204. SprintfLocal::SnprintfContext16 sc(pDestination, 0, pDestination ? n : 0);
  1205. const int nRequiredLength = SprintfLocal::OVprintfCore(SprintfLocal::StringWriter16, &sc, pFormat, arguments);
  1206. #if EASPRINTF_SNPRINTF_C99_RETURN
  1207. if(pDestination && (nRequiredLength >= 0))
  1208. {
  1209. if((size_t)nRequiredLength < n) // If there was enough space...
  1210. pDestination[nRequiredLength] = 0;
  1211. else if(n > 0)
  1212. pDestination[n - 1] = 0;
  1213. } // Else an encoding error has occurred and we can do nothing.
  1214. return nRequiredLength;
  1215. #else
  1216. if((size_t)nRequiredLength < n)
  1217. {
  1218. if(pDestination)
  1219. pDestination[nRequiredLength] = 0;
  1220. return n;
  1221. }
  1222. else if((n > 0) && pDestination)
  1223. pDestination[n - 1] = 0;
  1224. return -1;
  1225. #endif
  1226. }
  1227. EASTDC_API int OVscprintf(const char16_t* EA_RESTRICT pFormat, va_list arguments)
  1228. {
  1229. // vscprintf returns the number of chars that are needed for a printf operation.
  1230. return OVsnprintf(NULL, 0, pFormat, arguments);
  1231. }
  1232. EASTDC_API int OCprintf(WriteFunction16 pWriteFunction, void* EA_RESTRICT pContext, const char16_t* EA_RESTRICT pFormat, ...)
  1233. {
  1234. va_list arguments;
  1235. va_start(arguments, pFormat);
  1236. return SprintfLocal::OVprintfCore(pWriteFunction, pContext, pFormat, arguments);
  1237. }
  1238. EASTDC_API int OFprintf(FILE* EA_RESTRICT pFile, const char16_t* EA_RESTRICT pFormat, ...)
  1239. {
  1240. va_list arguments;
  1241. va_start(arguments, pFormat);
  1242. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter16, pFile, pFormat, arguments);
  1243. }
  1244. EASTDC_API int OPrintf(const char16_t* EA_RESTRICT pFormat, ...)
  1245. {
  1246. va_list arguments;
  1247. va_start(arguments, pFormat);
  1248. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter16, stdout, pFormat, arguments);
  1249. }
  1250. EASTDC_API int OSprintf(char16_t* EA_RESTRICT pDestination, const char16_t* EA_RESTRICT pFormat, ...)
  1251. {
  1252. va_list arguments;
  1253. va_start(arguments, pFormat);
  1254. return OVsnprintf(pDestination, (size_t)SprintfLocal::kNoPrecision, pFormat, arguments);
  1255. }
  1256. EASTDC_API int OSnprintf(char16_t* EA_RESTRICT pDestination, size_t n, const char16_t* EA_RESTRICT pFormat, ...)
  1257. {
  1258. va_list arguments;
  1259. va_start(arguments, pFormat);
  1260. return OVsnprintf(pDestination, n, pFormat, arguments);
  1261. }
  1262. ///////////////////////////////////////////////////////////////////////////////
  1263. // char32_t
  1264. ///////////////////////////////////////////////////////////////////////////////
  1265. EASTDC_API int OVcprintf(WriteFunction32 pWriteFunction32, void* EA_RESTRICT pContext, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1266. {
  1267. return SprintfLocal::OVprintfCore(pWriteFunction32, pContext, pFormat, arguments);
  1268. }
  1269. EASTDC_API int OVfprintf(FILE* EA_RESTRICT pFile, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1270. {
  1271. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter32, pFile, pFormat, arguments);
  1272. }
  1273. EASTDC_API int OVprintf(const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1274. {
  1275. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter32, stdout, pFormat, arguments);
  1276. }
  1277. EASTDC_API int OVsprintf(char32_t* EA_RESTRICT pDestination, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1278. {
  1279. return OVsnprintf(pDestination, (size_t)-1, pFormat, arguments);
  1280. }
  1281. EASTDC_API int OVsnprintf(char32_t* EA_RESTRICT pDestination, size_t n, const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1282. {
  1283. SprintfLocal::SnprintfContext32 sc(pDestination, 0, pDestination ? n : 0);
  1284. const int nRequiredLength = SprintfLocal::OVprintfCore(SprintfLocal::StringWriter32, &sc, pFormat, arguments);
  1285. #if EASPRINTF_SNPRINTF_C99_RETURN
  1286. if(pDestination && (nRequiredLength >= 0))
  1287. {
  1288. if((size_t)nRequiredLength < n) // If there was enough space...
  1289. pDestination[nRequiredLength] = 0;
  1290. else if(n > 0)
  1291. pDestination[n - 1] = 0;
  1292. } // Else an encoding error has occurred and we can do nothing.
  1293. return nRequiredLength;
  1294. #else
  1295. if((size_t)nRequiredLength < n)
  1296. {
  1297. if(pDestination)
  1298. pDestination[nRequiredLength] = 0;
  1299. return n;
  1300. }
  1301. else if((n > 0) && pDestination)
  1302. pDestination[n - 1] = 0;
  1303. return -1;
  1304. #endif
  1305. }
  1306. EASTDC_API int OVscprintf(const char32_t* EA_RESTRICT pFormat, va_list arguments)
  1307. {
  1308. // vscprintf returns the number of chars that are needed for a printf operation.
  1309. return OVsnprintf(NULL, 0, pFormat, arguments);
  1310. }
  1311. EASTDC_API int OCprintf(WriteFunction32 pWriteFunction, void* EA_RESTRICT pContext, const char32_t* EA_RESTRICT pFormat, ...)
  1312. {
  1313. va_list arguments;
  1314. va_start(arguments, pFormat);
  1315. return SprintfLocal::OVprintfCore(pWriteFunction, pContext, pFormat, arguments);
  1316. }
  1317. EASTDC_API int OFprintf(FILE* EA_RESTRICT pFile, const char32_t* EA_RESTRICT pFormat, ...)
  1318. {
  1319. va_list arguments;
  1320. va_start(arguments, pFormat);
  1321. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter32, pFile, pFormat, arguments);
  1322. }
  1323. EASTDC_API int OPrintf(const char32_t* EA_RESTRICT pFormat, ...)
  1324. {
  1325. va_list arguments;
  1326. va_start(arguments, pFormat);
  1327. return SprintfLocal::OVprintfCore(SprintfLocal::FILEWriter32, stdout, pFormat, arguments);
  1328. }
  1329. EASTDC_API int OSprintf(char32_t* EA_RESTRICT pDestination, const char32_t* EA_RESTRICT pFormat, ...)
  1330. {
  1331. va_list arguments;
  1332. va_start(arguments, pFormat);
  1333. return OVsnprintf(pDestination, (size_t)SprintfLocal::kNoPrecision, pFormat, arguments);
  1334. }
  1335. EASTDC_API int OSnprintf(char32_t* EA_RESTRICT pDestination, size_t n, const char32_t* EA_RESTRICT pFormat, ...)
  1336. {
  1337. va_list arguments;
  1338. va_start(arguments, pFormat);
  1339. return OVsnprintf(pDestination, n, pFormat, arguments);
  1340. }
  1341. } // namespace StdC
  1342. } // namespace EA
  1343. #ifdef _MSC_VER
  1344. #pragma warning(pop)
  1345. #endif