EAScanfCore.cpp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EAStdC/internal/Config.h>
  5. #include <EAStdC/EAScanf.h>
  6. #include <EAStdC/internal/ScanfCore.h>
  7. #include <EAStdC/EAString.h>
  8. #include <EAStdC/EACType.h>
  9. #include <EAStdC/EAMathHelp.h>
  10. #include <EAAssert/eaassert.h>
  11. EA_DISABLE_ALL_VC_WARNINGS()
  12. #include <math.h>
  13. #include <float.h>
  14. #include <stddef.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <errno.h>
  19. #include <limits.h>
  20. EA_RESTORE_ALL_VC_WARNINGS()
  21. EA_DISABLE_VC_WARNING(4127 4146) // C4127: conditional expression is constant.
  22. // C4146: unary minus operator applied to unsigned type, result still unsigned
  23. #if defined(EA_PLATFORM_WINDOWS)
  24. // Users sometimes get link problems when mixing DLL and non-DLL builds under Windows
  25. // due to HUGE_VAL. This is due to how they are building the app, though we can help
  26. // avoid the problem by using a different source for HUGE_VAL.
  27. #define EASTDC_HUGE_VAL EA::StdC::kFloat64Infinity
  28. #else
  29. #define EASTDC_HUGE_VAL HUGE_VAL
  30. #endif
  31. // EA_ENABLE_PRECISE_FP / EA_RESTORE_PRECISE_FP
  32. //
  33. // Allows you to force the usage of precise floating point support by the compiler, whereas the
  34. // compiler may have been set to default to another form which is faster but doesn't strictly
  35. // follow conventions. For example, see:
  36. // http://connect.microsoft.com/VisualStudio/feedback/details/754839/signed-double-0-0-vs-0-0-msvs2012-visual-c-bug-in-x64-mode-when-compiled-with-fp-fast-o2
  37. // Reference:
  38. // http://msdn.microsoft.com/en-us/library/45ec64h6.aspx
  39. //
  40. // Example usage:
  41. // EA_ENABLE_PRECISE_FP()
  42. // void SomeFunction(){ ... }
  43. // EA_RESTORE_PRECISE_FP()
  44. //
  45. #if !defined(EA_ENABLE_PRECISE_FP)
  46. #if defined(EA_COMPILER_MSVC)
  47. #define EA_ENABLE_PRECISE_FP() __pragma(float_control(precise, on, push))
  48. #else
  49. #define EA_ENABLE_PRECISE_FP()
  50. #endif
  51. #endif
  52. #if !defined(EA_RESTORE_PRECISE_FP)
  53. #if defined(EA_COMPILER_MSVC)
  54. #define EA_RESTORE_PRECISE_FP() __pragma(float_control(pop))
  55. #else
  56. #define EA_RESTORE_PRECISE_FP()
  57. #endif
  58. #endif
  59. namespace EA
  60. {
  61. namespace StdC
  62. {
  63. extern uint8_t utf8lengthTable[256];
  64. namespace ScanfLocal
  65. {
  66. int FILEReader8(ReadAction readAction, int value, void* pContext)
  67. {
  68. // We verify that the FILE functions work as desired. If this fails to
  69. // be so for some compiler/platform then we can modify this code.
  70. EA_COMPILETIME_ASSERT(EOF == kReadError);
  71. FILE* const pFile = (FILE*)pContext;
  72. switch(readAction)
  73. {
  74. case kReadActionBegin:
  75. {
  76. #if (!defined(__GNUC__) || (__GNUC__ >= 4)) // Older versions of GCC don't support fwide().
  77. // Question: Is this doing the right thing? Or do we need to be doing something else?
  78. if(value == 1) // "The value param will be 1 for UTF8 and 2 for UCS2."
  79. return (fwide(pFile, -1) < 0) ? 1 : 0; // Set the file to be interpreted as UTF8.
  80. else
  81. {
  82. // Problem: wide is 2 bytes for some platforms and 4 for others. The only way for us
  83. // to fix this problem properly is to handle 32->16 or 16->32 conversions on our
  84. // side. But we don't have state information in this FileReader8 function. We would
  85. // need to revise pContext to provide some space for us to write state.
  86. return (fwide(pFile, 1) > 0) ? 1 : 0; // Set the file to be interpreted as wide.
  87. }
  88. #endif
  89. }
  90. case kReadActionEnd:
  91. // Currently we do nothing, but possibly we should restore the file byte/wide state.
  92. break;
  93. case kReadActionRead:
  94. return fgetc(pFile);
  95. case kReadActionUnread:
  96. return ungetc(value, pFile);
  97. case kReadActionGetAtEnd:
  98. return feof(pFile);
  99. case kReadActionGetLastError:
  100. return ferror(pFile);
  101. }
  102. return 0;
  103. }
  104. int FILEReader16(ReadAction readAction, int value, void* pContext)
  105. {
  106. return FILEReader8(readAction, value, pContext);
  107. }
  108. int FILEReader32(ReadAction readAction, int value, void* pContext)
  109. {
  110. return FILEReader8(readAction, value, pContext);
  111. }
  112. int StringReader8(ReadAction readAction, int /*value*/, void* pContext)
  113. {
  114. SscanfContext8* const pSscanfContext8 = (SscanfContext8*)pContext;
  115. switch(readAction)
  116. {
  117. case kReadActionBegin:
  118. case kReadActionEnd:
  119. case kReadActionGetLastError:
  120. break;
  121. case kReadActionRead:
  122. if(*pSscanfContext8->mpSource)
  123. return (uint8_t)*pSscanfContext8->mpSource++;
  124. else
  125. {
  126. pSscanfContext8->mbEndFound = 1;
  127. return kReadError;
  128. }
  129. case kReadActionUnread:
  130. if(!pSscanfContext8->mbEndFound)
  131. pSscanfContext8->mpSource--; // We don't error-check this; we currently assume the caller is bug-free.
  132. else
  133. pSscanfContext8->mbEndFound = 0;
  134. break;
  135. case kReadActionGetAtEnd:
  136. return pSscanfContext8->mbEndFound;
  137. }
  138. return 0;
  139. }
  140. int StringReader16(ReadAction readAction, int /*value*/, void* pContext)
  141. {
  142. SscanfContext16* const pSscanfContext16 = (SscanfContext16*)pContext;
  143. switch(readAction)
  144. {
  145. case kReadActionBegin:
  146. case kReadActionEnd:
  147. case kReadActionGetLastError:
  148. break;
  149. case kReadActionRead:
  150. if(*pSscanfContext16->mpSource)
  151. {
  152. EA_COMPILETIME_ASSERT(sizeof(int) >= sizeof(char16_t));
  153. return (int)(char16_t)*pSscanfContext16->mpSource++;
  154. }
  155. else
  156. {
  157. pSscanfContext16->mbEndFound = 1;
  158. return kReadError;
  159. }
  160. case kReadActionUnread:
  161. if(!pSscanfContext16->mbEndFound)
  162. pSscanfContext16->mpSource--; // We don't error-check this; we currently assume the caller is bug-free.
  163. else
  164. pSscanfContext16->mbEndFound = 0;
  165. break;
  166. case kReadActionGetAtEnd:
  167. return pSscanfContext16->mbEndFound;
  168. }
  169. return 0;
  170. }
  171. int StringReader32(ReadAction readAction, int /*value*/, void* pContext)
  172. {
  173. SscanfContext32* const pSscanfContext32 = (SscanfContext32*)pContext;
  174. switch(readAction)
  175. {
  176. case kReadActionBegin:
  177. case kReadActionEnd:
  178. case kReadActionGetLastError:
  179. break;
  180. case kReadActionRead:
  181. if(*pSscanfContext32->mpSource)
  182. {
  183. EA_COMPILETIME_ASSERT(sizeof(int) >= sizeof(char32_t));
  184. return (int)(char32_t)*pSscanfContext32->mpSource++;
  185. }
  186. else
  187. {
  188. pSscanfContext32->mbEndFound = 1;
  189. return kReadError;
  190. }
  191. case kReadActionUnread:
  192. if(!pSscanfContext32->mbEndFound)
  193. pSscanfContext32->mpSource--; // We don't error-check this; we currently assume the caller is bug-free.
  194. else
  195. pSscanfContext32->mbEndFound = 0;
  196. break;
  197. case kReadActionGetAtEnd:
  198. return pSscanfContext32->mbEndFound;
  199. }
  200. return 0;
  201. }
  202. ///////////////////////////////////////////////////////////////////////////////
  203. // ToDouble
  204. //
  205. // We have a string of digits and an exponent. We need to convert them to
  206. // a double.
  207. //
  208. // The proper conversion from string to double is not entirely trivial,
  209. // as documented in the papers:
  210. // What Every Computer Scientist Should Know About Floating Point Arithmetic
  211. // How to Read Floating Point Numbers Accurately
  212. // Correctly Rounded Binary-Decimal and Decimal-Binary Conversions
  213. //
  214. const double powerTable[18] = { 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11 };
  215. double DoubleValue::ToDouble() const
  216. {
  217. if(mExponent >= -6 && mExponent <= 11) // If we can handle the result quickly and accurately with a simple implementation...
  218. {
  219. // We could handle exponents bigger than this if we used a bigger table or (better) if we
  220. // wrote code that allowed us to apply a multiplier to the existing table. On the other hand,
  221. // for our purposes it is uncommon to work with such huge numbers.
  222. double result = 0.0;
  223. for(int i = 0; i < mSigLen; ++i)
  224. result = (result * 10.0) + (float)(mSigStr[i] - '0');
  225. result *= powerTable[mExponent + 6]; // +6 because our smallest exponent above is 1e-6
  226. return result;
  227. }
  228. else
  229. {
  230. // Negative exponents mean the number has a fractional component.
  231. // However, floating point hardware can't perfectly represent decimal
  232. // fractions. A result of this, as noted in the above papers, is that
  233. // a simple loop which multiplies by 10 won't yield an ideal floating
  234. // point representation for all decimal values. In the absence of
  235. // FPU hardware support for decimal to binary conversions, the only
  236. // way to achieve the ideal solution is to use an iterative approximating
  237. // algorithm.
  238. //
  239. // Until we implement that algorithm we do a fallback to the system
  240. // provided strtod function, which in many cases will implement such
  241. // an algorithm itself internally.
  242. char8_t buffer[kMaxSignificandDigits + 12];
  243. int i;
  244. for(i = 0; i < mSigLen; ++i)
  245. buffer[i] = mSigStr[i];
  246. if(mExponent)
  247. {
  248. int multiplier;
  249. int e = mExponent;
  250. buffer[i++] = 'e';
  251. if(e < 0)
  252. {
  253. buffer[i++] = '-';
  254. e = -e;
  255. }
  256. if(e >= 100)
  257. multiplier = 100;
  258. else if(e >= 10)
  259. multiplier = 10;
  260. else
  261. multiplier = 1;
  262. while(multiplier)
  263. {
  264. buffer[i++] = (char8_t)('0' + (e / multiplier));
  265. e %= multiplier;
  266. multiplier /= 10;
  267. }
  268. }
  269. buffer[i] = 0;
  270. return strtod(buffer, NULL); // This is not a fast function. That's why we want to replace it.
  271. }
  272. }
  273. // Force precise floating support by the compiler. This is necessary under VC++ because otherwise
  274. // it's possible that the /fp:fast compiler argument was used, which causes the -0.0 code below to
  275. // be generated by the compiler in a non-conformant way. This generation is by design, but prevents
  276. // us from having a conforming scanf implementation.
  277. EA_ENABLE_PRECISE_FP()
  278. template<typename ReadFunctionT, typename ReadFormatSpanFunctionT, typename CharT>
  279. class VscanfUtil
  280. {
  281. public:
  282. int VscanfCore(ReadFunctionT pReadFunction, ReadFormatSpanFunctionT pReadFormatSpanFunction, void* pContext, const CharT* pFormat, va_list arguments)
  283. {
  284. using namespace ScanfLocal;
  285. int nAssignmentCount = 0; // Number of assigned fields. This is the return value of this function. -1 in case of error.
  286. int nConversionCount = 0; // Number of processed fields. Will be >= the number of assigned fields.
  287. int nReadCount; // Temporary holder.
  288. int nReadCountSum = 0; // Used to support the %n field.
  289. const CharT* pFormatCurrent = pFormat; // Current position within entire fd string.
  290. char* pArgumentCurrent = NULL; // Pointer to current va_list argument.
  291. FormatData fd; //
  292. int c = 0; // Temporary character.
  293. uintmax_t uintMaxValue = 0; //
  294. intmax_t intMaxValue = 0; //
  295. long double ldValue; //
  296. int bNegative; //
  297. int bIntegerOverflow; //
  298. int nBase; //
  299. pReadFunction(kReadActionBegin, sizeof(*pFormat), pContext);
  300. while(*pFormatCurrent)
  301. {
  302. CharT cFormat = *pFormatCurrent;
  303. if(Isspace(cFormat))
  304. {
  305. do{
  306. cFormat = *++pFormatCurrent;
  307. }
  308. while(Isspace(cFormat));
  309. while(Isspace((CharT)(c = pReadFunction(kReadActionRead, 0, pContext))))
  310. ++nReadCountSum;
  311. pReadFunction(kReadActionUnread, c, pContext);
  312. continue;
  313. }
  314. if(cFormat != '%')
  315. {
  316. if((c = pReadFunction(kReadActionRead, 0, pContext)) != (int)cFormat)
  317. {
  318. pReadFunction(kReadActionUnread, c, pContext);
  319. goto Done;
  320. }
  321. ++nReadCountSum;
  322. ++pFormatCurrent;
  323. continue;
  324. }
  325. pFormatCurrent = ReadFormat(pFormatCurrent, &fd);
  326. if((fd.mnType == '%') || fd.mbSkipAssignment)
  327. pArgumentCurrent = NULL;
  328. else
  329. pArgumentCurrent = (char*)va_arg(arguments, void*); // User arguments are always passed as pointers.
  330. if((fd.mnType != 'n') && (pReadFunction(kReadActionGetLastError, 0, pContext) || pReadFunction(kReadActionGetAtEnd, 0, pContext)))
  331. break;
  332. switch (fd.mnType)
  333. {
  334. case '%':
  335. {
  336. while(Isspace((CharT)(c = pReadFunction(kReadActionRead, 0, pContext))))
  337. ++nReadCountSum;
  338. if(c != '%')
  339. {
  340. pReadFunction(kReadActionUnread, c, pContext);
  341. goto Done;
  342. }
  343. ++nReadCountSum;
  344. break;
  345. }
  346. case 'n':
  347. {
  348. if(pArgumentCurrent) // If we should write the value to a user argument...
  349. {
  350. switch (fd.mModifier)
  351. {
  352. // There are some other modifier types we could support here.
  353. case kModifierMax_t: *(intmax_t*) pArgumentCurrent = (intmax_t) nReadCountSum; break;
  354. case kModifierSize_t: *(size_t*) pArgumentCurrent = (size_t) nReadCountSum; break;
  355. case kModifierPtrdiff_t:*(ptrdiff_t*)pArgumentCurrent = (ptrdiff_t)nReadCountSum; break;
  356. case kModifierInt64: *(int64_t*) pArgumentCurrent = (int64_t) nReadCountSum; break;
  357. case kModifierLongLong: *(long long*)pArgumentCurrent = (long long)nReadCountSum; break;
  358. case kModifierInt32: *(int32_t*) pArgumentCurrent = (int32_t) nReadCountSum; break;
  359. case kModifierLong: *(long*) pArgumentCurrent = (long) nReadCountSum; break;
  360. case kModifierInt16:
  361. case kModifierShort: *(short*) pArgumentCurrent = (short) nReadCountSum; break;
  362. case kModifierInt8:
  363. case kModifierChar: *(char*) pArgumentCurrent = (char) nReadCountSum; break;
  364. case kModifierNone: *(int*) pArgumentCurrent = (int) nReadCountSum; break;
  365. default: break;
  366. }
  367. }
  368. continue;
  369. }
  370. case 'b': // 'b' means binary. This is a convenient extension that we provide.
  371. case 'o':
  372. case 'u':
  373. case 'i':
  374. case 'd':
  375. case 'x':
  376. case 'X':
  377. {
  378. // To consider: replace if/else usage below with a switch or something with less branching.
  379. if(fd.mnType == 'b')
  380. nBase = 2;
  381. else if(fd.mnType == 'o')
  382. nBase = 8;
  383. else if(fd.mnType == 'u' || fd.mnType == 'd')
  384. nBase = 10;
  385. else if(fd.mnType == 'i')
  386. nBase = 0;
  387. else
  388. nBase = 16;
  389. switch (fd.mModifier)
  390. {
  391. case kModifierMax_t:
  392. uintMaxValue = (uintmax_t) ReadUint64(pReadFunction, pContext, UINTMAX_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  393. break;
  394. case kModifierSize_t:
  395. uintMaxValue = (size_t) ReadUint64(pReadFunction, pContext, SIZE_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  396. break;
  397. case kModifierPtrdiff_t:
  398. uintMaxValue = (ptrdiff_t) ReadUint64(pReadFunction, pContext, PTRDIFF_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  399. break;
  400. case kModifierInt64:
  401. case kModifierLongLong:
  402. uintMaxValue = (unsigned long long)ReadUint64(pReadFunction, pContext, UINT64_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  403. break;
  404. case kModifierInt32:
  405. case kModifierLong:
  406. uintMaxValue = (unsigned long) ReadUint64(pReadFunction, pContext, UINT32_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  407. break;
  408. case kModifierInt16:
  409. case kModifierShort:
  410. uintMaxValue = (unsigned long) ReadUint64(pReadFunction, pContext, UINT16_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  411. break;
  412. case kModifierInt8:
  413. case kModifierChar:
  414. default:
  415. uintMaxValue = (unsigned long) ReadUint64(pReadFunction, pContext, UINT8_MAX, nBase, fd.mnWidth, nReadCount, bNegative, bIntegerOverflow);
  416. break;
  417. }
  418. if(!nReadCount)
  419. goto Done;
  420. if((fd.mnType == 'i' || fd.mnType == 'd')) // If using a signed type...
  421. {
  422. if(bNegative)
  423. intMaxValue = -uintMaxValue;
  424. else
  425. intMaxValue = (intmax_t)uintMaxValue;
  426. if(pArgumentCurrent) // If we should write the value to a user argument...
  427. {
  428. switch (fd.mModifier)
  429. {
  430. case kModifierMax_t: *(intmax_t*) pArgumentCurrent = (intmax_t) intMaxValue; break;
  431. case kModifierSize_t: *(size_t*) pArgumentCurrent = (size_t) intMaxValue; break;
  432. case kModifierPtrdiff_t:*(ptrdiff_t*) pArgumentCurrent = (ptrdiff_t) intMaxValue; break;
  433. case kModifierInt64: *(int64_t*) pArgumentCurrent = (int64_t) intMaxValue; break;
  434. case kModifierLongLong: *(long long*) pArgumentCurrent = intMaxValue; break;
  435. case kModifierInt32: *(int32_t*) pArgumentCurrent = (int32_t) intMaxValue; break; // We assume sizeof long >= sizeof int32
  436. case kModifierLong: *(long*) pArgumentCurrent = (long) intMaxValue; break;
  437. case kModifierInt16:
  438. case kModifierShort: *(short*) pArgumentCurrent = (short) intMaxValue; break;
  439. case kModifierInt8:
  440. case kModifierChar: *(char*) pArgumentCurrent = (char) intMaxValue; break;
  441. case kModifierNone: *(int*) pArgumentCurrent = (int) intMaxValue; break;
  442. default: /* This should never occur. Possibly assert false */ break;
  443. }
  444. nAssignmentCount++;
  445. }
  446. }
  447. else
  448. {
  449. if(bNegative)
  450. {
  451. // It's a little odd to use a negative sign in front of an unsigned value, but it's valid C.
  452. uintMaxValue = (uintmax_t)-(intmax_t)uintMaxValue;
  453. }
  454. // else leave as-is.
  455. if(pArgumentCurrent) // If we should write the value to a user argument...
  456. {
  457. switch (fd.mModifier)
  458. {
  459. case kModifierMax_t: *(uintmax_t*) pArgumentCurrent = (uintmax_t) uintMaxValue; break;
  460. case kModifierSize_t: *(size_t*) pArgumentCurrent = (size_t) uintMaxValue; break;
  461. case kModifierPtrdiff_t:*(ptrdiff_t*) pArgumentCurrent = (ptrdiff_t) uintMaxValue; break;
  462. case kModifierInt64: *(uint64_t*) pArgumentCurrent = (uint64_t) uintMaxValue; break;
  463. case kModifierLongLong: *(unsigned long long*) pArgumentCurrent = uintMaxValue; break;
  464. case kModifierInt32: *(uint32_t*) pArgumentCurrent = (uint32_t) uintMaxValue; break; // We assume sizeof ulong >= sizeof uint32
  465. case kModifierLong: *(unsigned long*) pArgumentCurrent = (unsigned long) uintMaxValue; break;
  466. case kModifierInt16:
  467. case kModifierShort: *(unsigned short*) pArgumentCurrent = (unsigned short) uintMaxValue; break;
  468. case kModifierInt8:
  469. case kModifierChar: *(unsigned char*) pArgumentCurrent = (unsigned char) uintMaxValue; break;
  470. case kModifierNone: *(unsigned int*) pArgumentCurrent = (unsigned int) uintMaxValue; break;
  471. default: /* This should never occur. Possibly assert false */ break;
  472. }
  473. nAssignmentCount++;
  474. }
  475. }
  476. nReadCountSum += nReadCount;
  477. nConversionCount++;
  478. break;
  479. }
  480. case 'e':
  481. case 'E':
  482. case 'f':
  483. case 'F':
  484. case 'g':
  485. case 'G':
  486. case 'a':
  487. case 'A':
  488. {
  489. ldValue = ReadDouble(pReadFunction, pContext, fd.mnWidth, fd.mDecimalPoint, nReadCount, bIntegerOverflow);
  490. if(!nReadCount)
  491. goto Done;
  492. if(pArgumentCurrent) // If we should write the value to a user argument...
  493. {
  494. switch (fd.mModifier)
  495. {
  496. case kModifierLongDouble: *(long double*) pArgumentCurrent = ldValue; break;
  497. case kModifierDouble: *(double*) pArgumentCurrent = (double)ldValue; break;
  498. case kModifierNone: *(float*) pArgumentCurrent = (float) ldValue; break;
  499. default: /* This should never occur. Possibly assert false */ break;
  500. }
  501. nAssignmentCount++;
  502. }
  503. nReadCountSum += nReadCount;
  504. nConversionCount++;
  505. break;
  506. }
  507. case 's':
  508. case 'S':
  509. {
  510. c = pReadFunction(kReadActionRead, 0, pContext);
  511. // We eat leading whitespace and then fall through to reading characters.
  512. while(Isspace((CharT)c))
  513. {
  514. ++nReadCountSum;
  515. c = pReadFunction(kReadActionRead, 0, pContext);
  516. }
  517. pReadFunction(kReadActionUnread, c, pContext);
  518. // Fall through, as %[] processing is the same as %s except %[] specifies a filter for what characters to accept or ignore.
  519. }
  520. case '[':
  521. {
  522. // The user can use %[ab ] to read chars 'a', 'b', ' ' into the string until some other char is encountered.
  523. nReadCount = 0;
  524. if(pArgumentCurrent) // If we should write the value to a user argument...
  525. {
  526. int stringTypeSize;
  527. switch (fd.mModifier)
  528. {
  529. case kModifierInt8: // If the user specified %I8s or %I8S
  530. case kModifierChar: // If the user specified %hs or %hS or kModifierWChar was chosen implicitly for other reasons.
  531. stringTypeSize = 1;
  532. break;
  533. case kModifierInt16: // If the user specified %I16s or %I16S
  534. stringTypeSize = 2;
  535. break;
  536. case kModifierInt32: // If the user specified %I32s or %I32S
  537. stringTypeSize = 4;
  538. break;
  539. case kModifierWChar: // If the user specified %ls or %lS or kModifierWChar was chosen implicitly for other reasons.
  540. stringTypeSize = sizeof(wchar_t);
  541. break;
  542. default: // If the user specified %I64s or %I64S or another invalid size.
  543. //nAssignmentCount = -1; Should we do this?
  544. goto Done;
  545. }
  546. if (!pReadFormatSpanFunction(fd, c, pReadFunction, pContext, stringTypeSize, pArgumentCurrent, nReadCount))
  547. {
  548. nAssignmentCount = -1;
  549. goto Done;
  550. }
  551. if(!nReadCount)
  552. {
  553. pReadFunction(kReadActionUnread, c, pContext);
  554. goto Done;
  555. }
  556. // 0-terminate the user's string.
  557. switch (stringTypeSize)
  558. {
  559. case 1:
  560. *((char8_t*)pArgumentCurrent) = 0;
  561. break;
  562. case 2:
  563. *((char16_t*)pArgumentCurrent) = 0;
  564. break;
  565. case 4:
  566. *((char32_t*)pArgumentCurrent) = 0;
  567. break;
  568. }
  569. nAssignmentCount++;
  570. }
  571. else
  572. {
  573. pReadFormatSpanFunction(fd, c, pReadFunction, pContext, -1, pArgumentCurrent, nReadCount);
  574. if(!nReadCount)
  575. {
  576. pReadFunction(kReadActionUnread, c, pContext);
  577. break;
  578. }
  579. }
  580. if(fd.mnWidth >= 0)
  581. pReadFunction(kReadActionUnread, c, pContext);
  582. nReadCountSum += nReadCount;
  583. nConversionCount++;
  584. break;
  585. }
  586. case 'c':
  587. case 'C': // Actually %C is not a standard scanf format.
  588. {
  589. // The user can specify %23c to read 23 chars (including spaces) into an array, with no 0-termination.
  590. if(!fd.mbWidthSpecified)
  591. fd.mnWidth = 1;
  592. nReadCount = 0;
  593. if(pArgumentCurrent) // If we should write the value to a user argument...
  594. {
  595. int charTypeSize;
  596. switch (fd.mModifier)
  597. {
  598. case kModifierInt8: // If the user specified %I8c or %I8C
  599. case kModifierChar: // If the user specified %hc or %hC or kModifierWChar was chosen implicitly for other reasons.
  600. charTypeSize = 1;
  601. break;
  602. case kModifierInt16: // If the user specified %I16c or %I16C
  603. charTypeSize = 2;
  604. break;
  605. case kModifierInt32: // If the user specified %I32c or %I32C
  606. charTypeSize = 4;
  607. break;
  608. case kModifierWChar: // If the user specified %lc or %lC or kModifierWChar was chosen implicitly for other reasons.
  609. charTypeSize = sizeof(wchar_t);
  610. break;
  611. default: // If the user specified %I64c or %I64C or another invalid size.
  612. //nAssignmentCount = -1; Should we do this?
  613. goto Done;
  614. }
  615. while(fd.mnWidth-- && ((c = pReadFunction(kReadActionRead, 0, pContext)) != -1))
  616. {
  617. switch (charTypeSize)
  618. {
  619. case 1:
  620. // Applicable for 16 and 32 bit character string variant
  621. #if EASTDC_SCANF_WARNINGS_ENABLED
  622. //if(c > 127)
  623. // ReportScanfWarning(loss of information);
  624. #endif
  625. *((char8_t*)pArgumentCurrent) = (char8_t)(uint8_t)(unsigned)c;
  626. break;
  627. case 2:
  628. // Applicable for 8bit character string variant
  629. // To do: Support UTF8 sequences.
  630. // size_t charLength = UTF8CharSize(&c); Do this only for the first char.
  631. // if(charLength > 1)
  632. // read into buffer and do a single char Strlcpy from 8 bit to 16 bit.
  633. // Applicable for 32bit character string variant
  634. #if EASTDC_SCANF_WARNINGS_ENABLED
  635. //if(c > 65535)
  636. // ReportScanfWarning(loss of information);
  637. #endif
  638. *((char16_t*)pArgumentCurrent) = (char16_t)c;
  639. break;
  640. case 4:
  641. // Applicable for 8bit character string variant
  642. // To do: Support UTF8 sequences.
  643. *((char32_t*)pArgumentCurrent) = (char32_t)c;
  644. break;
  645. }
  646. ++nReadCount;
  647. }
  648. if(!nReadCount)
  649. goto Done;
  650. nAssignmentCount++;
  651. }
  652. else // else ignore the field
  653. {
  654. while(fd.mnWidth-- && ((c = pReadFunction(kReadActionRead, 0, pContext)) != -1))
  655. ++nReadCount;
  656. if(!nReadCount)
  657. goto Done;
  658. }
  659. nReadCountSum += nReadCount;
  660. nConversionCount++;
  661. break;
  662. }
  663. case kFormatError:
  664. default:
  665. goto Done;
  666. } // switch (fd.mnType)
  667. } // while(*pFormatCurrent)
  668. Done:
  669. if((nConversionCount == 0) && pReadFunction(kReadActionGetLastError, 0, pContext))
  670. nAssignmentCount = -1;
  671. pReadFunction(kReadActionEnd, 0, pContext);
  672. return nAssignmentCount;
  673. }
  674. private:
  675. const CharT* ReadFormat(const CharT* pFormat, FormatData* pFormatData)
  676. {
  677. const CharT* pFormatCurrent = pFormat;
  678. bool bModifierPresent = true; // True until proven false.
  679. FormatData fd;
  680. CharT c;
  681. c = *++pFormatCurrent;
  682. if(c == '%') // A %% sequence means to simply treat it as a literal '%'.
  683. {
  684. fd.mnType = '%';
  685. *pFormatData = fd;
  686. return ++pFormatCurrent;
  687. }
  688. if(Isdigit(c)) // If the user is specifying a field width...
  689. {
  690. // The standard doesn't say anything special about a field width of zero, so we allow it.
  691. fd.mbWidthSpecified = 1;
  692. fd.mnWidth = 0;
  693. do{
  694. fd.mnWidth = (int)((fd.mnWidth * 10) + (c - '0'));
  695. c = *++pFormatCurrent;
  696. } while(Isdigit(c));
  697. }
  698. else if(c == '*') // A * char after % means to skip the assignment but eat it from the source data.
  699. {
  700. fd.mbSkipAssignment = true;
  701. c = *++pFormatCurrent;
  702. }
  703. // See if the user specified a modifier, such as h, hh, l, ll, or L.
  704. switch (c)
  705. {
  706. case 'h': // handle h and hh
  707. {
  708. if(pFormatCurrent[1] == 'h') // If the fd is hh ...
  709. {
  710. fd.mModifier = kModifierChar; // Specifies that a following d, i, o, u, x, X, or n conversion specifier applies to an argument with type pointer to signed char or unsigned char.
  711. c = *++pFormatCurrent;
  712. }
  713. else
  714. fd.mModifier = kModifierShort; // Specifies that a following d, i, o, u, x, X, or n conversion specifier applies to an argument with type pointer to short int or unsigned short int.
  715. break;
  716. }
  717. case 'l': // handle l and ll
  718. {
  719. if(pFormatCurrent[1] == 'l') // If the fd is ll ...
  720. {
  721. fd.mModifier = kModifierLongLong; // Specifies that a following d, i, o, u, x, X, or n conversion specifier applies to an argument with type pointer to long long int or unsigned long long int.
  722. c = *++pFormatCurrent;
  723. }
  724. else
  725. fd.mModifier = kModifierLong; // Specifies that a following d, i, o, u, x, X, or n conversion specifier applies to an argument with type pointer to long int or unsigned long int; that a following a, A, e, E, f, F, g, or G conversion specifier applies to an argument with type pointer to double; or that a following c, s, or [ conversion specifier applies to an argument with type pointer to wchar_t.
  726. break;
  727. }
  728. case 'j':
  729. // 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.
  730. fd.mModifier = kModifierMax_t;
  731. break;
  732. case 'z':
  733. // 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.
  734. fd.mModifier = kModifierSize_t;
  735. break;
  736. case 't':
  737. // 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.
  738. fd.mModifier = kModifierPtrdiff_t;
  739. break;
  740. case 'L':
  741. // Specifies that a following a, A, e, E, f, F, g, or G conversion specifier applies to an argument with type pointer to long double.
  742. fd.mModifier = kModifierLongDouble;
  743. break;
  744. case 'I': // We support Microsoft's extension sized fd specifiers.
  745. if(pFormatCurrent[1] == '8') // If the user specified %I8 ...
  746. {
  747. fd.mModifier = kModifierInt8;
  748. c = *++pFormatCurrent; // Account for the '8' part of I8. We'll account for the 'I' part below for all formats.
  749. }
  750. else if((pFormatCurrent[1] == '1') && (pFormatCurrent[2] == '6'))
  751. {
  752. fd.mModifier = kModifierInt16;
  753. c = *(pFormatCurrent += 2);
  754. }
  755. else if((pFormatCurrent[1] == '3') && (pFormatCurrent[2] == '2'))
  756. {
  757. fd.mModifier = kModifierInt32;
  758. c = *(pFormatCurrent += 2);
  759. }
  760. else if((pFormatCurrent[1] == '6') && (pFormatCurrent[2] == '4'))
  761. {
  762. fd.mModifier = kModifierInt64;
  763. c = *(pFormatCurrent += 2); // Account for the '64' part of I64. We'll account for the 'I' part below for all formats.
  764. }
  765. else if((pFormatCurrent[1] == '1') && (pFormatCurrent[2] == '2') && (pFormatCurrent[3] == '8'))
  766. {
  767. fd.mModifier = kModifierInt128;
  768. c = *(pFormatCurrent += 3);
  769. }
  770. else // Else the specified modifier was invalid.
  771. {
  772. fd.mnType = kFormatError;
  773. *pFormatData = fd;
  774. EA_FAIL_MSG("Scanf: Invalid %I modifier");
  775. return ++pFormatCurrent;
  776. }
  777. break;
  778. default:
  779. bModifierPresent = false;
  780. break;
  781. }
  782. if(bModifierPresent)
  783. c = *++pFormatCurrent;
  784. fd.mnType = (int)c;
  785. switch (c)
  786. {
  787. case 'b': // 'b' means binary. This is a convenient extension that we provide.
  788. case 'd':
  789. case 'u':
  790. case 'i':
  791. case 'x':
  792. case 'X':
  793. case 'o':
  794. if(fd.mModifier == kModifierLongDouble)
  795. {
  796. fd.mnType = kFormatError;
  797. EA_FAIL_MSG("Scanf: Invalid %b/%d/%u/%i/%x/%o modifier");
  798. }
  799. break;
  800. case 'c': // We accept %hc, %c, %lc, %I8c, %I16c, %I32c (regular, regular, wide, char8_t, char16_t, char32_t)
  801. case 'C': // We accept %hC, %C, %lC, %I8C, %I16C, %I32C (regular, wide, wide, char8_t, char16_t, char32_t)
  802. case 's': // We accept %hs, %s, %ls, %I8s, %I16s, %I32s (regular, regular, wide, char8_t, char16_t, char32_t)
  803. case 'S': // We accept %hS, %S, %lS, %I8s, %I16s, %I32s (regular, wide, wide, char8_t, char16_t, char32_t)
  804. {
  805. // Microsoft's library goes against the C and C++ standard: %s is
  806. // not interpreted to mean char8_t string but instead is interpreted
  807. // to be either char8_t or wchar_t depending on what the output
  808. // text fd is. This is non-standard but has the convenience
  809. // of allowing users to migrate between char8_t and wchar_t usage
  810. // more easily. So we allow EASCANF_MS_STYLE_S_FORMAT to control this.
  811. if(fd.mModifier == kModifierLong)
  812. fd.mModifier = kModifierWChar;
  813. else if(fd.mModifier == kModifierShort)
  814. fd.mModifier = kModifierChar;
  815. else if(fd.mModifier == kModifierNone)
  816. {
  817. #if EASCANF_MS_STYLE_S_FORMAT
  818. if((c == 's') || (c == 'c'))
  819. fd.mModifier = (sizeof(*pFormat) == sizeof(char8_t)) ? kModifierChar : kModifierWChar;
  820. else
  821. fd.mModifier = (sizeof(*pFormat) == sizeof(char8_t)) ? kModifierWChar : kModifierChar;
  822. #else
  823. if((c == 's') || (c == 'c'))
  824. fd.mModifier = kModifierChar;
  825. else
  826. fd.mModifier = kModifierWChar;
  827. #endif
  828. }
  829. else if((fd.mModifier < kModifierInt8) || (fd.mModifier > kModifierInt32)) // This expression assumes that Int8, Int16, Int32 are contiguous enum values.
  830. {
  831. fd.mnType = kFormatError;
  832. EA_FAIL_MSG("Scanf: Invalid %s/%c modifier");
  833. }
  834. if((c == 's') || (c == 'S'))
  835. {
  836. // We make %s be a special case of %[] whereby all non-space characters are accepted.
  837. // fd.mCharBitmap.SetAll();
  838. // fd.mCharBitmap.Clear(0x09); // Set tab (0x09),
  839. // fd.mCharBitmap.Clear(0x0a); // LF (0x0a),
  840. // fd.mCharBitmap.Clear(0x0b); // VT (0x0b),
  841. // fd.mCharBitmap.Clear(0x0c); // FF (0x0c),
  842. // fd.mCharBitmap.Clear(0x0d); // CR (0x0d),
  843. // fd.mCharBitmap.Clear(0x20); // space (0x20) to zero.
  844. // Pre-calculated version of above:
  845. fd.mCharBitmap.mBits[0] = 0xffffc1ff;
  846. fd.mCharBitmap.mBits[1] = 0xfffffffe;
  847. fd.mCharBitmap.mBits[2] = 0xffffffff;
  848. fd.mCharBitmap.mBits[3] = 0xffffffff;
  849. fd.mCharBitmap.mBits[4] = 0xffffffff;
  850. fd.mCharBitmap.mBits[5] = 0xffffffff;
  851. fd.mCharBitmap.mBits[6] = 0xffffffff;
  852. fd.mCharBitmap.mBits[7] = 0xffffffff;
  853. }
  854. break;
  855. }
  856. case 'e':
  857. case 'E':
  858. case 'f':
  859. case 'F':
  860. case 'g':
  861. case 'G':
  862. case 'a':
  863. case 'A':
  864. // The C99 Standard, section 7.24.2.2, specifies that %l and %L are the only modifiers that
  865. // affect floating point types. %f = float, %lf = double, %Lf = long double. It doesn't say
  866. // what the expected result is for using other modifiers with floating point types. We can
  867. // choose to ignore these types or yield an error. We give an error. The VC++ Standard
  868. // Library has inconsistent behaviour: it ignores the h in %hf, but in the case of %llf it
  869. // reinterprets the format to be %lli.
  870. if(fd.mModifier == kModifierLong) // if %lf ...
  871. fd.mModifier = kModifierDouble;
  872. else if((fd.mModifier != kModifierLongDouble) && // if not %Lf ...
  873. (fd.mModifier != kModifierNone))
  874. {
  875. fd.mnType = kFormatError;
  876. EA_FAIL_MSG("Scanf: Invalid %e/%f/%g/%a modifier");
  877. }
  878. break;
  879. case 'p':
  880. if(sizeof(void*) == 2)
  881. fd.mModifier = kModifierInt16;
  882. else if(sizeof(void*) == 4)
  883. fd.mModifier = kModifierInt32;
  884. else
  885. fd.mModifier = kModifierInt64;
  886. fd.mnType = 'x';
  887. break;
  888. case '[':
  889. {
  890. // The C99 standard states (7.19.6.2 p12):
  891. // Matches a non-empty sequence of bytes from a set of expected bytes (the scanset). The normal skip over
  892. // white-space characters shall be suppressed in this case. The application shall ensure that the
  893. // corresponding argument is a pointer to the initial byte of an array of char, signed char, or unsigned char
  894. // large enough to accept the sequence and a terminating null byte, which shall be added automatically.
  895. //
  896. // If an l (ell) qualifier is present, the input is a sequence of characters that begins in the initial shift state.
  897. // Each character in the sequence shall be converted to a wide character as if by a call to the mbrtowc() function,
  898. // with the conversion state described by an mbstate_t object initialized to zero before the first character is converted.
  899. // The application shall ensure that the corresponding argument is a pointer to an array of wchar_t large enough to
  900. // accept the sequence and the terminating null wide character, which shall be added automatically.
  901. //
  902. // The conversion specification includes all subsequent bytes in the fd string up to and including the matching
  903. // right square bracket (']'). The bytes between the square brackets (the scanlist) comprise the scanset,
  904. // unless the byte after the left square bracket is a circumflex ('^'), in which case the scanset contains all
  905. // bytes that do not appear in the scanlist between the circumflex and the right square bracket. If the conversion
  906. // specification begins with "[]" or "[^]", the right square bracket is included in the scanlist and the next right
  907. // square bracket is the matching right square bracket that ends the conversion specification; otherwise, the first
  908. // right square bracket is the one that ends the conversion specification. If a '-' is in the scanlist and is not
  909. // the first character, nor the second where the first character is a '^', nor the last character, the behavior is
  910. // implementation-defined.
  911. bool bInclusive = true;
  912. if(fd.mModifier == kModifierShort)
  913. fd.mModifier = kModifierChar;
  914. else if(fd.mModifier == kModifierLong)
  915. fd.mModifier = kModifierWChar;
  916. else if(fd.mModifier == kModifierNone)
  917. {
  918. #if EASCANF_MS_STYLE_S_FORMAT
  919. fd.mModifier = (sizeof(*pFormat) == sizeof(char8_t)) ? kModifierChar : kModifierWChar;
  920. #else
  921. fd.mModifier = (sizeof(*pFormat) == sizeof(char16_t)) ? kModifierWChar : kModifierChar; //TODO: This condition seems odd, needs review.
  922. #endif
  923. }
  924. else if((fd.mModifier < kModifierInt8) || (fd.mModifier > kModifierInt32)) // This expression assumes that Int8, Int16, Int32 are contiguous enum values.
  925. {
  926. fd.mnType = kFormatError;
  927. EA_FAIL_MSG("Scanf: Invalid %[ modifier");
  928. }
  929. c = *++pFormatCurrent;
  930. if(c == '^')
  931. {
  932. bInclusive = false;
  933. c = *++pFormatCurrent;
  934. }
  935. if(c == ']') // The C99 standard requires that if there is an excluded ']' char, then it is the first char after [ or [^.
  936. {
  937. fd.mCharBitmap.Set((CharT)']');
  938. c = *++pFormatCurrent;
  939. }
  940. // To do: We need to read UTF8 character sequences here instead of just ascii values.
  941. EA_ASSERT((sizeof(CharT) != sizeof(char8_t)) || ((uint8_t)(char8_t)c < 128)); // A c >= 128 refers to a UTF8 sequence, which we don't yet support.
  942. while(c && (c != ']')) // Walk through the characters until we encounter a closing ']' char. Use '-' char to indicate character ranges, as in "a-d"
  943. {
  944. fd.mCharBitmap.Set(c);
  945. if((pFormatCurrent[1] == '-') && pFormatCurrent[2] && (pFormatCurrent[2] != ']')) // If we have a character range specifier...
  946. {
  947. while(++c <= pFormatCurrent[2])
  948. fd.mCharBitmap.Set(c);
  949. pFormatCurrent += 2;
  950. }
  951. c = *++pFormatCurrent;
  952. }
  953. if(c) // At this point, c should be ']'
  954. {
  955. if(!bInclusive)
  956. fd.mCharBitmap.NegateAll();
  957. }
  958. else
  959. {
  960. fd.mnType = kFormatError;
  961. EA_FAIL_MSG("Scanf: Missing format ] char");
  962. }
  963. break;
  964. }
  965. case 'n':
  966. {
  967. // The C99 standard states (7.19.6.2 p12): No input is consumed. The application shall ensure
  968. // that the corresponding argument is a pointer to the integer into which shall be written the
  969. // number of bytes read from the input so far by this call to the fscanf() functions.
  970. // Execution of a %n conversion specification shall not increment the assignment nReadCount returned
  971. // at the completion of execution of the function. No argument shall be converted, but one shall
  972. // be consumed. If the conversion specification includes an assignment-suppressing character or
  973. // a field width, the behavior is undefined.
  974. break;
  975. }
  976. default:
  977. {
  978. fd.mnType = kFormatError;
  979. EA_FAIL_MSG("Scanf: Invalid format.");
  980. break;
  981. }
  982. }
  983. *pFormatData = fd;
  984. return ++pFormatCurrent;
  985. }
  986. uint64_t ReadUint64(ReadFunctionT pReadFunction, void* pContext,
  987. uint64_t nMaxValue, int nBase, int nMaxFieldWidth,
  988. int& nReadCount, int& bNegative, int& bIntegerOverflow)
  989. {
  990. ReadIntegerState state = kRISError;
  991. uint64_t nValue = 0;
  992. int nSpaceCount = 0;
  993. const int kRISDone = kRISError | kRISEnd;
  994. const int kRISSuccess = kRISAfterZero | kRISReadDigits | kRISEnd;
  995. nReadCount = 0;
  996. bNegative = 0;
  997. bIntegerOverflow = 0;
  998. if((nBase != 1) && (nBase <= 36) && (nMaxFieldWidth >= 1))
  999. {
  1000. uint64_t nMaxValueCheck = 0; // This is what we compare nValue to as we build nValue. It is always equal to nValue / nBase. We need to do this because otherwise we'd compare overflowed values.
  1001. int c;
  1002. state = kRISLeadingSpace;
  1003. c = pReadFunction(kReadActionRead, 0, pContext);
  1004. nReadCount++;
  1005. if(nBase)
  1006. nMaxValueCheck = (nMaxValue / nBase);
  1007. while((c != kReadError) && (nReadCount <= nMaxFieldWidth) && ((state & kRISDone) == 0))
  1008. {
  1009. switch ((int)state)
  1010. {
  1011. case kRISLeadingSpace:
  1012. {
  1013. if(Isspace((CharT)c))
  1014. {
  1015. c = pReadFunction(kReadActionRead, 0, pContext);
  1016. nSpaceCount++;
  1017. // Stay in this state and read another char.
  1018. }
  1019. else
  1020. {
  1021. if(c == '-')
  1022. {
  1023. c = pReadFunction(kReadActionRead, 0, pContext);
  1024. nReadCount++;
  1025. bNegative = 1;
  1026. }
  1027. else if(c == '+')
  1028. {
  1029. c = pReadFunction(kReadActionRead, 0, pContext);
  1030. nReadCount++;
  1031. }
  1032. state = kRISZeroTest;
  1033. }
  1034. break;
  1035. }
  1036. case kRISZeroTest:
  1037. {
  1038. if(((nBase == 0) || (nBase == 16)) && (c == '0')) // If nBase == 0, then we should expect hex (0x1234) or octal (01234)
  1039. {
  1040. c = pReadFunction(kReadActionRead, 0, pContext);
  1041. nReadCount++;
  1042. state = kRISAfterZero;
  1043. }
  1044. else
  1045. {
  1046. if(nBase == 0) // If the base hasn't been determined yet (e.g. by leading "0x"), then it must be 10.
  1047. nBase = 10;
  1048. if(nMaxValueCheck == 0) // If this hasn't been set yet...
  1049. nMaxValueCheck = (nMaxValue / nBase);
  1050. state = kRISReadFirstDigit;
  1051. }
  1052. break;
  1053. }
  1054. case kRISAfterZero:
  1055. {
  1056. if((c == 'x') || (c == 'X'))
  1057. {
  1058. c = pReadFunction(kReadActionRead, 0, pContext);
  1059. nReadCount++;
  1060. nBase = 16;
  1061. state = kRISReadFirstDigit;
  1062. }
  1063. else
  1064. {
  1065. if(nBase == 0)
  1066. nBase = 8;
  1067. state = kRISReadDigits;
  1068. }
  1069. if(nMaxValueCheck == 0) // If this hasn't been set yet...
  1070. nMaxValueCheck = (nMaxValue / nBase);
  1071. break;
  1072. }
  1073. case kRISReadFirstDigit:
  1074. case kRISReadDigits:
  1075. {
  1076. const int cDigit = (c - '0');
  1077. if((unsigned)cDigit < 10) // If c is compatible with base 2, 8, 10 ...
  1078. {
  1079. if(cDigit >= nBase)
  1080. {
  1081. if(state == kRISReadDigits)
  1082. state = kRISEnd;
  1083. else
  1084. state = kRISError;
  1085. break;
  1086. }
  1087. c = cDigit;
  1088. }
  1089. else //Else we may have a hex digit, but we only pay attention to it if it's compatible with nBase (e.g. base 16).
  1090. {
  1091. int cHex; // Actually it might be something other than hex if we are using a screwy base such as 18.
  1092. CharT cLower;
  1093. // If the base is > 10 and if c is a char that can represent a digit in the base...
  1094. if((nBase > 10) && ((cLower = Tolower((CharT)c)) >= 'a') && ((cHex = (10 + (int)cLower - 'a')) < nBase))
  1095. c = cHex;
  1096. else
  1097. {
  1098. if(state == kRISReadDigits)
  1099. state = kRISEnd;
  1100. else
  1101. state = kRISError;
  1102. break;
  1103. }
  1104. }
  1105. if(nValue > nMaxValueCheck)
  1106. bIntegerOverflow = 1;
  1107. nValue *= nBase;
  1108. EA_ASSERT(c >= 0);
  1109. if((unsigned)c > (nMaxValue - nValue))
  1110. bIntegerOverflow = 1;
  1111. nValue += c;
  1112. state = kRISReadDigits;
  1113. c = pReadFunction(kReadActionRead, 0, pContext);
  1114. nReadCount++;
  1115. break;
  1116. }
  1117. } // switch()
  1118. } // while()
  1119. // Return the final char back to the stream. It will typically be a 0 (nul terminator) char.
  1120. pReadFunction(kReadActionUnread, c, pContext);
  1121. } // if()
  1122. if(state & kRISSuccess)
  1123. nReadCount += nSpaceCount - 1; // -1 because we un-read the last char above.
  1124. else
  1125. {
  1126. nValue = 0;
  1127. nReadCount = 0;
  1128. }
  1129. return nValue;
  1130. }
  1131. double ReadDouble(ReadFunctionT pReadFunction, void* pContext,
  1132. int nMaxFieldWidth, int cDecimalPoint, int& nReadCount, int& bOverflow)
  1133. {
  1134. int c;
  1135. DoubleValue doubleValue; // The string representation of the value, to be converted to actual value.
  1136. double dValue = 0.0;
  1137. int nSpaceCount = 0;
  1138. int nSignCount = 0; // There's supposed to be just zero or one of these.
  1139. int nFieldCount = 0;
  1140. int nExponent = 0;
  1141. int nExponentAdd = 0;
  1142. bool bNegative = false;
  1143. bool bExponentNegative = false;
  1144. ReadDoubleState state = kRDSLeadingSpace;
  1145. const int kRDSDone = kRDSError | kRDSEnd;
  1146. const int kRDSSuccess = kRDSSignificandLeading | kRDSIntegerDigits |
  1147. kRDSFractionLeading | kRDSFractionDigits |
  1148. kRDSExponentLeading | kRDSExponentDigits |
  1149. kRDSEnd;
  1150. nReadCount = 0;
  1151. bOverflow = 0;
  1152. c = pReadFunction(kReadActionRead, 0, pContext);
  1153. nFieldCount++;
  1154. while((c != kReadError) && (nFieldCount <= nMaxFieldWidth) && !(state & kRDSDone))
  1155. {
  1156. switch((int)state)
  1157. {
  1158. case kRDSLeadingSpace:
  1159. {
  1160. if(Isspace((CharT)c))
  1161. {
  1162. c = pReadFunction(kReadActionRead, 0, pContext);
  1163. nSpaceCount++;
  1164. break;
  1165. }
  1166. switch(c)
  1167. {
  1168. case '-':
  1169. bNegative = true;
  1170. // Fall through
  1171. case '+':
  1172. c = pReadFunction(kReadActionRead, 0, pContext);
  1173. nFieldCount++;
  1174. nSignCount++;
  1175. break;
  1176. case 'i': // Start of an "INF" or "INFINITY" sequence.
  1177. case 'I':
  1178. c = pReadFunction(kReadActionRead, 0, pContext);
  1179. nFieldCount++;
  1180. state = kRDSInfinity;
  1181. break;
  1182. case 'n': // Start of an "NAN" or "NAN(...)" sequence.
  1183. case 'N':
  1184. c = pReadFunction(kReadActionRead, 0, pContext);
  1185. nFieldCount++;
  1186. state = kRDSNAN;
  1187. break;
  1188. default:
  1189. state = kRDSSignificandBegin;
  1190. break;
  1191. }
  1192. break;
  1193. }
  1194. case kRDSSignificandBegin:
  1195. {
  1196. if(c == cDecimalPoint) // If there is no significand but there is instead the fraction-starting '.' char...
  1197. {
  1198. c = pReadFunction(kReadActionRead, 0, pContext);
  1199. nFieldCount++;
  1200. state = kRDSFractionBegin;
  1201. }
  1202. else if(c == '0')
  1203. {
  1204. c = pReadFunction(kReadActionRead, 0, pContext);
  1205. nFieldCount++;
  1206. state = kRDSSignificandLeading; // We eat leading zeroes.
  1207. }
  1208. else if(Isdigit((CharT)c))
  1209. state = kRDSIntegerDigits;
  1210. else
  1211. state = kRDSError;
  1212. break;
  1213. }
  1214. case kRDSSignificandLeading:
  1215. {
  1216. if(c == '0')
  1217. {
  1218. c = pReadFunction(kReadActionRead, 0, pContext);
  1219. nFieldCount++;
  1220. }
  1221. else
  1222. state = kRDSIntegerDigits;
  1223. break;
  1224. }
  1225. case kRDSIntegerDigits:
  1226. {
  1227. if(Isdigit((CharT)c))
  1228. {
  1229. if(doubleValue.mSigLen < kMaxSignificandDigits) // If we have any more room...
  1230. doubleValue.mSigStr[doubleValue.mSigLen++] = (char8_t)c;
  1231. else
  1232. nExponentAdd++; // Lose significant digits but increase the exponent multiplier, so that the final result is close intended value, though chopped.
  1233. c = pReadFunction(kReadActionRead, 0, pContext);
  1234. nFieldCount++;
  1235. }
  1236. else
  1237. {
  1238. if(c == cDecimalPoint)
  1239. {
  1240. c = pReadFunction(kReadActionRead, 0, pContext);
  1241. nFieldCount++;
  1242. state = kRDSFractionDigits;
  1243. }
  1244. else
  1245. state = kRDSSignificandEnd;
  1246. }
  1247. break;
  1248. }
  1249. case kRDSFractionBegin:
  1250. {
  1251. if(Isdigit((CharT)c))
  1252. state = kRDSFractionDigits;
  1253. else
  1254. state = kRDSError;
  1255. break;
  1256. }
  1257. case kRDSFractionDigits:
  1258. {
  1259. if(Isdigit((CharT)c))
  1260. {
  1261. if(doubleValue.mSigLen < kMaxSignificandDigits) // If we have any more room...
  1262. {
  1263. nExponentAdd--; // Fractional digits reduce our multiplier.
  1264. if((c != '0') || doubleValue.mSigLen)
  1265. doubleValue.mSigStr[doubleValue.mSigLen++] = (char8_t)c;
  1266. } // Else lose the remaining fractional part.
  1267. c = pReadFunction(kReadActionRead, 0, pContext);
  1268. nFieldCount++;
  1269. }
  1270. else
  1271. state = kRDSSignificandEnd;
  1272. break;
  1273. }
  1274. case kRDSSignificandEnd:
  1275. {
  1276. if(Toupper((CharT)c) == 'E')
  1277. {
  1278. c = pReadFunction(kReadActionRead, 0, pContext);
  1279. nFieldCount++;
  1280. state = kRDSExponentBegin;
  1281. break;
  1282. }
  1283. state = kRDSEnd;
  1284. break;
  1285. }
  1286. case kRDSExponentBegin:
  1287. {
  1288. if(c == '+')
  1289. {
  1290. c = pReadFunction(kReadActionRead, 0, pContext);
  1291. nFieldCount++;
  1292. }
  1293. else if(c == '-')
  1294. {
  1295. c = pReadFunction(kReadActionRead, 0, pContext);
  1296. nFieldCount++;
  1297. bExponentNegative = 1;
  1298. }
  1299. state = kRDSExponentBeginDigits;
  1300. break;
  1301. }
  1302. case kRDSExponentBeginDigits:
  1303. {
  1304. if(c == '0')
  1305. {
  1306. c = pReadFunction(kReadActionRead, 0, pContext);
  1307. nFieldCount++;
  1308. state = kRDSExponentLeading;
  1309. }
  1310. else if(Isdigit((CharT)c))
  1311. state = kRDSExponentDigits;
  1312. else
  1313. state = kRDSError;
  1314. break;
  1315. }
  1316. case kRDSExponentLeading:
  1317. {
  1318. if(c == '0')
  1319. {
  1320. c = pReadFunction(kReadActionRead, 0, pContext);
  1321. nFieldCount++;
  1322. }
  1323. else
  1324. state = kRDSExponentDigits;
  1325. break;
  1326. }
  1327. case kRDSExponentDigits:
  1328. {
  1329. if(Isdigit((CharT)c))
  1330. {
  1331. nExponent = (nExponent * 10) + (c - '0');
  1332. if(nExponent > kMaxDoubleExponent)
  1333. bOverflow = 1;
  1334. c = pReadFunction(kReadActionRead, 0, pContext);
  1335. nFieldCount++;
  1336. }
  1337. else
  1338. state = kRDSEnd;
  1339. break;
  1340. }
  1341. case kRDSInfinity:
  1342. {
  1343. // The C99 Standard specifies that we accept "INF" or "INFINITY", ignoring case.
  1344. int i = 1; // We have already matched the first 'I' char.
  1345. while((i < 8) && ((int)Toupper((CharT)c) == (int)"INFINITY"[i]))
  1346. {
  1347. i++;
  1348. c = pReadFunction(kReadActionRead, 0, pContext);
  1349. nFieldCount++;
  1350. }
  1351. if((i == 3) || (i == 8))
  1352. {
  1353. if(bNegative)
  1354. dValue = -kFloat64Infinity;
  1355. else
  1356. dValue = kFloat64Infinity;
  1357. nReadCount = nSpaceCount + nSignCount + i;
  1358. return dValue; // Question: Do some FPUs refuse to accept infinity as-is?
  1359. }
  1360. else
  1361. state = kRDSError;
  1362. break;
  1363. }
  1364. case kRDSNAN:
  1365. {
  1366. // The C99 Standard specifies that we accept "NAN" or "NAN(n-char-sequence)", ignoring case. The n-char-sequence is implementation-defined but is a string specifying a particular NAN.
  1367. int i = 1; // We have already matched the first 'N' char.
  1368. int j = 0;
  1369. //CharT pNANString[24]; pNANString[0] = 0;
  1370. while((i < 4) && ((int)Toupper((CharT)c) == (int)"NAN("[i]))
  1371. {
  1372. c = pReadFunction(kReadActionRead, 0, pContext);
  1373. nFieldCount++;
  1374. i++;
  1375. }
  1376. if((i == 3) || (i == 4))
  1377. {
  1378. if(i == 4)
  1379. {
  1380. while((j < 32) && (Isdigit((CharT)c) || Isalpha((CharT)c)))
  1381. {
  1382. //pNANString[j] = (char16_t)c;
  1383. c = pReadFunction(kReadActionRead, 0, pContext);
  1384. nFieldCount++;
  1385. j++;
  1386. }
  1387. if(c != ')')
  1388. {
  1389. state = kRDSError;
  1390. break;
  1391. }
  1392. else
  1393. j++;
  1394. }
  1395. // We currently ignore pNANString. To consider: Support some explicit NAN types based on the content of pNANString.
  1396. //pNANString[j] = 0;
  1397. if(bNegative)
  1398. dValue = -kFloat64NAN;
  1399. else
  1400. dValue = kFloat64NAN;
  1401. nReadCount = nSpaceCount + nSignCount + i + j;
  1402. return dValue; // Question: Don't some FPUs refuse to accept NANs as-is?
  1403. }
  1404. else
  1405. state = kRDSError;
  1406. break;
  1407. }
  1408. } // switch()
  1409. } // while()
  1410. // Return the final char back to the stream. It will typically be a 0 (nul terminator) char.
  1411. pReadFunction(kReadActionUnread, c, pContext);
  1412. if(state & kRDSSuccess)
  1413. {
  1414. nFieldCount--;
  1415. nReadCount = nFieldCount + nSpaceCount;
  1416. }
  1417. else
  1418. {
  1419. nFieldCount = 0;
  1420. nReadCount = 0;
  1421. }
  1422. if(bExponentNegative)
  1423. nExponent = -nExponent;
  1424. // We've got a mSigStr/mExponent that is something like "123"/0 for the case of "123"
  1425. // We've got a mSigStr/mExponent that is something like "123456"/-3 for the case of "123.456"
  1426. // We remove trailing zeroes until we have at most just one trailing zero.
  1427. int i = doubleValue.mSigLen - 1;
  1428. while((i > 0) && (doubleValue.mSigStr[i] == '0'))
  1429. {
  1430. nExponentAdd++;
  1431. i--;
  1432. }
  1433. if(i >= 0)
  1434. doubleValue.mSigLen = (int16_t)(i + 1);
  1435. else
  1436. {
  1437. // In this case we have no significand or a significand of all zeroes.
  1438. // Thus we have zero with some exponent, and the result is always zero,
  1439. // even if we had some kind of apparent exponent overflow.
  1440. bOverflow = false;
  1441. return bNegative ? -0.0 : 0.0; // Usage of -0.0 requires that precise floating point be enabled under VC++. We ensure that above via EA_ENABLE_PRECISE_FP().
  1442. // Alternative processing:
  1443. // doubleValue.mSigLen = 1;
  1444. // doubleValue.mSigStr[0] = '0'; // Leave nExponent as it is, which is probably zero.
  1445. }
  1446. doubleValue.mExponent = (int16_t)(nExponent + nExponentAdd);
  1447. if((doubleValue.mExponent < kMinDoubleExponent) || (doubleValue.mExponent > kMaxDoubleExponent))
  1448. bOverflow = 1;
  1449. // Note that it's still possible to have overflow if the exponent is present and less than max.
  1450. if(bOverflow)
  1451. {
  1452. if(bExponentNegative) // If the value is very small, return zero.
  1453. return 0.0;
  1454. else
  1455. {
  1456. // We don't set errno here; instead we set it in the caller.
  1457. // errno = ERANGE; // C99 standard, section 7.20.1.3-10
  1458. if(bNegative) // If the value is a very large negative value...
  1459. return -EASTDC_HUGE_VAL; // The C99 Standard (7.20.1.3-10) specifies that we return HUGE_VAL in the case of overflow.
  1460. else // Else the value is a very large positive value.
  1461. return EASTDC_HUGE_VAL;
  1462. }
  1463. }
  1464. dValue = doubleValue.ToDouble();
  1465. if(dValue > DBL_MAX) // If the value is denormalized too big...
  1466. {
  1467. // We don't set errno here; instead we set it in the caller.
  1468. //errno = ERANGE; // C99 standard, section 7.20.1.3-10
  1469. bOverflow = 1;
  1470. dValue = EASTDC_HUGE_VAL;
  1471. }
  1472. else if((dValue != 0.0) && (dValue < DBL_MIN)) // If the value is denormalized too small...
  1473. {
  1474. // We don't set errno here; instead we set it in the caller.
  1475. //errno = ERANGE; // C99 standard, section 7.20.1.3-10
  1476. bOverflow = 1;
  1477. //dValue = 0.0; // "If the result underflows (7.12.1), the functions return a value whose magnitude is no greater than the smallest normalized positive number in the return type; whether errno acquires the value ERANGE is implementation-defined."
  1478. }
  1479. if(bNegative)
  1480. dValue = -dValue;
  1481. return dValue;
  1482. }
  1483. };
  1484. bool ReadFormatSpan8(FormatData& fd, int& c, ReadFunction8 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount)
  1485. {
  1486. while(fd.mnWidth-- && ((c = pReadFunction(kReadActionRead, 0, pContext)) != -1) && fd.mCharBitmap.Get((char8_t)c))
  1487. {
  1488. uint8_t c8 = (uint8_t)c; // It's easier to work with uint8_t instead of char8_t, which might be signed.
  1489. switch (stringTypeSize)
  1490. {
  1491. case 1:
  1492. *((uint8_t*)pArgumentCurrent) = c8;
  1493. ++pArgumentCurrent;
  1494. break;
  1495. case 2:
  1496. case 4:
  1497. {
  1498. if(c8 < 128)
  1499. {
  1500. if(stringTypeSize == 2)
  1501. *((char16_t*)pArgumentCurrent) = c8;
  1502. else
  1503. *((char32_t*)pArgumentCurrent) = c8;
  1504. }
  1505. else
  1506. {
  1507. // We need to convert from UTF8 to UCS here. However, this can be complicated because
  1508. // multiple UTF8 chars may correspond to a single UCS char. Luckily, the UTF8 format
  1509. // allows us to know how many chars are in a multi-byte sequence based on the char value.
  1510. char8_t buffer[7];
  1511. const size_t utf8Len = utf8lengthTable[c8];
  1512. char16_t c16[2];
  1513. char32_t c32[2];
  1514. int result;
  1515. buffer[0] = (char8_t)c8;
  1516. for(size_t i = 1; i < utf8Len; ++i)
  1517. {
  1518. c = pReadFunction(kReadActionRead, 0, pContext);
  1519. if(c < 0)
  1520. return false;
  1521. ++nReadCount;
  1522. buffer[i] = (char8_t)c;
  1523. }
  1524. if(stringTypeSize == 2)
  1525. result = Strlcpy(c16, buffer, 2, utf8Len);
  1526. else
  1527. result = Strlcpy(c32, buffer, 2, utf8Len);
  1528. if(result < 0) // If the UTF8 sequence was malformed...
  1529. return false;
  1530. if(stringTypeSize == 2)
  1531. *((char16_t*)pArgumentCurrent) = c16[0];
  1532. else
  1533. *((char32_t*)pArgumentCurrent) = c32[0];
  1534. }
  1535. pArgumentCurrent += stringTypeSize;
  1536. break;
  1537. }
  1538. }
  1539. ++nReadCount;
  1540. }
  1541. return true;
  1542. }
  1543. bool ReadFormatSpan16(FormatData& fd, int& c, ReadFunction16 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount)
  1544. {
  1545. while (fd.mnWidth-- && ((c = pReadFunction(kReadActionRead, 0, pContext)) != -1) && fd.mCharBitmap.Get((char16_t)c))
  1546. {
  1547. char16_t c16 = (char16_t)(unsigned)c;
  1548. switch (stringTypeSize)
  1549. {
  1550. case 1:
  1551. // We need to convert from UCS2 to UTF8 here. One UCS2 char may convert to
  1552. // as many as six UTF8 chars (though usually no more than three).
  1553. // This Strlcpy (16 to 8) can never fail.
  1554. pArgumentCurrent += Strlcpy((char8_t*)pArgumentCurrent, &c16, 7, 1);
  1555. break;
  1556. case 2:
  1557. *((char16_t*)pArgumentCurrent) = (char16_t)c16;
  1558. pArgumentCurrent += sizeof(char16_t);
  1559. break;
  1560. case 4:
  1561. *((char32_t*)pArgumentCurrent) = c16;
  1562. pArgumentCurrent += sizeof(char32_t);
  1563. break;
  1564. }
  1565. ++nReadCount;
  1566. }
  1567. return true;
  1568. }
  1569. bool ReadFormatSpan32(FormatData& fd, int& c, ReadFunction32 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount)
  1570. {
  1571. while (fd.mnWidth-- && ((c = pReadFunction(kReadActionRead, 0, pContext)) != -1) && fd.mCharBitmap.Get((char32_t)c))
  1572. {
  1573. char32_t c32 = (char32_t)(unsigned)c;
  1574. switch (stringTypeSize)
  1575. {
  1576. case 1:
  1577. // We need to convert from UCS4 to UTF8 here. One UCS4 char may convert to
  1578. // as many as six UTF8 chars (though usually no more than three).
  1579. // This Strlcpy (32 to 8) can never fail.
  1580. pArgumentCurrent += Strlcpy((char8_t*)pArgumentCurrent, &c32, 7, 1);
  1581. break;
  1582. case 2:
  1583. *((char16_t*)pArgumentCurrent) = (char16_t)c32;
  1584. pArgumentCurrent += sizeof(char16_t);
  1585. break;
  1586. case 4:
  1587. *((char32_t*)pArgumentCurrent) = c32;
  1588. pArgumentCurrent += sizeof(char32_t);
  1589. break;
  1590. }
  1591. ++nReadCount;
  1592. }
  1593. return true;
  1594. }
  1595. typedef bool(*ReadFormatSpanFunction8)(FormatData& fd, int& c, ReadFunction8 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount);
  1596. typedef bool(*ReadFormatSpanFunction16)(FormatData& fd, int& c, ReadFunction16 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount);
  1597. typedef bool(*ReadFormatSpanFunction32)(FormatData& fd, int& c, ReadFunction32 pReadFunction, void* pContext, int stringTypeSize, char*& pArgumentCurrent, int& nReadCount);
  1598. int VscanfCore(ReadFunction8 pReadFunction8, void* pContext, const char8_t* pFormat, va_list arguments)
  1599. {
  1600. VscanfUtil<ReadFunction8, ReadFormatSpanFunction8, char8_t> scanner;
  1601. return scanner.VscanfCore(pReadFunction8, ReadFormatSpan8, pContext, pFormat, arguments);
  1602. }
  1603. int VscanfCore(ReadFunction16 pReadFunction16, void* pContext, const char16_t* pFormat, va_list arguments)
  1604. {
  1605. VscanfUtil<ReadFunction16, ReadFormatSpanFunction16, char16_t> scanner;
  1606. return scanner.VscanfCore(pReadFunction16, ReadFormatSpan16, pContext, pFormat, arguments);
  1607. }
  1608. int VscanfCore(ReadFunction32 pReadFunction32, void* pContext, const char32_t* pFormat, va_list arguments)
  1609. {
  1610. VscanfUtil<ReadFunction32, ReadFormatSpanFunction32, char32_t> scanner;
  1611. return scanner.VscanfCore(pReadFunction32, ReadFormatSpan32, pContext, pFormat, arguments);
  1612. }
  1613. // Undo the floating point precision statement we made above with EA_ENABLE_PRECISE_FP.
  1614. EA_RESTORE_PRECISE_FP()
  1615. } // namespace ScanfLocal
  1616. } // namespace StdC
  1617. } // namespace EA
  1618. EA_RESTORE_VC_WARNING()