wprint.c 79 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. wprint.c
  5. Abstract:
  6. This module implements wide character print format support.
  7. Author:
  8. Evan Green 27-Aug-2013
  9. Environment:
  10. Any
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "rtlp.h"
  16. //
  17. // ---------------------------------------------------------------- Definitions
  18. //
  19. #define CONVERSION_CHARACTER L'%'
  20. #define POSITIONAL_ARGUMENT L'$'
  21. #define FIELD_IN_ARGUMENT L'*'
  22. #define THOUSANDS_GROUPING L'\''
  23. #define LEFT_JUSTIFIED L'-'
  24. #define SPACE_FOR_PLUS L' '
  25. #define PRINT_SIGN L'+'
  26. #define PRINT_RADIX_IDENTIFIER L'#'
  27. #define PRINT_LEADING_ZEROES L'0'
  28. #define PRECISION_SPECIFIED L'.'
  29. #define FORMAT_SHORT L'h'
  30. #define FORMAT_LONG L'l'
  31. #define FORMAT_INTMAX L'j'
  32. #define FORMAT_SIZE_T L'z'
  33. #define FORMAT_PTRDIFF_T L't'
  34. #define FORMAT_LONG_DOUBLE L'L'
  35. #define FORMAT_DOUBLE_HEX L'a'
  36. #define FORMAT_DOUBLE_HEX_CAPITAL L'A'
  37. #define FORMAT_FLOAT L'f'
  38. #define FORMAT_FLOAT_CAPITAL L'F'
  39. #define FORMAT_SCIENTIFIC L'e'
  40. #define FORMAT_SCIENTIFIC_CAPITAL L'E'
  41. #define FORMAT_DOUBLE L'g'
  42. #define FORMAT_DOUBLE_CAPITAL L'G'
  43. #define FORMAT_CHARACTER L'c'
  44. #define FORMAT_LONG_CHARACTER L'C'
  45. #define FORMAT_STRING L's'
  46. #define FORMAT_LONG_STRING L'S'
  47. #define FORMAT_BYTES_PRINTED L'n'
  48. #define FORMAT_POINTER L'p'
  49. #define FORMAT_NONE L'%'
  50. #define FORMAT_DECIMAL L'd'
  51. #define FORMAT_DECIMAL2 L'i'
  52. #define FORMAT_OCTAL L'o'
  53. #define FORMAT_UNSIGNED L'u'
  54. #define FORMAT_HEX L'x'
  55. #define FORMAT_HEX_CAPITAL L'X'
  56. #define FORMAT_LONGLONG_START L'I'
  57. //
  58. // ------------------------------------------------------ Data Type Definitions
  59. //
  60. //
  61. // ----------------------------------------------- Internal Function Prototypes
  62. //
  63. BOOL
  64. RtlpConvertFormatSpecifierWide (
  65. PPRINT_FORMAT_CONTEXT Context,
  66. PWSTR Format,
  67. PULONG Index,
  68. va_list *Arguments
  69. );
  70. ULONG
  71. RtlpPrintIntegerWide (
  72. PPRINT_FORMAT_CONTEXT Context,
  73. ULONGLONG Integer,
  74. PPRINT_FORMAT_PROPERTIES Properties
  75. );
  76. ULONG
  77. RtlpPrintDoubleWide (
  78. PPRINT_FORMAT_CONTEXT Context,
  79. double Value,
  80. PPRINT_FORMAT_PROPERTIES Properties
  81. );
  82. ULONG
  83. RtlpPrintHexDoubleWide (
  84. PPRINT_FORMAT_CONTEXT Context,
  85. double Value,
  86. PPRINT_FORMAT_PROPERTIES Properties
  87. );
  88. BOOL
  89. RtlpPrintStringWide (
  90. PPRINT_FORMAT_CONTEXT Context,
  91. PWSTR String,
  92. LONG FieldWidth,
  93. LONG Precision,
  94. BOOL LeftJustified,
  95. BOOL Character
  96. );
  97. BOOL
  98. RtlpPrintByteStringWide (
  99. PPRINT_FORMAT_CONTEXT Context,
  100. PSTR String,
  101. LONG FieldWidth,
  102. LONG Precision,
  103. BOOL LeftJustified,
  104. BOOL Character
  105. );
  106. BOOL
  107. RtlpFormatWriteCharacterWide (
  108. PPRINT_FORMAT_CONTEXT Context,
  109. WCHAR Character
  110. );
  111. ULONGLONG
  112. RtlpGetPositionalArgumentWide (
  113. PWSTR Format,
  114. ULONG ArgumentNumber,
  115. va_list *Arguments
  116. );
  117. ULONG
  118. RtlpGetPositionalArgumentSizeWide (
  119. PWSTR Format,
  120. ULONG ArgumentNumber
  121. );
  122. BOOL
  123. RtlpStringFormatWriteCharacterWide (
  124. WCHAR Character,
  125. PPRINT_FORMAT_CONTEXT Context
  126. );
  127. //
  128. // -------------------------------------------------------------------- Globals
  129. //
  130. //
  131. // ------------------------------------------------------------------ Functions
  132. //
  133. RTL_API
  134. ULONG
  135. RtlPrintToStringWide (
  136. PWSTR Destination,
  137. ULONG DestinationSize,
  138. CHARACTER_ENCODING Encoding,
  139. PWSTR Format,
  140. ...
  141. )
  142. /*++
  143. Routine Description:
  144. This routine prints a formatted wide string out to a buffer.
  145. Arguments:
  146. Destination - Supplies a pointer to the buffer where the formatted string
  147. will be placed.
  148. DestinationSize - Supplies the size of the destination buffer, in bytes.
  149. Encoding - Supplies the character encoding to use for any non-wide
  150. characters or strings.
  151. Format - Supplies the printf-style format string to print. The contents of
  152. this string determine the rest of the arguments passed.
  153. ... - Supplies any arguments needed to convert the Format string.
  154. Return Value:
  155. Returns the length of the final string (in characters) after all formatting
  156. has been completed. The length will be returned even if NULL is passed as
  157. the destination.
  158. --*/
  159. {
  160. va_list ArgumentList;
  161. ULONG Result;
  162. va_start(ArgumentList, Format);
  163. Result = RtlFormatStringWide(Destination,
  164. DestinationSize,
  165. Encoding,
  166. Format,
  167. ArgumentList);
  168. va_end(ArgumentList);
  169. return Result;
  170. }
  171. RTL_API
  172. ULONG
  173. RtlFormatStringWide (
  174. PWSTR Destination,
  175. ULONG DestinationSize,
  176. CHARACTER_ENCODING Encoding,
  177. PWSTR Format,
  178. va_list ArgumentList
  179. )
  180. /*++
  181. Routine Description:
  182. This routine converts a printf-style wide format string given the
  183. parameters.
  184. Arguments:
  185. Destination - Supplies a pointer to the buffer where the final string will
  186. be printed. It is assumed that this string is allocated and is big
  187. enough to hold the converted string. Pass NULL here to determine how big
  188. a buffer is necessary to hold the string. If the buffer is not big
  189. enough, it will be truncated but still NULL terminated.
  190. DestinationSize - Supplies the size of the destination buffer. If NULL was
  191. passed as the Destination argument, then this argument is ignored.
  192. Encoding - Supplies the character encoding to use for any non-wide
  193. characters or strings.
  194. Format - Supplies a pointer to the printf-style format string.
  195. ArgumentList - Supplies an initialized list of arguments to the format
  196. string.
  197. Return Value:
  198. Returns the length of the final string after all formatting has been
  199. completed, including the null terminator. The length will be returned even
  200. if NULL is passed as the destination.
  201. --*/
  202. {
  203. UINTN CharactersWritten;
  204. PRINT_FORMAT_CONTEXT Context;
  205. RtlZeroMemory(&Context, sizeof(PRINT_FORMAT_CONTEXT));
  206. Context.U.WriteWideCharacter = RtlpStringFormatWriteCharacterWide;
  207. Context.Context = Destination;
  208. if (DestinationSize != 0) {
  209. Context.Limit = DestinationSize - 1;
  210. }
  211. RtlInitializeMultibyteState(&(Context.State), Encoding);
  212. RtlFormatWide(&Context, Format, ArgumentList);
  213. CharactersWritten = Context.CharactersWritten;
  214. if (DestinationSize != 0) {
  215. if (Context.CharactersWritten > Context.Limit) {
  216. Context.CharactersWritten = Context.Limit;
  217. }
  218. Context.Limit = DestinationSize;
  219. }
  220. RtlpFormatWriteCharacterWide(&Context, WIDE_STRING_TERMINATOR);
  221. return CharactersWritten + 1;
  222. }
  223. RTL_API
  224. BOOL
  225. RtlFormatWide (
  226. PPRINT_FORMAT_CONTEXT Context,
  227. PWSTR Format,
  228. va_list ArgumentList
  229. )
  230. /*++
  231. Routine Description:
  232. This routine converts a printf-style wide format string given the
  233. parameters.
  234. Arguments:
  235. Context - Supplies a pointer to the initialized context structure.
  236. Format - Supplies a pointer to the printf-style format string.
  237. ArgumentList - Supplies an initialized list of arguments to the format
  238. string.
  239. Return Value:
  240. TRUE if all characters were written to the destination.
  241. FALSE if the destination or limit cut the conversion short.
  242. --*/
  243. {
  244. va_list ArgumentListCopy;
  245. ULONG Index;
  246. BOOL Result;
  247. ASSERT((Context != NULL) && (Context->U.WriteWideCharacter != NULL) &&
  248. (Context->CharactersWritten == 0) &&
  249. (RtlIsCharacterEncodingSupported(Context->State.Encoding) != FALSE));
  250. if (Format == NULL) {
  251. Format = L"(null)";
  252. }
  253. //
  254. // Copy each character to the destination, handling formats along the way.
  255. //
  256. va_copy(ArgumentListCopy, ArgumentList);
  257. Result = TRUE;
  258. Index = 0;
  259. while (Format[Index] != WIDE_STRING_TERMINATOR) {
  260. if (Format[Index] == CONVERSION_CHARACTER) {
  261. Result = RtlpConvertFormatSpecifierWide(Context,
  262. Format,
  263. &Index,
  264. &ArgumentListCopy);
  265. if (Result == FALSE) {
  266. goto FormatWideEnd;
  267. }
  268. } else {
  269. Result = RtlpFormatWriteCharacterWide(Context, Format[Index]);
  270. if (Result == FALSE) {
  271. goto FormatWideEnd;
  272. }
  273. Index += 1;
  274. }
  275. }
  276. FormatWideEnd:
  277. va_end(ArgumentListCopy);
  278. return Result;
  279. }
  280. //
  281. // --------------------------------------------------------- Internal Functions
  282. //
  283. BOOL
  284. RtlpConvertFormatSpecifierWide (
  285. PPRINT_FORMAT_CONTEXT Context,
  286. PWSTR Format,
  287. PULONG Index,
  288. va_list *Arguments
  289. )
  290. /*++
  291. Routine Description:
  292. This routine converts one printf-style wide format specifier to its wide
  293. string conversion.
  294. Arguments:
  295. Context - Supplies a pointer to the initialized context structure.
  296. Format - Supplies a pointer to the printf-style conversion specifier.
  297. Index - Supplies a pointer that upon input contains the index of the
  298. L'%' specifier to convert. On output, this will be advanced beyond the
  299. specifier.
  300. Arguments - Supplies a pointer to the variable list of arguments.
  301. Return Value:
  302. TRUE if all characters were written to the destination.
  303. FALSE if the string was truncated.
  304. --*/
  305. {
  306. CHAR ByteCharacterArgument;
  307. PSTR ByteStringArgument;
  308. WCHAR CharacterArgument;
  309. PWSTR CurrentFormat;
  310. DOUBLE_PARTS DoubleParts;
  311. LONGLONG Integer;
  312. ULONGLONG IntegerArgument;
  313. BOOL IsFloat;
  314. BOOL IsInteger;
  315. BOOL LongDoubleSpecified;
  316. BOOL LongSpecified;
  317. ULONG Position;
  318. PRINT_FORMAT_PROPERTIES Properties;
  319. ULONG RemainingSize;
  320. BOOL Result;
  321. WCHAR Specifier;
  322. KSTATUS Status;
  323. PWSTR StringArgument;
  324. CurrentFormat = Format + *Index;
  325. RtlZeroMemory(&Properties, sizeof(PRINT_FORMAT_PROPERTIES));
  326. IntegerArgument = 0;
  327. Properties.Precision = -1;
  328. //
  329. // Check for the format character.
  330. //
  331. if (*CurrentFormat != CONVERSION_CHARACTER) {
  332. Result = FALSE;
  333. goto ConvertFormatSpecifierWideEnd;
  334. }
  335. CurrentFormat += 1;
  336. Position = 0;
  337. //
  338. // If there's a non-zero digit, grab it. It could be the position or field
  339. // width.
  340. //
  341. if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
  342. RemainingSize = -1;
  343. Status = RtlStringScanIntegerWide(&CurrentFormat,
  344. &RemainingSize,
  345. 10,
  346. FALSE,
  347. &Integer);
  348. if (!KSUCCESS(Status)) {
  349. Integer = 0;
  350. }
  351. if (*CurrentFormat == POSITIONAL_ARGUMENT) {
  352. if (Integer < 0) {
  353. Result = FALSE;
  354. goto ConvertFormatSpecifierWideEnd;
  355. }
  356. Position = (ULONG)Integer;
  357. CurrentFormat += 1;
  358. } else {
  359. Properties.FieldWidth = (ULONG)Integer;
  360. }
  361. }
  362. //
  363. // Process any flags.
  364. //
  365. while (TRUE) {
  366. if (*CurrentFormat == THOUSANDS_GROUPING) {
  367. Properties.ThousandsGrouping = TRUE;
  368. } else if (*CurrentFormat == LEFT_JUSTIFIED) {
  369. Properties.LeftJustified = TRUE;
  370. } else if (*CurrentFormat == SPACE_FOR_PLUS) {
  371. Properties.SpaceForPlus = TRUE;
  372. } else if (*CurrentFormat == PRINT_SIGN) {
  373. Properties.AlwaysPrintSign = TRUE;
  374. } else if (*CurrentFormat == PRINT_RADIX_IDENTIFIER) {
  375. Properties.PrintRadix = TRUE;
  376. } else if (*CurrentFormat == PRINT_LEADING_ZEROES) {
  377. Properties.PrintLeadingZeroes = TRUE;
  378. } else {
  379. break;
  380. }
  381. CurrentFormat += 1;
  382. }
  383. //
  384. // If both print leading zeroes and left justify are specified, print
  385. // leading zeroes is ignored.
  386. //
  387. if (Properties.LeftJustified != FALSE) {
  388. Properties.PrintLeadingZeroes = FALSE;
  389. }
  390. if (Properties.AlwaysPrintSign != FALSE) {
  391. Properties.SpaceForPlus = FALSE;
  392. }
  393. //
  394. // Process a field width. It could have already been sucked in, be a
  395. // decimal, be a star, or be a star followed by a position and a dollar
  396. // sign.
  397. //
  398. if (*CurrentFormat == FIELD_IN_ARGUMENT) {
  399. CurrentFormat += 1;
  400. if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
  401. RemainingSize = -1;
  402. Status = RtlStringScanIntegerWide(&CurrentFormat,
  403. &RemainingSize,
  404. 10,
  405. FALSE,
  406. &Integer);
  407. if ((!KSUCCESS(Status)) || (Integer < 0)) {
  408. Result = FALSE;
  409. goto ConvertFormatSpecifierWideEnd;
  410. }
  411. if (*CurrentFormat != POSITIONAL_ARGUMENT) {
  412. Result = FALSE;
  413. goto ConvertFormatSpecifierWideEnd;
  414. }
  415. CurrentFormat += 1;
  416. Properties.FieldWidth = (INT)RtlpGetPositionalArgumentWide(
  417. Format,
  418. (ULONG)Integer,
  419. Arguments);
  420. } else {
  421. Properties.FieldWidth = va_arg(*Arguments, INT);
  422. }
  423. } else if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
  424. RemainingSize = -1;
  425. Status = RtlStringScanIntegerWide(&CurrentFormat,
  426. &RemainingSize,
  427. 10,
  428. FALSE,
  429. &Integer);
  430. if (!KSUCCESS(Status)) {
  431. Result = FALSE;
  432. goto ConvertFormatSpecifierWideEnd;
  433. }
  434. Properties.FieldWidth = (ULONG)Integer;
  435. }
  436. if (Properties.FieldWidth < 0) {
  437. Properties.LeftJustified = TRUE;
  438. Properties.FieldWidth = -Properties.FieldWidth;
  439. }
  440. //
  441. // If there's a dot, then the precision follows. Like the field width, it
  442. // could either be a decimal, a star, or a star plus a position and a
  443. // dollar sign.
  444. //
  445. if (*CurrentFormat == PRECISION_SPECIFIED) {
  446. CurrentFormat += 1;
  447. if (*CurrentFormat == FIELD_IN_ARGUMENT) {
  448. CurrentFormat += 1;
  449. if ((*CurrentFormat >= L'0') && (*CurrentFormat <= L'9')) {
  450. RemainingSize = -1;
  451. Status = RtlStringScanIntegerWide(&CurrentFormat,
  452. &RemainingSize,
  453. 10,
  454. FALSE,
  455. &Integer);
  456. if ((!KSUCCESS(Status)) || (Integer < 0)) {
  457. Result = FALSE;
  458. goto ConvertFormatSpecifierWideEnd;
  459. }
  460. if (*CurrentFormat != POSITIONAL_ARGUMENT) {
  461. Result = FALSE;
  462. goto ConvertFormatSpecifierWideEnd;
  463. }
  464. CurrentFormat += 1;
  465. Properties.Precision = (INT)RtlpGetPositionalArgumentWide(
  466. Format,
  467. (ULONG)Integer,
  468. Arguments);
  469. } else {
  470. Properties.Precision = va_arg(*Arguments, INT);
  471. }
  472. } else if ((*CurrentFormat >= L'0') && (*CurrentFormat <= L'9')) {
  473. RemainingSize = -1;
  474. Status = RtlStringScanIntegerWide(&CurrentFormat,
  475. &RemainingSize,
  476. 10,
  477. FALSE,
  478. &Integer);
  479. if (!KSUCCESS(Status)) {
  480. Result = FALSE;
  481. goto ConvertFormatSpecifierWideEnd;
  482. }
  483. if (Integer >= 0) {
  484. Properties.Precision = (ULONG)Integer;
  485. }
  486. }
  487. }
  488. //
  489. // A negative precision is taken as precision being omitted.
  490. //
  491. if (Properties.Precision < 0) {
  492. Properties.Precision = -1;
  493. }
  494. //
  495. // Look for the length modifiers: hh, h, l, ll, j, z, t, L, I64.
  496. //
  497. LongSpecified = FALSE;
  498. LongDoubleSpecified = FALSE;
  499. Properties.IntegerSize = sizeof(INT);
  500. if (*CurrentFormat == FORMAT_SHORT) {
  501. CurrentFormat += 1;
  502. Properties.IntegerSize = sizeof(SHORT);
  503. if (*CurrentFormat == FORMAT_SHORT) {
  504. CurrentFormat += 1;
  505. Properties.IntegerSize = sizeof(CHAR);
  506. }
  507. } else if (*CurrentFormat == FORMAT_LONG) {
  508. LongSpecified = TRUE;
  509. CurrentFormat += 1;
  510. Properties.IntegerSize = sizeof(LONG);
  511. if (*CurrentFormat == FORMAT_LONG) {
  512. LongSpecified = FALSE;
  513. CurrentFormat += 1;
  514. Properties.IntegerSize = sizeof(LONGLONG);
  515. }
  516. } else if (*CurrentFormat == FORMAT_INTMAX) {
  517. CurrentFormat += 1;
  518. Properties.IntegerSize = sizeof(intmax_t);
  519. } else if (*CurrentFormat == FORMAT_SIZE_T) {
  520. CurrentFormat += 1;
  521. Properties.IntegerSize = sizeof(size_t);
  522. } else if (*CurrentFormat == FORMAT_LONG_DOUBLE) {
  523. //
  524. // Printing of long doubles is not currently supported.
  525. //
  526. ASSERT(FALSE);
  527. LongDoubleSpecified = TRUE;
  528. CurrentFormat += 1;
  529. Properties.IntegerSize = sizeof(long double);
  530. } else if ((*CurrentFormat == FORMAT_LONGLONG_START) &&
  531. (*(CurrentFormat + 1) == '6') &&
  532. (*(CurrentFormat + 2) == '4')) {
  533. CurrentFormat += 3;
  534. Properties.IntegerSize = sizeof(LONGLONG);
  535. }
  536. //
  537. // Now, finally, get the conversion specifier
  538. //
  539. Specifier = *CurrentFormat;
  540. if (LongSpecified != FALSE) {
  541. if (Specifier == FORMAT_CHARACTER) {
  542. Specifier = FORMAT_LONG_CHARACTER;
  543. } else if (Specifier == FORMAT_STRING) {
  544. Specifier = FORMAT_LONG_STRING;
  545. }
  546. }
  547. IsInteger = FALSE;
  548. IsFloat = FALSE;
  549. Properties.Unsigned = TRUE;
  550. switch (Specifier) {
  551. case FORMAT_DECIMAL:
  552. case FORMAT_DECIMAL2:
  553. IsInteger = TRUE;
  554. Properties.Radix = 10;
  555. Properties.Unsigned = FALSE;
  556. break;
  557. case FORMAT_OCTAL:
  558. IsInteger = TRUE;
  559. Properties.Radix = 8;
  560. break;
  561. case FORMAT_UNSIGNED:
  562. IsInteger = TRUE;
  563. Properties.Radix = 10;
  564. break;
  565. case FORMAT_HEX:
  566. IsInteger = TRUE;
  567. Properties.Radix = 16;
  568. break;
  569. case FORMAT_POINTER:
  570. IsInteger = TRUE;
  571. Properties.IntegerSize = sizeof(UINTN);
  572. Properties.Radix = 16;
  573. Properties.PrintUpperCase = TRUE;
  574. break;
  575. case FORMAT_HEX_CAPITAL:
  576. IsInteger = TRUE;
  577. Properties.Radix = 16;
  578. Properties.PrintUpperCase = TRUE;
  579. break;
  580. case FORMAT_BYTES_PRINTED:
  581. IsInteger = TRUE;
  582. Properties.IntegerSize = sizeof(PVOID);
  583. break;
  584. case FORMAT_FLOAT:
  585. IsFloat = TRUE;
  586. Properties.FloatFormat = TRUE;
  587. break;
  588. case FORMAT_FLOAT_CAPITAL:
  589. IsFloat = TRUE;
  590. Properties.FloatFormat = TRUE;
  591. Properties.PrintUpperCase = TRUE;
  592. break;
  593. case FORMAT_DOUBLE:
  594. IsFloat = TRUE;
  595. Properties.SignificantDigitPrecision = TRUE;
  596. break;
  597. case FORMAT_DOUBLE_CAPITAL:
  598. IsFloat = TRUE;
  599. Properties.PrintUpperCase = TRUE;
  600. Properties.SignificantDigitPrecision = TRUE;
  601. break;
  602. case FORMAT_SCIENTIFIC:
  603. IsFloat = TRUE;
  604. Properties.ScientificFormat = TRUE;
  605. break;
  606. case FORMAT_SCIENTIFIC_CAPITAL:
  607. IsFloat = TRUE;
  608. Properties.ScientificFormat = TRUE;
  609. Properties.PrintUpperCase = TRUE;
  610. break;
  611. case FORMAT_DOUBLE_HEX:
  612. IsFloat = TRUE;
  613. Properties.ScientificFormat = TRUE;
  614. Properties.Radix = 16;
  615. break;
  616. case FORMAT_DOUBLE_HEX_CAPITAL:
  617. IsFloat = TRUE;
  618. Properties.ScientificFormat = TRUE;
  619. Properties.PrintUpperCase = TRUE;
  620. Properties.Radix = 16;
  621. break;
  622. case FORMAT_LONG_CHARACTER:
  623. if (Position != 0) {
  624. CharacterArgument = (WCHAR)RtlpGetPositionalArgumentWide(Format,
  625. Position,
  626. Arguments);
  627. } else {
  628. CharacterArgument = va_arg(*Arguments, int);
  629. }
  630. Result = RtlpPrintStringWide(Context,
  631. &CharacterArgument,
  632. Properties.FieldWidth,
  633. Properties.Precision,
  634. Properties.LeftJustified,
  635. TRUE);
  636. if (Result == FALSE) {
  637. goto ConvertFormatSpecifierWideEnd;
  638. }
  639. break;
  640. case FORMAT_CHARACTER:
  641. RtlResetMultibyteState(&(Context->State));
  642. if (Position != 0) {
  643. ByteCharacterArgument = (UCHAR)RtlpGetPositionalArgumentWide(
  644. Format,
  645. Position,
  646. Arguments);
  647. } else {
  648. ByteCharacterArgument = (CHAR)va_arg(*Arguments, INT);
  649. }
  650. Result = RtlpPrintByteStringWide(Context,
  651. &ByteCharacterArgument,
  652. Properties.FieldWidth,
  653. Properties.Precision,
  654. Properties.LeftJustified,
  655. TRUE);
  656. if (Result == FALSE) {
  657. goto ConvertFormatSpecifierWideEnd;
  658. }
  659. break;
  660. case FORMAT_LONG_STRING:
  661. if (Position != 0) {
  662. IntegerArgument = RtlpGetPositionalArgumentWide(Format,
  663. Position,
  664. Arguments);
  665. StringArgument = (PWSTR)(UINTN)IntegerArgument;
  666. } else {
  667. StringArgument = va_arg(*Arguments, PWSTR);
  668. }
  669. Result = RtlpPrintStringWide(Context,
  670. StringArgument,
  671. Properties.FieldWidth,
  672. Properties.Precision,
  673. Properties.LeftJustified,
  674. FALSE);
  675. if (Result == FALSE) {
  676. goto ConvertFormatSpecifierWideEnd;
  677. }
  678. break;
  679. case FORMAT_STRING:
  680. RtlResetMultibyteState(&(Context->State));
  681. if (Position != 0) {
  682. IntegerArgument = RtlpGetPositionalArgumentWide(Format,
  683. Position,
  684. Arguments);
  685. ByteStringArgument = (PSTR)(UINTN)IntegerArgument;
  686. } else {
  687. ByteStringArgument = va_arg(*Arguments, PSTR);
  688. }
  689. Result = RtlpPrintByteStringWide(Context,
  690. ByteStringArgument,
  691. Properties.FieldWidth,
  692. Properties.Precision,
  693. Properties.LeftJustified,
  694. FALSE);
  695. if (Result == FALSE) {
  696. goto ConvertFormatSpecifierWideEnd;
  697. }
  698. break;
  699. case FORMAT_NONE:
  700. IsInteger = FALSE;
  701. CharacterArgument = FORMAT_NONE;
  702. Result = RtlpPrintStringWide(Context,
  703. &CharacterArgument,
  704. Properties.FieldWidth,
  705. Properties.Precision,
  706. Properties.LeftJustified,
  707. TRUE);
  708. if (Result == FALSE) {
  709. goto ConvertFormatSpecifierWideEnd;
  710. }
  711. break;
  712. default:
  713. Result = FALSE;
  714. goto ConvertFormatSpecifierWideEnd;
  715. }
  716. CurrentFormat += 1;
  717. //
  718. // If it's an integer, get the argument and process it.
  719. //
  720. if (IsInteger != FALSE) {
  721. if (Position != 0) {
  722. IntegerArgument = RtlpGetPositionalArgumentWide(Format,
  723. Position,
  724. Arguments);
  725. switch (Properties.IntegerSize) {
  726. case 0:
  727. break;
  728. case sizeof(CHAR):
  729. IntegerArgument = (UCHAR)IntegerArgument;
  730. break;
  731. case sizeof(SHORT):
  732. IntegerArgument = (USHORT)IntegerArgument;
  733. break;
  734. case sizeof(LONG):
  735. IntegerArgument = (ULONG)IntegerArgument;
  736. break;
  737. case sizeof(LONGLONG):
  738. break;
  739. default:
  740. ASSERT(FALSE);
  741. Result = FALSE;
  742. goto ConvertFormatSpecifierWideEnd;
  743. }
  744. } else {
  745. switch (Properties.IntegerSize) {
  746. case 0:
  747. break;
  748. case sizeof(CHAR):
  749. IntegerArgument = (CHAR)va_arg(*Arguments, UINT);
  750. break;
  751. case sizeof(SHORT):
  752. IntegerArgument = (SHORT)va_arg(*Arguments, UINT);
  753. break;
  754. case sizeof(LONG):
  755. IntegerArgument = va_arg(*Arguments, ULONG);
  756. break;
  757. case sizeof(LONGLONG):
  758. IntegerArgument = va_arg(*Arguments, ULONGLONG);
  759. break;
  760. default:
  761. ASSERT(FALSE);
  762. Result = FALSE;
  763. goto ConvertFormatSpecifierWideEnd;
  764. }
  765. }
  766. if (Specifier == FORMAT_BYTES_PRINTED) {
  767. ASSERT(IntegerArgument != (UINTN)NULL);
  768. *((PINT)(UINTN)IntegerArgument) = Context->CharactersWritten;
  769. } else {
  770. Result = RtlpPrintIntegerWide(Context,
  771. IntegerArgument,
  772. &Properties);
  773. if (Result == FALSE) {
  774. goto ConvertFormatSpecifierWideEnd;
  775. }
  776. }
  777. //
  778. // If it's an float, get the argument and process it.
  779. //
  780. } else if (IsFloat != FALSE) {
  781. if (Position != 0) {
  782. //
  783. // TODO: Support long double.
  784. //
  785. DoubleParts.Ulonglong = RtlpGetPositionalArgumentWide(Format,
  786. Position,
  787. Arguments);
  788. } else {
  789. if (LongDoubleSpecified != FALSE) {
  790. DoubleParts.Double = (double)va_arg(*Arguments, long double);
  791. } else {
  792. DoubleParts.Double = va_arg(*Arguments, double);
  793. }
  794. }
  795. Result = RtlpPrintDoubleWide(Context, DoubleParts.Double, &Properties);
  796. if (Result == FALSE) {
  797. goto ConvertFormatSpecifierWideEnd;
  798. }
  799. }
  800. Result = TRUE;
  801. ConvertFormatSpecifierWideEnd:
  802. *Index += ((UINTN)CurrentFormat - (UINTN)(Format + *Index)) / sizeof(WCHAR);
  803. return Result;
  804. }
  805. ULONG
  806. RtlpPrintIntegerWide (
  807. PPRINT_FORMAT_CONTEXT Context,
  808. ULONGLONG Integer,
  809. PPRINT_FORMAT_PROPERTIES Properties
  810. )
  811. /*++
  812. Routine Description:
  813. This routine prints an integer to the destination given the style
  814. properties.
  815. Arguments:
  816. Context - Supplies a pointer to the initialized context structure.
  817. DestinationSize - Supplies the size of the destination buffer. If NULL was
  818. passed as the Destination argument, then this argument is ignored.
  819. Integer - Supplies the integer argument to convert to a string.
  820. Properties - Supplies the style characteristics to use when printing this
  821. integer.
  822. Return Value:
  823. Returns the length of the final string after the format conversion has
  824. completed. The length will be returned even if NULL is passed as the
  825. destination.
  826. --*/
  827. {
  828. WCHAR Character;
  829. ULONG FieldCount;
  830. ULONG FieldIndex;
  831. ULONG IntegerLength;
  832. WCHAR LocalBuffer[MAX_INTEGER_STRING_SIZE];
  833. ULONG LocalIndex;
  834. BOOL Negative;
  835. ULONGLONG NextInteger;
  836. LONG Precision;
  837. ULONG PrecisionCount;
  838. ULONG PrecisionIndex;
  839. WCHAR Prefix[4];
  840. ULONG PrefixIndex;
  841. ULONG PrefixSize;
  842. ULONGLONG Remainder;
  843. BOOL Result;
  844. IntegerLength = 0;
  845. Negative = FALSE;
  846. Precision = Properties->Precision;
  847. if (Precision == -1) {
  848. Precision = 1;
  849. }
  850. //
  851. // Get the integer. If it's signed, allow it to be extended to a signed
  852. // long long (as a signed char is probably just sitting as 0x0000...00FF).
  853. //
  854. if (Properties->Unsigned == FALSE) {
  855. switch (Properties->IntegerSize) {
  856. case sizeof(CHAR):
  857. Integer = (CHAR)Integer;
  858. break;
  859. case sizeof(SHORT):
  860. Integer = (SHORT)Integer;
  861. break;
  862. case sizeof(LONG):
  863. Integer = (LONG)Integer;
  864. break;
  865. default:
  866. break;
  867. }
  868. }
  869. //
  870. // If the integer is zero and a zero length precision was explicitly
  871. // asked for, print no characters.
  872. //
  873. if ((Integer == 0) && (Precision == 0)) {
  874. return TRUE;
  875. }
  876. //
  877. // If the integer is signed and negative, make it positive.
  878. //
  879. if ((Properties->Unsigned == FALSE) && ((LONGLONG)Integer < 0)) {
  880. Negative = TRUE;
  881. Integer = -Integer;
  882. }
  883. //
  884. // Convert the integer into a reversed string.
  885. //
  886. RtlZeroMemory(LocalBuffer, sizeof(LocalBuffer));
  887. do {
  888. //
  889. // Get the least significant digit.
  890. //
  891. NextInteger = RtlDivideUnsigned64(Integer,
  892. Properties->Radix,
  893. &Remainder);
  894. Character = (WCHAR)Remainder;
  895. if (Character > 9) {
  896. if (Properties->PrintUpperCase != FALSE) {
  897. Character = Character - 10 + L'A';
  898. } else {
  899. Character = Character - 10 + L'a';
  900. }
  901. } else {
  902. Character += L'0';
  903. }
  904. //
  905. // Write out the character.
  906. //
  907. LocalBuffer[IntegerLength] = Character;
  908. IntegerLength += 1;
  909. //
  910. // Use the divided integer to get the next least significant digit.
  911. //
  912. Integer = NextInteger;
  913. } while (Integer > 0);
  914. //
  915. // Reverse the integer string.
  916. //
  917. RtlStringReverseWide(LocalBuffer, LocalBuffer + IntegerLength);
  918. //
  919. // Figure out what kind of decorations can go on the integer. There could
  920. // be up to 1 character for the sign ('+', '-', or ' '), and up to two for
  921. // the radix ('0x').
  922. //
  923. PrefixSize = 0;
  924. if ((Properties->Unsigned == FALSE) && (Negative != FALSE)) {
  925. Prefix[PrefixSize] = L'-';
  926. PrefixSize += 1;
  927. } else if (Properties->AlwaysPrintSign != FALSE) {
  928. Prefix[PrefixSize] = L'+';
  929. PrefixSize += 1;
  930. } else if (Properties->SpaceForPlus != FALSE) {
  931. Prefix[PrefixSize] = L' ';
  932. PrefixSize += 1;
  933. }
  934. if (Properties->PrintRadix != FALSE) {
  935. if (Properties->Radix == 8) {
  936. if (LocalBuffer[0] != L'0') {
  937. Prefix[PrefixSize] = L'0';
  938. PrefixSize += 1;
  939. }
  940. } else if (Properties->Radix == 16) {
  941. Prefix[PrefixSize] = L'0';
  942. PrefixSize += 1;
  943. if (Properties->PrintUpperCase != 0) {
  944. Prefix[PrefixSize] = L'X';
  945. } else {
  946. Prefix[PrefixSize] = L'x';
  947. }
  948. PrefixSize += 1;
  949. }
  950. }
  951. //
  952. // Also remember if there are additional precision digits that will need to
  953. // go on the number.
  954. //
  955. PrecisionCount = 0;
  956. if (IntegerLength < Precision) {
  957. PrecisionCount = Precision - IntegerLength;
  958. }
  959. //
  960. // If the field width is bigger than the integer, there will need to be
  961. // some field spacing characters.
  962. //
  963. FieldCount = 0;
  964. if (IntegerLength + PrefixSize + PrecisionCount < Properties->FieldWidth) {
  965. FieldCount = Properties->FieldWidth -
  966. (IntegerLength + PrefixSize + PrecisionCount);
  967. }
  968. //
  969. // Everything's ready, start writing out the number to the destination. If
  970. // the field is not left justified or leading zeros are supposed to be
  971. // printed, start with the extra field width.
  972. //
  973. if ((Properties->LeftJustified == FALSE) ||
  974. (Properties->PrintLeadingZeroes != FALSE)) {
  975. //
  976. // If the field is leading zero padding, then the prefix needs to go
  977. // first, otherwise -0001 would look like 00-1.
  978. //
  979. Character = L' ';
  980. if (Properties->PrintLeadingZeroes != FALSE) {
  981. Character = L'0';
  982. for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
  983. Result = RtlpFormatWriteCharacterWide(Context,
  984. Prefix[PrefixIndex]);
  985. if (Result == FALSE) {
  986. return FALSE;
  987. }
  988. }
  989. //
  990. // Zero out the prefix size so it won't be written again.
  991. //
  992. PrefixSize = 0;
  993. }
  994. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  995. Result = RtlpFormatWriteCharacterWide(Context, Character);
  996. if (Result == FALSE) {
  997. return FALSE;
  998. }
  999. }
  1000. FieldCount = 0;
  1001. }
  1002. //
  1003. // Now write the prefix, followed by the precision leading zeroes,
  1004. // followed by the integer itself.
  1005. //
  1006. for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
  1007. Result = RtlpFormatWriteCharacterWide(Context, Prefix[PrefixIndex]);
  1008. if (Result == FALSE) {
  1009. return FALSE;
  1010. }
  1011. }
  1012. for (PrecisionIndex = 0;
  1013. PrecisionIndex < PrecisionCount;
  1014. PrecisionIndex += 1) {
  1015. Result = RtlpFormatWriteCharacterWide(Context, L'0');
  1016. if (Result == FALSE) {
  1017. return FALSE;
  1018. }
  1019. }
  1020. for (LocalIndex = 0; LocalIndex < IntegerLength; LocalIndex += 1) {
  1021. Result = RtlpFormatWriteCharacterWide(Context, LocalBuffer[LocalIndex]);
  1022. if (Result == FALSE) {
  1023. return FALSE;
  1024. }
  1025. }
  1026. //
  1027. // Finally, if there are still field characters to be spit out, print them.
  1028. // They must be spaces, as there can't be leading zeroes on the end.
  1029. //
  1030. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  1031. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  1032. if (Result == FALSE) {
  1033. return FALSE;
  1034. }
  1035. }
  1036. return TRUE;
  1037. }
  1038. ULONG
  1039. RtlpPrintDoubleWide (
  1040. PPRINT_FORMAT_CONTEXT Context,
  1041. double Value,
  1042. PPRINT_FORMAT_PROPERTIES Properties
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. This routine prints a double to the destination given the style
  1047. properties.
  1048. Arguments:
  1049. Context - Supplies a pointer to the initialized context structure.
  1050. DestinationSize - Supplies the size of the destination buffer. If NULL was
  1051. passed as the Destination argument, then this argument is ignored.
  1052. Value - Supplies a pointer to the value to convert to a string.
  1053. Properties - Supplies the style characteristics to use when printing this
  1054. integer.
  1055. Return Value:
  1056. Returns the length of the final string after the format conversion has
  1057. completed. The length will be returned even if NULL is passed as the
  1058. destination.
  1059. --*/
  1060. {
  1061. WCHAR Character;
  1062. LONG CurrentExponent;
  1063. WCHAR Digit;
  1064. LONG DigitCount;
  1065. LONG Exponent;
  1066. WCHAR ExponentCharacter;
  1067. ULONG ExponentIndex;
  1068. WCHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
  1069. ULONG FieldCount;
  1070. ULONG FieldIndex;
  1071. WCHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
  1072. ULONG LocalIndex;
  1073. BOOL Negative;
  1074. PWSTR NonNumberString;
  1075. ULONG NumberLength;
  1076. DOUBLE_PARTS Parts;
  1077. LONG Precision;
  1078. LONG PrecisionIndex;
  1079. WCHAR Prefix;
  1080. BOOL PrintExponent;
  1081. BOOL Result;
  1082. double RoundingAmount;
  1083. LONG SignificantDigits;
  1084. double TenPower;
  1085. NumberLength = 0;
  1086. Negative = FALSE;
  1087. Parts.Double = Value;
  1088. Precision = Properties->Precision;
  1089. if (Precision == -1) {
  1090. Precision = DEFAULT_FLOAT_PRECISION;
  1091. }
  1092. if ((Properties->SignificantDigitPrecision != FALSE) && (Precision == 0)) {
  1093. Precision = 1;
  1094. }
  1095. Prefix = 0;
  1096. //
  1097. // Handle NaN and the infinities.
  1098. //
  1099. if ((Parts.Ulong.High & (~DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) >=
  1100. NAN_HIGH_WORD) {
  1101. //
  1102. // NaN is the only value that doesn't equal itself.
  1103. //
  1104. if (Value != Value) {
  1105. if (Properties->PrintUpperCase != FALSE) {
  1106. NonNumberString = L"NAN";
  1107. } else {
  1108. NonNumberString = L"nan";
  1109. }
  1110. //
  1111. // Also handle positive and negative infinity.
  1112. //
  1113. } else {
  1114. if (Properties->PrintUpperCase != FALSE) {
  1115. NonNumberString = L"INF";
  1116. } else {
  1117. NonNumberString = L"inf";
  1118. }
  1119. if (Value < 0) {
  1120. Negative = TRUE;
  1121. }
  1122. }
  1123. //
  1124. // Create a string in the local buffer containing a sign (maybe) and
  1125. // the weird string.
  1126. //
  1127. LocalIndex = 0;
  1128. if (Negative != FALSE) {
  1129. LocalBuffer[LocalIndex] = L'-';
  1130. LocalIndex += 1;
  1131. } else if (Properties->AlwaysPrintSign != FALSE) {
  1132. LocalBuffer[LocalIndex] = L'+';
  1133. LocalIndex += 1;
  1134. } else if (Properties->SpaceForPlus != FALSE) {
  1135. LocalBuffer[LocalIndex] = L' ';
  1136. LocalIndex += 1;
  1137. }
  1138. RtlStringCopyWide(LocalBuffer + LocalIndex,
  1139. NonNumberString,
  1140. sizeof(LocalBuffer) - LocalIndex);
  1141. Result = RtlpPrintStringWide(Context,
  1142. LocalBuffer,
  1143. Properties->FieldWidth,
  1144. Properties->Precision,
  1145. Properties->LeftJustified,
  1146. FALSE);
  1147. return Result;
  1148. }
  1149. //
  1150. // Use a special routine for hex formats.
  1151. //
  1152. if (Properties->Radix == 16) {
  1153. return RtlpPrintHexDoubleWide(Context, Value, Properties);
  1154. }
  1155. //
  1156. // If the value is negative, make it positive.
  1157. //
  1158. if ((Parts.Ulong.High & (DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) != 0) {
  1159. Negative = TRUE;
  1160. Value = -Value;
  1161. }
  1162. //
  1163. // Get the base 10 exponent of the value to determine whether or not to
  1164. // print the exponent.
  1165. //
  1166. Exponent = RtlpGetDoubleBase10Exponent(Value, &TenPower);
  1167. RoundingAmount = 0.5;
  1168. //
  1169. // Figure out whether or not to print the exponent. If not explicitly
  1170. // specified, print it out if the exponent is less than -4 or greater than
  1171. // the precision.
  1172. //
  1173. PrintExponent = Properties->ScientificFormat;
  1174. if ((PrintExponent == FALSE) && (Properties->FloatFormat == FALSE)) {
  1175. if ((Exponent < SCIENTIFIC_NOTATION_AUTO_LOWER_LIMIT) ||
  1176. (Exponent >= Precision)) {
  1177. PrintExponent = TRUE;
  1178. }
  1179. }
  1180. DigitCount = 0;
  1181. if (Value != 0.0) {
  1182. //
  1183. // In scientific notation or with significant digit based precision,
  1184. // the rounding amount should be adjusted by the exponent.
  1185. //
  1186. if ((PrintExponent != FALSE) ||
  1187. (Properties->SignificantDigitPrecision != FALSE)) {
  1188. RoundingAmount /= TenPower;
  1189. //
  1190. // Scoot the rounding amount up by one because the loop below is
  1191. // going to go one too far because it's not taking into account
  1192. // the integral digit as a precision digit.
  1193. //
  1194. if (Properties->SignificantDigitPrecision != FALSE) {
  1195. RoundingAmount *= 10.0;
  1196. }
  1197. }
  1198. //
  1199. // Figure out the rounding amount to add for the proper precision.
  1200. //
  1201. for (PrecisionIndex = 0;
  1202. PrecisionIndex < Precision;
  1203. PrecisionIndex += 1) {
  1204. RoundingAmount *= 0.1;
  1205. }
  1206. Value += RoundingAmount;
  1207. //
  1208. // Normalize the value into the range 1 to 10 to take the rounding
  1209. // amount into account.
  1210. //
  1211. Value = Value * TenPower;
  1212. //
  1213. // The rounding could have bumped it up by a power of 10 (ie 0.99999999
  1214. // rounding to 1.000000, so adjust for that if needed.
  1215. //
  1216. if ((LONG)Value > 9) {
  1217. Value *= 0.1;
  1218. Exponent += 1;
  1219. }
  1220. //
  1221. // Convert this batch of numbers into characters, not worrying about
  1222. // the decimal point.
  1223. //
  1224. while ((Value != 0.0) && (DigitCount < MAX_DOUBLE_DIGITS_SIZE)) {
  1225. LocalBuffer[DigitCount] = (LONG)Value + L'0';
  1226. DigitCount += 1;
  1227. Value = (Value - (double)(LONG)Value) * 10.0;
  1228. }
  1229. //
  1230. // If significant digits matter, chop the digits down to the precision.
  1231. // This lops off any digits that were added solely by the rounding
  1232. // value.
  1233. //
  1234. if (Properties->SignificantDigitPrecision != FALSE) {
  1235. ASSERT(Precision > 0);
  1236. if (DigitCount > Precision) {
  1237. DigitCount = Precision;
  1238. }
  1239. }
  1240. //
  1241. // Remove any zero characters on the end.
  1242. //
  1243. while ((DigitCount > 1) && (LocalBuffer[DigitCount - 1] == L'0')) {
  1244. DigitCount -= 1;
  1245. }
  1246. }
  1247. //
  1248. // Figure out what kind of decorations can go on the integer. There could
  1249. // be up to 1 character for the sign ('+', '-', or ' ').
  1250. //
  1251. if (Negative != FALSE) {
  1252. Prefix = L'-';
  1253. } else if (Properties->AlwaysPrintSign != FALSE) {
  1254. Prefix = L'+';
  1255. } else if (Properties->SpaceForPlus != FALSE) {
  1256. Prefix = L' ';
  1257. }
  1258. //
  1259. // If printing with significant digit precision, then the number of
  1260. // significant digits is capped to the precision, and the precision
  1261. // is capped to the number of significant digits. So %.4g with 0.01 prints
  1262. // 0.01, and %.4g with 0.0123456 prints 0.1235.
  1263. //
  1264. SignificantDigits = DigitCount;
  1265. if (Properties->SignificantDigitPrecision != FALSE) {
  1266. if (SignificantDigits > Precision) {
  1267. SignificantDigits = Precision;
  1268. }
  1269. if (Precision > SignificantDigits) {
  1270. Precision = SignificantDigits;
  1271. //
  1272. // For a number like 100, there's only one significant digit, but
  1273. // a precision of 3 indicates that all three digits should be
  1274. // printed.
  1275. //
  1276. if ((PrintExponent == FALSE) && ((Exponent + 1) > Precision)) {
  1277. Precision = Exponent + 1;
  1278. }
  1279. if (Precision == 0) {
  1280. Precision = 1;
  1281. }
  1282. }
  1283. }
  1284. NumberLength = Precision;
  1285. //
  1286. // Figure out if a radix character is going to come out of here.
  1287. //
  1288. if (Properties->PrintRadix != FALSE) {
  1289. NumberLength += 1;
  1290. } else if (Properties->SignificantDigitPrecision != FALSE) {
  1291. if (PrintExponent != FALSE) {
  1292. if (Precision > 1) {
  1293. NumberLength += 1;
  1294. }
  1295. } else {
  1296. //
  1297. // A radix character is printed if the number of significant digits
  1298. // (capped to the precision) is greater than the number of integral
  1299. // digits. For example, 10.1 has 3 significant digits, only 2 of
  1300. // which are integral, so any precision greater than 2 causes the
  1301. // radix to be printed. Anything not in scientific notation with
  1302. // a negative exponent also has a radix.
  1303. //
  1304. if ((Exponent < 0) || ((Exponent + 1) - SignificantDigits < 0)) {
  1305. NumberLength += 1;
  1306. }
  1307. }
  1308. } else if (Precision != 0) {
  1309. NumberLength += 1;
  1310. }
  1311. //
  1312. // Figure out the total length of the number.
  1313. //
  1314. if (PrintExponent != FALSE) {
  1315. //
  1316. // Add extras for the exponent character, sign, and (at least) two
  1317. // exponent digits.
  1318. //
  1319. NumberLength += 4;
  1320. //
  1321. // If the precision only represents the fractional part, add one more
  1322. // for the integer portion.
  1323. //
  1324. if (Properties->SignificantDigitPrecision == FALSE) {
  1325. NumberLength += 1;
  1326. }
  1327. //
  1328. // Figure out how wide the exponent is. Negative exponents look like
  1329. // 1e-01.
  1330. //
  1331. if (Exponent < 0) {
  1332. if (Exponent <= -100) {
  1333. NumberLength += 1;
  1334. if (Exponent <= -1000) {
  1335. NumberLength += 1;
  1336. }
  1337. }
  1338. } else {
  1339. if (Exponent >= 100) {
  1340. NumberLength += 1;
  1341. if (Exponent >= 1000) {
  1342. NumberLength += 1;
  1343. }
  1344. }
  1345. }
  1346. //
  1347. // This is the regular float format where all the digits are printed.
  1348. //
  1349. } else {
  1350. //
  1351. // If the exponent is not negative, then the number of digits before
  1352. // a radix character is the exponent.
  1353. //
  1354. if (Exponent >= 0) {
  1355. if (Properties->SignificantDigitPrecision == FALSE) {
  1356. NumberLength += Exponent + 1;
  1357. }
  1358. //
  1359. // The exponent is negative, so add 1 for the zero.
  1360. //
  1361. } else {
  1362. NumberLength += 1;
  1363. //
  1364. // If the precision is the fractional part, that's all that needs
  1365. // to be done. If the precision is the number of significant digits,
  1366. // add the exponent to the precision so that the precision again
  1367. // just represents the fractional part.
  1368. //
  1369. if (Properties->SignificantDigitPrecision != FALSE) {
  1370. Precision += (-Exponent) - 1;
  1371. NumberLength += (-Exponent) - 1;
  1372. }
  1373. }
  1374. }
  1375. if (Prefix != 0) {
  1376. NumberLength += 1;
  1377. }
  1378. //
  1379. // If the field width is bigger than the integer, there will need to be
  1380. // some field spacing characters.
  1381. //
  1382. FieldCount = 0;
  1383. if (NumberLength < Properties->FieldWidth) {
  1384. FieldCount = Properties->FieldWidth - NumberLength;
  1385. }
  1386. //
  1387. // If the field is left justified or the extra field width is leading
  1388. // zeroes, print the prefix now.
  1389. //
  1390. if ((Properties->LeftJustified != FALSE) ||
  1391. (Properties->PrintLeadingZeroes != FALSE)) {
  1392. if (Prefix != 0) {
  1393. Result = RtlpFormatWriteCharacterWide(Context, Prefix);
  1394. if (Result == FALSE) {
  1395. return FALSE;
  1396. }
  1397. }
  1398. //
  1399. // Zero out the prefix so it won't be written again.
  1400. //
  1401. Prefix = 0;
  1402. }
  1403. //
  1404. // If the field is not right justified or leading zeros are supposed to be
  1405. // printed, spit out the extra field width.
  1406. //
  1407. if ((Properties->LeftJustified == FALSE) ||
  1408. (Properties->PrintLeadingZeroes != FALSE)) {
  1409. Character = L' ';
  1410. if (Properties->PrintLeadingZeroes != FALSE) {
  1411. Character = L'0';
  1412. }
  1413. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  1414. Result = RtlpFormatWriteCharacterWide(Context, Character);
  1415. if (Result == FALSE) {
  1416. return FALSE;
  1417. }
  1418. }
  1419. FieldCount = 0;
  1420. }
  1421. //
  1422. // In the case of a right justified number with no leading zeroes, the
  1423. // extra field width comes before the prefix. So print the prefix now if
  1424. // it has not yet been printed.
  1425. //
  1426. if (Prefix != 0) {
  1427. Result = RtlpFormatWriteCharacterWide(Context, Prefix);
  1428. if (Result == FALSE) {
  1429. return FALSE;
  1430. }
  1431. }
  1432. //
  1433. // Time to print the number itself.
  1434. //
  1435. LocalIndex = 0;
  1436. if (PrintExponent != FALSE) {
  1437. //
  1438. // Print the first character, always.
  1439. //
  1440. if (DigitCount == 0) {
  1441. Digit = L'0';
  1442. } else {
  1443. Digit = LocalBuffer[LocalIndex];
  1444. ASSERT(Digit != L'0');
  1445. LocalIndex += 1;
  1446. }
  1447. Result = RtlpFormatWriteCharacterWide(Context, Digit);
  1448. if (Result == FALSE) {
  1449. return FALSE;
  1450. }
  1451. //
  1452. // If the precision is the number of significant digits, then this
  1453. // guy counts as a significant digit.
  1454. //
  1455. if ((Properties->SignificantDigitPrecision != FALSE) &&
  1456. (Precision != 0)) {
  1457. Precision -= 1;
  1458. }
  1459. //
  1460. // Print the radix character.
  1461. //
  1462. if ((Precision != 0) || (Properties->PrintRadix != FALSE)) {
  1463. Result = RtlpFormatWriteCharacterWide(Context, L'.');
  1464. if (Result == FALSE) {
  1465. return FALSE;
  1466. }
  1467. }
  1468. //
  1469. // Print the rest of the desired precision.
  1470. //
  1471. for (PrecisionIndex = 0;
  1472. PrecisionIndex < Precision;
  1473. PrecisionIndex += 1) {
  1474. if (LocalIndex < DigitCount) {
  1475. Digit = LocalBuffer[LocalIndex];
  1476. LocalIndex += 1;
  1477. } else {
  1478. Digit = L'0';
  1479. }
  1480. Result = RtlpFormatWriteCharacterWide(Context, Digit);
  1481. if (Result == FALSE) {
  1482. return FALSE;
  1483. }
  1484. }
  1485. //
  1486. // Determine the exponent character.
  1487. //
  1488. ExponentCharacter = L'e';
  1489. if (Properties->PrintUpperCase != FALSE) {
  1490. ExponentCharacter = L'E';
  1491. }
  1492. //
  1493. // Print the exponent.
  1494. //
  1495. RtlPrintToStringWide(ExponentString,
  1496. MAX_DOUBLE_EXPONENT_SIZE,
  1497. Context->State.Encoding,
  1498. L"%c%+0.2d",
  1499. ExponentCharacter,
  1500. Exponent);
  1501. for (ExponentIndex = 0;
  1502. ExponentIndex < MAX_DOUBLE_EXPONENT_SIZE;
  1503. ExponentIndex += 1) {
  1504. if (ExponentString[ExponentIndex] == '\0') {
  1505. break;
  1506. }
  1507. Result = RtlpFormatWriteCharacterWide(
  1508. Context,
  1509. ExponentString[ExponentIndex]);
  1510. if (Result == FALSE) {
  1511. return FALSE;
  1512. }
  1513. }
  1514. //
  1515. // This is being printed in non-scientific notation. Could be a lot of
  1516. // zeros here.
  1517. //
  1518. } else {
  1519. if (Exponent >= 0) {
  1520. CurrentExponent = Exponent;
  1521. //
  1522. // Print the integral portion.
  1523. //
  1524. while (CurrentExponent >= 0) {
  1525. if (LocalIndex < DigitCount) {
  1526. Digit = LocalBuffer[LocalIndex];
  1527. LocalIndex += 1;
  1528. } else {
  1529. Digit = L'0';
  1530. }
  1531. Result = RtlpFormatWriteCharacterWide(Context, Digit);
  1532. if (Result == FALSE) {
  1533. return FALSE;
  1534. }
  1535. CurrentExponent -= 1;
  1536. //
  1537. // Count this as a precision digit if the precision is the
  1538. // number of significant digits.
  1539. //
  1540. if ((Properties->SignificantDigitPrecision != FALSE) &&
  1541. (Precision != 0)) {
  1542. Precision -= 1;
  1543. }
  1544. }
  1545. //
  1546. // Print the integer part, which is 0.
  1547. //
  1548. } else {
  1549. Result = RtlpFormatWriteCharacterWide(Context, L'0');
  1550. if (Result == FALSE) {
  1551. return FALSE;
  1552. }
  1553. CurrentExponent = -1;
  1554. }
  1555. //
  1556. // Print the radix character.
  1557. //
  1558. if ((Precision != 0) || (Properties->PrintRadix != FALSE)) {
  1559. Result = RtlpFormatWriteCharacterWide(Context, L'.');
  1560. if (Result == FALSE) {
  1561. return FALSE;
  1562. }
  1563. }
  1564. //
  1565. // Print as many digits of precision as are desired. If the precision
  1566. // is significant digits and the exponent is way negative, the
  1567. // precision variable should have already been adjusted above.
  1568. //
  1569. for (PrecisionIndex = 0;
  1570. PrecisionIndex < Precision;
  1571. PrecisionIndex += 1) {
  1572. //
  1573. // If the current exponent has not yet met up with the exponent
  1574. // of the digits, it's a leading zero (something like
  1575. // 0.00000000000000000000000000012345.
  1576. //
  1577. if (CurrentExponent > Exponent) {
  1578. Digit = L'0';
  1579. } else if (LocalIndex < DigitCount) {
  1580. Digit = LocalBuffer[LocalIndex];
  1581. LocalIndex += 1;
  1582. } else {
  1583. Digit = L'0';
  1584. }
  1585. Result = RtlpFormatWriteCharacterWide(Context, Digit);
  1586. if (Result == FALSE) {
  1587. return FALSE;
  1588. }
  1589. CurrentExponent -= 1;
  1590. }
  1591. }
  1592. //
  1593. // Finally, if there are still field characters to be spit out, print them.
  1594. // They must be spaces, as there can't be leading zeroes on the end.
  1595. //
  1596. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  1597. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  1598. if (Result == FALSE) {
  1599. return FALSE;
  1600. }
  1601. }
  1602. return TRUE;
  1603. }
  1604. ULONG
  1605. RtlpPrintHexDoubleWide (
  1606. PPRINT_FORMAT_CONTEXT Context,
  1607. double Value,
  1608. PPRINT_FORMAT_PROPERTIES Properties
  1609. )
  1610. /*++
  1611. Routine Description:
  1612. This routine prints a double to the destination in hex given the style
  1613. properties.
  1614. Arguments:
  1615. Context - Supplies a pointer to the initialized context structure.
  1616. DestinationSize - Supplies the size of the destination buffer. If NULL was
  1617. passed as the Destination argument, then this argument is ignored.
  1618. Value - Supplies a pointer to the value to convert to a string.
  1619. Properties - Supplies the style characteristics to use when printing this
  1620. integer.
  1621. Return Value:
  1622. Returns the length of the final string after the format conversion has
  1623. completed. The length will be returned even if NULL is passed as the
  1624. destination.
  1625. --*/
  1626. {
  1627. LONG AbsoluteExponent;
  1628. WCHAR Character;
  1629. WCHAR Digit;
  1630. LONG Exponent;
  1631. WCHAR ExponentCharacter;
  1632. WCHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
  1633. ULONG FieldCount;
  1634. ULONG FieldIndex;
  1635. ULONGLONG HalfWay;
  1636. WCHAR IntegerPortion;
  1637. WCHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
  1638. ULONG LocalIndex;
  1639. BOOL Negative;
  1640. ULONG NumberLength;
  1641. DOUBLE_PARTS Parts;
  1642. LONG Precision;
  1643. ULONG PrecisionIndex;
  1644. WCHAR Prefix[4];
  1645. ULONG PrefixIndex;
  1646. ULONG PrefixSize;
  1647. BOOL Result;
  1648. ULONGLONG RoundingValue;
  1649. ULONGLONG Significand;
  1650. Negative = FALSE;
  1651. Precision = Properties->Precision;
  1652. Parts.Double = Value;
  1653. //
  1654. // If the integer is negative, make it positive.
  1655. //
  1656. if ((Parts.Ulong.High & (DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) != 0) {
  1657. Negative = TRUE;
  1658. Parts.Double = -Parts.Double;
  1659. }
  1660. Exponent = (Parts.Ulong.High &
  1661. (DOUBLE_EXPONENT_MASK >> DOUBLE_HIGH_WORD_SHIFT)) >>
  1662. (DOUBLE_EXPONENT_SHIFT - DOUBLE_HIGH_WORD_SHIFT);
  1663. Exponent -= DOUBLE_EXPONENT_BIAS;
  1664. AbsoluteExponent = Exponent;
  1665. if (AbsoluteExponent < 0) {
  1666. AbsoluteExponent = -AbsoluteExponent;
  1667. }
  1668. if (Value == 0.0) {
  1669. Exponent = 0;
  1670. AbsoluteExponent = 0;
  1671. Significand = 0;
  1672. IntegerPortion = L'0';
  1673. if (Precision == -1) {
  1674. Precision = 0;
  1675. }
  1676. for (LocalIndex = 0;
  1677. LocalIndex < DOUBLE_SIGNIFICAND_HEX_DIGITS;
  1678. LocalIndex += 1) {
  1679. LocalBuffer[LocalIndex] = L'0';
  1680. }
  1681. } else {
  1682. Significand = Parts.Ulong.Low |
  1683. ((ULONGLONG)(Parts.Ulong.High & DOUBLE_HIGH_VALUE_MASK) <<
  1684. (sizeof(ULONG) * BITS_PER_BYTE));
  1685. //
  1686. // If there's a precision, add a half (8 of 16) to the digit beyond the
  1687. // precision.
  1688. //
  1689. IntegerPortion = L'1';
  1690. if (Precision != -1) {
  1691. HalfWay = 1ULL << (DOUBLE_EXPONENT_SHIFT - 1);
  1692. RoundingValue = HalfWay;
  1693. if (4 * Precision > (sizeof(ULONGLONG) * BITS_PER_BYTE)) {
  1694. RoundingValue = 0;
  1695. } else {
  1696. RoundingValue = RoundingValue >> (4 * Precision);
  1697. }
  1698. Significand += RoundingValue;
  1699. if (Significand >= (1ULL << DOUBLE_EXPONENT_SHIFT)) {
  1700. Significand -= (1ULL << DOUBLE_EXPONENT_SHIFT);
  1701. IntegerPortion += 1;
  1702. }
  1703. }
  1704. //
  1705. // Convert the significand into a hex string.
  1706. //
  1707. ASSERT(MAX_DOUBLE_DIGITS_SIZE >= DOUBLE_SIGNIFICAND_HEX_DIGITS);
  1708. for (LocalIndex = 0;
  1709. LocalIndex < DOUBLE_SIGNIFICAND_HEX_DIGITS;
  1710. LocalIndex += 1) {
  1711. Digit = (Significand >> (LocalIndex * 4)) & 0xF;
  1712. if (Digit < 10) {
  1713. Character = Digit + L'0';
  1714. } else if (Properties->PrintUpperCase != FALSE) {
  1715. Character = Digit + L'A' - 10;
  1716. } else {
  1717. Character = Digit + L'a' - 10;
  1718. }
  1719. LocalBuffer[DOUBLE_SIGNIFICAND_HEX_DIGITS - LocalIndex - 1] =
  1720. Character;
  1721. }
  1722. //
  1723. // Figure out how many significant digits there are if there is no
  1724. // precision.
  1725. //
  1726. if (Precision == -1) {
  1727. Precision = DOUBLE_SIGNIFICAND_HEX_DIGITS;
  1728. while ((Precision - 1 >= 0) &&
  1729. (LocalBuffer[Precision - 1] == L'0')) {
  1730. Precision -= 1;
  1731. }
  1732. }
  1733. }
  1734. //
  1735. // Figure out what kind of decorations can go on the integer. There could
  1736. // be up to 1 character for the sign ('+', '-', or ' '), and up to two for
  1737. // the radix ('0x').
  1738. //
  1739. PrefixSize = 0;
  1740. if (Negative != FALSE) {
  1741. Prefix[PrefixSize] = L'-';
  1742. PrefixSize += 1;
  1743. } else if (Properties->AlwaysPrintSign != FALSE) {
  1744. Prefix[PrefixSize] = L'+';
  1745. PrefixSize += 1;
  1746. } else if (Properties->SpaceForPlus != FALSE) {
  1747. Prefix[PrefixSize] = L' ';
  1748. PrefixSize += 1;
  1749. }
  1750. Prefix[PrefixSize] = L'0';
  1751. PrefixSize += 1;
  1752. if (Properties->PrintUpperCase != 0) {
  1753. Prefix[PrefixSize] = L'X';
  1754. } else {
  1755. Prefix[PrefixSize] = L'x';
  1756. }
  1757. PrefixSize += 1;
  1758. //
  1759. // Figure out the size of the number, which is the integer portion plus
  1760. // the precision, plus one more for a radix character if there was a
  1761. // precision.
  1762. //
  1763. NumberLength = 1 + Precision;
  1764. if ((Properties->PrintRadix != FALSE) || (Precision != 0)) {
  1765. NumberLength += 1;
  1766. }
  1767. //
  1768. // Don't forget about the exponent (the 'p', a sign, and at least one
  1769. // digit).
  1770. //
  1771. NumberLength += 3;
  1772. if (AbsoluteExponent > 10) {
  1773. NumberLength += 1;
  1774. if (AbsoluteExponent > 100) {
  1775. NumberLength += 1;
  1776. if (AbsoluteExponent > 1000) {
  1777. NumberLength += 1;
  1778. }
  1779. }
  1780. }
  1781. ExponentCharacter = L'p';
  1782. if (Properties->PrintUpperCase != FALSE) {
  1783. ExponentCharacter = L'P';
  1784. }
  1785. RtlPrintToStringWide(ExponentString,
  1786. sizeof(ExponentString),
  1787. Context->State.Encoding,
  1788. L"%c%+d",
  1789. ExponentCharacter,
  1790. Exponent);
  1791. //
  1792. // If the field width is bigger than the integer, there will need to be
  1793. // some field spacing characters.
  1794. //
  1795. FieldCount = 0;
  1796. if (NumberLength + PrefixSize < Properties->FieldWidth) {
  1797. FieldCount = Properties->FieldWidth - (NumberLength + PrefixSize);
  1798. }
  1799. //
  1800. // Everything's ready, start writing out the number to the destination. If
  1801. // the field is not left justified or leading zeros are supposed to be
  1802. // printed, start with the extra field width.
  1803. //
  1804. if ((Properties->LeftJustified == FALSE) ||
  1805. (Properties->PrintLeadingZeroes != FALSE)) {
  1806. //
  1807. // If the field is leading zero padding, then the prefix needs to go
  1808. // first, otherwise -0001 would look like 00-1.
  1809. //
  1810. Character = L' ';
  1811. if (Properties->PrintLeadingZeroes != FALSE) {
  1812. Character = L'0';
  1813. for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
  1814. Result = RtlpFormatWriteCharacterWide(Context,
  1815. Prefix[PrefixIndex]);
  1816. if (Result == FALSE) {
  1817. return FALSE;
  1818. }
  1819. }
  1820. //
  1821. // Zero out the prefix size so it won't be written again.
  1822. //
  1823. PrefixSize = 0;
  1824. }
  1825. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  1826. Result = RtlpFormatWriteCharacterWide(Context, Character);
  1827. if (Result == FALSE) {
  1828. return FALSE;
  1829. }
  1830. }
  1831. FieldCount = 0;
  1832. }
  1833. //
  1834. // Now write the prefix, followed by the precision leading zeroes,
  1835. // followed by the integer itself.
  1836. //
  1837. for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
  1838. Result = RtlpFormatWriteCharacterWide(Context, Prefix[PrefixIndex]);
  1839. if (Result == FALSE) {
  1840. return FALSE;
  1841. }
  1842. }
  1843. //
  1844. // Print the integer portion.
  1845. //
  1846. Result = RtlpFormatWriteCharacterWide(Context, IntegerPortion);
  1847. if (Result == FALSE) {
  1848. return FALSE;
  1849. }
  1850. //
  1851. // Print a radix if needed.
  1852. //
  1853. if ((Properties->PrintRadix != FALSE) || (Precision != 0)) {
  1854. Result = RtlpFormatWriteCharacterWide(Context, L'.');
  1855. if (Result == FALSE) {
  1856. return FALSE;
  1857. }
  1858. }
  1859. //
  1860. // Print the precision digits.
  1861. //
  1862. for (PrecisionIndex = 0; PrecisionIndex < Precision; PrecisionIndex += 1) {
  1863. if (PrecisionIndex >= DOUBLE_SIGNIFICAND_HEX_DIGITS) {
  1864. Digit = L'0';
  1865. } else {
  1866. Digit = LocalBuffer[PrecisionIndex];
  1867. }
  1868. Result = RtlpFormatWriteCharacterWide(Context, Digit);
  1869. if (Result == FALSE) {
  1870. return FALSE;
  1871. }
  1872. }
  1873. //
  1874. // Print the exponent.
  1875. //
  1876. RtlpPrintStringWide(Context, ExponentString, 0, -1, FALSE, FALSE);
  1877. //
  1878. // Finally, if there are still field characters to be spit out, print them.
  1879. // They must be spaces, as there can't be leading zeroes on the end.
  1880. //
  1881. for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
  1882. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  1883. if (Result == FALSE) {
  1884. return FALSE;
  1885. }
  1886. }
  1887. return TRUE;
  1888. }
  1889. BOOL
  1890. RtlpPrintStringWide (
  1891. PPRINT_FORMAT_CONTEXT Context,
  1892. PWSTR String,
  1893. LONG FieldWidth,
  1894. LONG Precision,
  1895. BOOL LeftJustified,
  1896. BOOL Character
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. This routine prints a string destination buffer given the style properties.
  1901. Arguments:
  1902. Context - Supplies a pointer to the initialized context structure.
  1903. String - Supplies a pointer to the string to print.
  1904. FieldWidth - Supplies the width of the string or character field. If the
  1905. argument doesn't fill up this space, it will be padded with spaces.
  1906. Precision - Supplies the precision of the string (the maximum number of
  1907. characters to print). Supply -1 to print the whole string.
  1908. LeftJustified - Supplies a flag indicating whether or not the character in
  1909. the string is to be left justfied.
  1910. Character - Supplies a boolean indicating that this is a character rather
  1911. than a full string.
  1912. Return Value:
  1913. TRUE if all characters were written to the destination.
  1914. FALSE if the destination crapped out before all characters could be written.
  1915. --*/
  1916. {
  1917. ULONG PaddingIndex;
  1918. ULONG PaddingLength;
  1919. BOOL Result;
  1920. ULONG StringLength;
  1921. if (String == NULL) {
  1922. String = L"(null)";
  1923. }
  1924. if (Character != FALSE) {
  1925. StringLength = 1;
  1926. } else {
  1927. StringLength = RtlStringLengthWide(String);
  1928. }
  1929. if ((Precision >= 0) && (StringLength > Precision)) {
  1930. StringLength = Precision;
  1931. }
  1932. //
  1933. // Find out how much padding to add to the field.
  1934. //
  1935. PaddingLength = 0;
  1936. if (FieldWidth > StringLength) {
  1937. PaddingLength = FieldWidth - StringLength;
  1938. }
  1939. PaddingIndex = PaddingLength;
  1940. //
  1941. // Pad left, if required.
  1942. //
  1943. if (LeftJustified == FALSE) {
  1944. while (PaddingIndex > 0) {
  1945. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  1946. if (Result == FALSE) {
  1947. return FALSE;
  1948. }
  1949. PaddingIndex -= 1;
  1950. }
  1951. }
  1952. //
  1953. // Copy the string.
  1954. //
  1955. while (StringLength != 0) {
  1956. Result = RtlpFormatWriteCharacterWide(Context, *String);
  1957. if (Result == FALSE) {
  1958. return FALSE;
  1959. }
  1960. String += 1;
  1961. StringLength -= 1;
  1962. }
  1963. //
  1964. // Pad right, if required.
  1965. //
  1966. while (PaddingIndex > 0) {
  1967. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  1968. if (Result == FALSE) {
  1969. return FALSE;
  1970. }
  1971. PaddingIndex -= 1;
  1972. }
  1973. return TRUE;
  1974. }
  1975. BOOL
  1976. RtlpPrintByteStringWide (
  1977. PPRINT_FORMAT_CONTEXT Context,
  1978. PSTR String,
  1979. LONG FieldWidth,
  1980. LONG Precision,
  1981. BOOL LeftJustified,
  1982. BOOL Character
  1983. )
  1984. /*++
  1985. Routine Description:
  1986. This routine prints a byte-based string to a wide print destination.
  1987. Arguments:
  1988. Context - Supplies a pointer to the initialized context structure.
  1989. String - Supplies a pointer to the string to print.
  1990. FieldWidth - Supplies the width of the string or character field. If the
  1991. argument doesn't fill up this space, it will be padded with spaces.
  1992. Precision - Supplies the precision of the string (the maximum number of
  1993. characters to print). Supply -1 to print the whole string.
  1994. LeftJustified - Supplies a flag indicating whether or not the character in
  1995. the string is to be left justfied.
  1996. Character - Supplies a boolean indicating that this is a character rather
  1997. than a full string.
  1998. Return Value:
  1999. TRUE if all characters were written to the destination.
  2000. FALSE if the destination crapped out before all characters could be written.
  2001. --*/
  2002. {
  2003. ULONG PaddingIndex;
  2004. ULONG PaddingLength;
  2005. BOOL Result;
  2006. KSTATUS Status;
  2007. ULONG StringLength;
  2008. WCHAR WideCharacter;
  2009. if (String == NULL) {
  2010. String = "(null)";
  2011. }
  2012. if (Character != FALSE) {
  2013. StringLength = 1;
  2014. } else {
  2015. StringLength = RtlStringLength(String);
  2016. }
  2017. //
  2018. // Find out how much padding to add to the field.
  2019. //
  2020. PaddingLength = 0;
  2021. if (FieldWidth > StringLength) {
  2022. PaddingLength = FieldWidth - StringLength;
  2023. }
  2024. PaddingIndex = PaddingLength;
  2025. //
  2026. // Pad left, if required.
  2027. //
  2028. if (LeftJustified == FALSE) {
  2029. while (PaddingIndex > 0) {
  2030. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  2031. if (Result == FALSE) {
  2032. return FALSE;
  2033. }
  2034. PaddingIndex -= 1;
  2035. }
  2036. }
  2037. //
  2038. // Copy the string by converting bytes into wide characters.
  2039. //
  2040. while (StringLength != 0) {
  2041. Status = RtlConvertMultibyteCharacterToWide(&String,
  2042. &StringLength,
  2043. &WideCharacter,
  2044. &(Context->State));
  2045. if (!KSUCCESS(Status)) {
  2046. return FALSE;
  2047. }
  2048. Result = RtlpFormatWriteCharacterWide(Context, WideCharacter);
  2049. if (Result == FALSE) {
  2050. return FALSE;
  2051. }
  2052. }
  2053. //
  2054. // Pad right, if required.
  2055. //
  2056. while (PaddingIndex > 0) {
  2057. Result = RtlpFormatWriteCharacterWide(Context, L' ');
  2058. if (Result == FALSE) {
  2059. return FALSE;
  2060. }
  2061. PaddingIndex -= 1;
  2062. }
  2063. return TRUE;
  2064. }
  2065. BOOL
  2066. RtlpFormatWriteCharacterWide (
  2067. PPRINT_FORMAT_CONTEXT Context,
  2068. WCHAR Character
  2069. )
  2070. /*++
  2071. Routine Description:
  2072. This routine writes a wide character to the print format destination.
  2073. Arguments:
  2074. Context - Supplies a pointer to the print format context.
  2075. Character - Supplies the character to write.
  2076. Return Value:
  2077. TRUE if the character was written.
  2078. FALSE on failure.
  2079. --*/
  2080. {
  2081. BOOL Result;
  2082. Result = Context->U.WriteWideCharacter(Character, Context);
  2083. if (Result == FALSE) {
  2084. return FALSE;
  2085. }
  2086. Context->CharactersWritten += 1;
  2087. return TRUE;
  2088. }
  2089. ULONGLONG
  2090. RtlpGetPositionalArgumentWide (
  2091. PWSTR Format,
  2092. ULONG ArgumentNumber,
  2093. va_list *Arguments
  2094. )
  2095. /*++
  2096. Routine Description:
  2097. This routine attempts to get a positional argument by rescanning the
  2098. string from the beginning and counting up all arguments less than it. This
  2099. is more than a little slow (O(N^2) for each argument), but it doesn't
  2100. require allocations, which is nice for a library like this shared between
  2101. several environments.
  2102. Arguments:
  2103. Format - Supplies the format string.
  2104. ArgumentNumber - Supplies the argument number to retrieve.
  2105. Arguments - Supplies a pointer to a VA list initialized at the beginning
  2106. of the printf arguments. This list will be copied.
  2107. Return Value:
  2108. Returns the argument.
  2109. --*/
  2110. {
  2111. ULONGLONG Argument;
  2112. ULONG ArgumentIndex;
  2113. va_list ArgumentsCopy;
  2114. ULONG ArgumentSize;
  2115. ASSERT(ArgumentNumber != 0);
  2116. va_copy(ArgumentsCopy, *Arguments);
  2117. for (ArgumentIndex = 1;
  2118. ArgumentIndex < ArgumentNumber;
  2119. ArgumentIndex += 1) {
  2120. //
  2121. // Get the size of this argument.
  2122. //
  2123. ArgumentSize = RtlpGetPositionalArgumentSizeWide(Format, ArgumentIndex);
  2124. switch (ArgumentSize) {
  2125. case 0:
  2126. break;
  2127. case sizeof(CHAR):
  2128. Argument = va_arg(ArgumentsCopy, INT);
  2129. break;
  2130. case sizeof(SHORT):
  2131. Argument = va_arg(ArgumentsCopy, INT);
  2132. break;
  2133. case sizeof(LONG):
  2134. Argument = va_arg(ArgumentsCopy, LONG);
  2135. break;
  2136. case sizeof(LONGLONG):
  2137. Argument = va_arg(ArgumentsCopy, LONGLONG);
  2138. break;
  2139. default:
  2140. ASSERT(FALSE);
  2141. break;
  2142. }
  2143. }
  2144. //
  2145. // Now the important one, get the size of the specified argument.
  2146. //
  2147. Argument = 0;
  2148. ArgumentSize = RtlpGetPositionalArgumentSizeWide(Format, ArgumentNumber);
  2149. switch (ArgumentSize) {
  2150. case 0:
  2151. break;
  2152. case sizeof(CHAR):
  2153. Argument = (UCHAR)va_arg(ArgumentsCopy, INT);
  2154. break;
  2155. case sizeof(SHORT):
  2156. Argument = (USHORT)va_arg(ArgumentsCopy, INT);
  2157. break;
  2158. case sizeof(LONG):
  2159. Argument = va_arg(ArgumentsCopy, LONG);
  2160. break;
  2161. case sizeof(LONGLONG):
  2162. Argument = va_arg(ArgumentsCopy, LONGLONG);
  2163. break;
  2164. default:
  2165. ASSERT(FALSE);
  2166. break;
  2167. }
  2168. va_end(ArgumentsCopy);
  2169. return Argument;
  2170. }
  2171. ULONG
  2172. RtlpGetPositionalArgumentSizeWide (
  2173. PWSTR Format,
  2174. ULONG ArgumentNumber
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. This routine scans through the format string to determine the size of the
  2179. given positional argument.
  2180. Arguments:
  2181. Format - Supplies the format string.
  2182. ArgumentNumber - Supplies the argument number to retrieve.
  2183. Return Value:
  2184. Returns the size of the argument.
  2185. 0 if the given positional argument was not found.
  2186. --*/
  2187. {
  2188. ULONG ArgumentSize;
  2189. ULONG CurrentArgumentSize;
  2190. LONGLONG Integer;
  2191. ULONG Position;
  2192. ULONG RemainingSize;
  2193. KSTATUS Status;
  2194. ArgumentSize = 0;
  2195. while (*Format != WIDE_STRING_TERMINATOR) {
  2196. if (*Format != CONVERSION_CHARACTER) {
  2197. Format += 1;
  2198. continue;
  2199. }
  2200. Position = 0;
  2201. Format += 1;
  2202. //
  2203. // If there's a non-zero digit, grab it. It could be the position or
  2204. // field width.
  2205. //
  2206. if ((*Format >= L'1') && (*Format <= L'9')) {
  2207. RemainingSize = -1;
  2208. Status = RtlStringScanIntegerWide(&Format,
  2209. &RemainingSize,
  2210. 10,
  2211. FALSE,
  2212. &Integer);
  2213. if (!KSUCCESS(Status)) {
  2214. return 0;
  2215. }
  2216. if (*Format == POSITIONAL_ARGUMENT) {
  2217. Position = (ULONG)Integer;
  2218. Format += 1;
  2219. }
  2220. }
  2221. //
  2222. // Get past any flags.
  2223. //
  2224. while (TRUE) {
  2225. if ((*Format != THOUSANDS_GROUPING) &&
  2226. (*Format != LEFT_JUSTIFIED) &&
  2227. (*Format != SPACE_FOR_PLUS) &&
  2228. (*Format != PRINT_SIGN) &&
  2229. (*Format != PRINT_RADIX_IDENTIFIER) &&
  2230. (*Format != PRINT_LEADING_ZEROES)) {
  2231. break;
  2232. }
  2233. Format += 1;
  2234. }
  2235. //
  2236. // Process a field width. It could have already been sucked in, be a
  2237. // decimal, be a star, or be a star followed by a position and a dollar
  2238. // sign.
  2239. //
  2240. if (*Format == FIELD_IN_ARGUMENT) {
  2241. Format += 1;
  2242. if ((*Format >= L'1') && (*Format <= L'9')) {
  2243. RemainingSize = -1;
  2244. Status = RtlStringScanIntegerWide(&Format,
  2245. &RemainingSize,
  2246. 10,
  2247. FALSE,
  2248. &Integer);
  2249. if ((!KSUCCESS(Status)) || (Integer < 0)) {
  2250. return 0;
  2251. }
  2252. if (*Format != POSITIONAL_ARGUMENT) {
  2253. return 0;
  2254. }
  2255. Format += 1;
  2256. //
  2257. // This is a positional argument and its size is int.
  2258. //
  2259. if ((Integer == ArgumentNumber) &&
  2260. (ArgumentSize < sizeof(INT))) {
  2261. ArgumentSize = sizeof(INT);
  2262. }
  2263. }
  2264. } else if ((*Format >= L'1') && (*Format <= L'9')) {
  2265. RemainingSize = -1;
  2266. RtlStringScanIntegerWide(&Format,
  2267. &RemainingSize,
  2268. 10,
  2269. FALSE,
  2270. &Integer);
  2271. }
  2272. //
  2273. // If there's a dot, then the precision follows. Like the field width,
  2274. // it could either be a decimal, a star, or a star plus a position and a
  2275. // dollar sign.
  2276. //
  2277. if (*Format == PRECISION_SPECIFIED) {
  2278. Format += 1;
  2279. if (*Format == FIELD_IN_ARGUMENT) {
  2280. Format += 1;
  2281. if ((*Format >= L'1') && (*Format <= L'9')) {
  2282. RemainingSize = -1;
  2283. Status = RtlStringScanIntegerWide(&Format,
  2284. &RemainingSize,
  2285. 10,
  2286. FALSE,
  2287. &Integer);
  2288. if ((!KSUCCESS(Status)) || (Integer < 0)) {
  2289. return 0;
  2290. }
  2291. if (*Format != POSITIONAL_ARGUMENT) {
  2292. return 0;
  2293. }
  2294. Format += 1;
  2295. //
  2296. // This is a positional argument and its size is int.
  2297. //
  2298. if ((Integer == ArgumentNumber) &&
  2299. (ArgumentSize < sizeof(INT))) {
  2300. ArgumentSize = sizeof(INT);
  2301. }
  2302. }
  2303. } else if ((*Format >= L'1') && (*Format <= L'9')) {
  2304. RemainingSize = -1;
  2305. RtlStringScanIntegerWide(&Format,
  2306. &RemainingSize,
  2307. 10,
  2308. FALSE,
  2309. &Integer);
  2310. }
  2311. }
  2312. //
  2313. // Look for the length modifiers: hh, h, l, ll, j, z, t, L, I64.
  2314. //
  2315. CurrentArgumentSize = sizeof(INT);
  2316. if (*Format == FORMAT_SHORT) {
  2317. Format += 1;
  2318. CurrentArgumentSize = sizeof(SHORT);
  2319. if (*Format == FORMAT_SHORT) {
  2320. Format += 1;
  2321. CurrentArgumentSize = sizeof(CHAR);
  2322. }
  2323. } else if (*Format == FORMAT_LONG) {
  2324. Format += 1;
  2325. CurrentArgumentSize = sizeof(LONG);
  2326. if (*Format == FORMAT_LONG) {
  2327. Format += 1;
  2328. CurrentArgumentSize = sizeof(LONGLONG);
  2329. }
  2330. } else if (*Format == FORMAT_INTMAX) {
  2331. Format += 1;
  2332. CurrentArgumentSize = sizeof(intmax_t);
  2333. } else if (*Format == FORMAT_SIZE_T) {
  2334. Format += 1;
  2335. CurrentArgumentSize = sizeof(size_t);
  2336. } else if (*Format == FORMAT_LONG_DOUBLE) {
  2337. Format += 1;
  2338. CurrentArgumentSize = sizeof(long double);
  2339. } else if ((*Format == FORMAT_LONGLONG_START) &&
  2340. (*(Format + 1) == L'6') &&
  2341. (*(Format + 1) == L'4')) {
  2342. Format += 3;
  2343. CurrentArgumentSize = sizeof(LONGLONG);
  2344. }
  2345. //
  2346. // Now, finally, get the conversion specifier.
  2347. //
  2348. if ((*Format == FORMAT_POINTER) || (*Format == FORMAT_BYTES_PRINTED)) {
  2349. CurrentArgumentSize = sizeof(PVOID);
  2350. } else if (*Format == FORMAT_LONG_CHARACTER) {
  2351. CurrentArgumentSize = sizeof(SHORT);
  2352. } else if (*Format == FORMAT_CHARACTER) {
  2353. CurrentArgumentSize = sizeof(CHAR);
  2354. } else if ((*Format == FORMAT_LONG_STRING) ||
  2355. (*Format == FORMAT_STRING)) {
  2356. CurrentArgumentSize = sizeof(PVOID);
  2357. } else if (*Format == FORMAT_NONE) {
  2358. CurrentArgumentSize = 0;
  2359. }
  2360. //
  2361. // If the argument is the right position, up the argument size.
  2362. //
  2363. if ((Position == ArgumentNumber) &&
  2364. (CurrentArgumentSize > ArgumentSize)) {
  2365. ArgumentSize = CurrentArgumentSize;
  2366. }
  2367. Format += 1;
  2368. }
  2369. return ArgumentSize;
  2370. }
  2371. BOOL
  2372. RtlpStringFormatWriteCharacterWide (
  2373. WCHAR Character,
  2374. PPRINT_FORMAT_CONTEXT Context
  2375. )
  2376. /*++
  2377. Routine Description:
  2378. This routine writes a character to the string during a printf-style
  2379. formatting operation.
  2380. Arguments:
  2381. Character - Supplies the character to be written.
  2382. Context - Supplies a pointer to the printf-context.
  2383. Return Value:
  2384. TRUE on success.
  2385. FALSE on failure.
  2386. --*/
  2387. {
  2388. PWSTR String;
  2389. String = Context->Context;
  2390. if ((String != NULL) && (Context->CharactersWritten < Context->Limit)) {
  2391. String[Context->CharactersWritten] = Character;
  2392. }
  2393. return TRUE;
  2394. }