1
0

print.c 81 KB

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