12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- wprint.c
- Abstract:
- This module implements wide character print format support.
- Author:
- Evan Green 27-Aug-2013
- Environment:
- Any
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "rtlp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define CONVERSION_CHARACTER L'%'
- #define POSITIONAL_ARGUMENT L'$'
- #define FIELD_IN_ARGUMENT L'*'
- #define THOUSANDS_GROUPING L'\''
- #define LEFT_JUSTIFIED L'-'
- #define SPACE_FOR_PLUS L' '
- #define PRINT_SIGN L'+'
- #define PRINT_RADIX_IDENTIFIER L'#'
- #define PRINT_LEADING_ZEROES L'0'
- #define PRECISION_SPECIFIED L'.'
- #define FORMAT_SHORT L'h'
- #define FORMAT_LONG L'l'
- #define FORMAT_INTMAX L'j'
- #define FORMAT_SIZE_T L'z'
- #define FORMAT_PTRDIFF_T L't'
- #define FORMAT_LONG_DOUBLE L'L'
- #define FORMAT_DOUBLE_HEX L'a'
- #define FORMAT_DOUBLE_HEX_CAPITAL L'A'
- #define FORMAT_FLOAT L'f'
- #define FORMAT_FLOAT_CAPITAL L'F'
- #define FORMAT_SCIENTIFIC L'e'
- #define FORMAT_SCIENTIFIC_CAPITAL L'E'
- #define FORMAT_DOUBLE L'g'
- #define FORMAT_DOUBLE_CAPITAL L'G'
- #define FORMAT_CHARACTER L'c'
- #define FORMAT_LONG_CHARACTER L'C'
- #define FORMAT_STRING L's'
- #define FORMAT_LONG_STRING L'S'
- #define FORMAT_BYTES_PRINTED L'n'
- #define FORMAT_POINTER L'p'
- #define FORMAT_NONE L'%'
- #define FORMAT_DECIMAL L'd'
- #define FORMAT_DECIMAL2 L'i'
- #define FORMAT_OCTAL L'o'
- #define FORMAT_UNSIGNED L'u'
- #define FORMAT_HEX L'x'
- #define FORMAT_HEX_CAPITAL L'X'
- #define FORMAT_LONGLONG_START L'I'
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOL
- RtlpConvertFormatSpecifierWide (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR Format,
- PULONG Index,
- va_list *Arguments
- );
- ULONG
- RtlpPrintIntegerWide (
- PPRINT_FORMAT_CONTEXT Context,
- ULONGLONG Integer,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- ULONG
- RtlpPrintDoubleWide (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- ULONG
- RtlpPrintHexDoubleWide (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- BOOL
- RtlpPrintStringWide (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- );
- BOOL
- RtlpPrintByteStringWide (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- );
- BOOL
- RtlpFormatWriteCharacterWide (
- PPRINT_FORMAT_CONTEXT Context,
- WCHAR Character
- );
- ULONGLONG
- RtlpGetPositionalArgumentWide (
- PWSTR Format,
- ULONG ArgumentNumber,
- va_list *Arguments
- );
- ULONG
- RtlpGetPositionalArgumentSizeWide (
- PWSTR Format,
- ULONG ArgumentNumber
- );
- BOOL
- RtlpStringFormatWriteCharacterWide (
- WCHAR Character,
- PPRINT_FORMAT_CONTEXT Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- RTL_API
- ULONG
- RtlPrintToStringWide (
- PWSTR Destination,
- ULONG DestinationSize,
- CHARACTER_ENCODING Encoding,
- PWSTR Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatted wide string out to a buffer.
- Arguments:
- Destination - Supplies a pointer to the buffer where the formatted string
- will be placed.
- DestinationSize - Supplies the size of the destination buffer, in bytes.
- Encoding - Supplies the character encoding to use for any non-wide
- characters or strings.
- Format - Supplies the printf-style format string to print. The contents of
- this string determine the rest of the arguments passed.
- ... - Supplies any arguments needed to convert the Format string.
- Return Value:
- Returns the length of the final string (in characters) after all formatting
- has been completed. The length will be returned even if NULL is passed as
- the destination.
- --*/
- {
- va_list ArgumentList;
- ULONG Result;
- va_start(ArgumentList, Format);
- Result = RtlFormatStringWide(Destination,
- DestinationSize,
- Encoding,
- Format,
- ArgumentList);
- va_end(ArgumentList);
- return Result;
- }
- RTL_API
- ULONG
- RtlFormatStringWide (
- PWSTR Destination,
- ULONG DestinationSize,
- CHARACTER_ENCODING Encoding,
- PWSTR Format,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine converts a printf-style wide format string given the
- parameters.
- Arguments:
- Destination - Supplies a pointer to the buffer where the final string will
- be printed. It is assumed that this string is allocated and is big
- enough to hold the converted string. Pass NULL here to determine how big
- a buffer is necessary to hold the string. If the buffer is not big
- enough, it will be truncated but still NULL terminated.
- DestinationSize - Supplies the size of the destination buffer. If NULL was
- passed as the Destination argument, then this argument is ignored.
- Encoding - Supplies the character encoding to use for any non-wide
- characters or strings.
- Format - Supplies a pointer to the printf-style format string.
- ArgumentList - Supplies an initialized list of arguments to the format
- string.
- Return Value:
- Returns the length of the final string after all formatting has been
- completed, including the null terminator. The length will be returned even
- if NULL is passed as the destination.
- --*/
- {
- UINTN CharactersWritten;
- PRINT_FORMAT_CONTEXT Context;
- RtlZeroMemory(&Context, sizeof(PRINT_FORMAT_CONTEXT));
- Context.U.WriteWideCharacter = RtlpStringFormatWriteCharacterWide;
- Context.Context = Destination;
- if (DestinationSize != 0) {
- Context.Limit = DestinationSize - 1;
- }
- RtlInitializeMultibyteState(&(Context.State), Encoding);
- RtlFormatWide(&Context, Format, ArgumentList);
- CharactersWritten = Context.CharactersWritten;
- if (DestinationSize != 0) {
- if (Context.CharactersWritten > Context.Limit) {
- Context.CharactersWritten = Context.Limit;
- }
- Context.Limit = DestinationSize;
- }
- RtlpFormatWriteCharacterWide(&Context, WIDE_STRING_TERMINATOR);
- return CharactersWritten + 1;
- }
- RTL_API
- BOOL
- RtlFormatWide (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR Format,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine converts a printf-style wide format string given the
- parameters.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- Format - Supplies a pointer to the printf-style format string.
- ArgumentList - Supplies an initialized list of arguments to the format
- string.
- Return Value:
- TRUE if all characters were written to the destination.
- FALSE if the destination or limit cut the conversion short.
- --*/
- {
- va_list ArgumentListCopy;
- ULONG Index;
- BOOL Result;
- ASSERT((Context != NULL) && (Context->U.WriteWideCharacter != NULL) &&
- (Context->CharactersWritten == 0) &&
- (RtlIsCharacterEncodingSupported(Context->State.Encoding) != FALSE));
- if (Format == NULL) {
- Format = L"(null)";
- }
- //
- // Copy each character to the destination, handling formats along the way.
- //
- va_copy(ArgumentListCopy, ArgumentList);
- Result = TRUE;
- Index = 0;
- while (Format[Index] != WIDE_STRING_TERMINATOR) {
- if (Format[Index] == CONVERSION_CHARACTER) {
- Result = RtlpConvertFormatSpecifierWide(Context,
- Format,
- &Index,
- &ArgumentListCopy);
- if (Result == FALSE) {
- goto FormatWideEnd;
- }
- } else {
- Result = RtlpFormatWriteCharacterWide(Context, Format[Index]);
- if (Result == FALSE) {
- goto FormatWideEnd;
- }
- Index += 1;
- }
- }
- FormatWideEnd:
- va_end(ArgumentListCopy);
- return Result;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOL
- RtlpConvertFormatSpecifierWide (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR Format,
- PULONG Index,
- va_list *Arguments
- )
- /*++
- Routine Description:
- This routine converts one printf-style wide format specifier to its wide
- string conversion.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- Format - Supplies a pointer to the printf-style conversion specifier.
- Index - Supplies a pointer that upon input contains the index of the
- L'%' specifier to convert. On output, this will be advanced beyond the
- specifier.
- Arguments - Supplies a pointer to the variable list of arguments.
- Return Value:
- TRUE if all characters were written to the destination.
- FALSE if the string was truncated.
- --*/
- {
- CHAR ByteCharacterArgument;
- PSTR ByteStringArgument;
- WCHAR CharacterArgument;
- PWSTR CurrentFormat;
- DOUBLE_PARTS DoubleParts;
- LONGLONG Integer;
- ULONGLONG IntegerArgument;
- BOOL IsFloat;
- BOOL IsInteger;
- BOOL LongDoubleSpecified;
- BOOL LongSpecified;
- ULONG Position;
- PRINT_FORMAT_PROPERTIES Properties;
- ULONG RemainingSize;
- BOOL Result;
- WCHAR Specifier;
- KSTATUS Status;
- PWSTR StringArgument;
- CurrentFormat = Format + *Index;
- RtlZeroMemory(&Properties, sizeof(PRINT_FORMAT_PROPERTIES));
- IntegerArgument = 0;
- Properties.Precision = -1;
- //
- // Check for the format character.
- //
- if (*CurrentFormat != CONVERSION_CHARACTER) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- CurrentFormat += 1;
- Position = 0;
- //
- // If there's a non-zero digit, grab it. It could be the position or field
- // width.
- //
- if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Integer = 0;
- }
- if (*CurrentFormat == POSITIONAL_ARGUMENT) {
- if (Integer < 0) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- Position = (ULONG)Integer;
- CurrentFormat += 1;
- } else {
- Properties.FieldWidth = (ULONG)Integer;
- }
- }
- //
- // Process any flags.
- //
- while (TRUE) {
- if (*CurrentFormat == THOUSANDS_GROUPING) {
- Properties.ThousandsGrouping = TRUE;
- } else if (*CurrentFormat == LEFT_JUSTIFIED) {
- Properties.LeftJustified = TRUE;
- } else if (*CurrentFormat == SPACE_FOR_PLUS) {
- Properties.SpaceForPlus = TRUE;
- } else if (*CurrentFormat == PRINT_SIGN) {
- Properties.AlwaysPrintSign = TRUE;
- } else if (*CurrentFormat == PRINT_RADIX_IDENTIFIER) {
- Properties.PrintRadix = TRUE;
- } else if (*CurrentFormat == PRINT_LEADING_ZEROES) {
- Properties.PrintLeadingZeroes = TRUE;
- } else {
- break;
- }
- CurrentFormat += 1;
- }
- //
- // If both print leading zeroes and left justify are specified, print
- // leading zeroes is ignored.
- //
- if (Properties.LeftJustified != FALSE) {
- Properties.PrintLeadingZeroes = FALSE;
- }
- if (Properties.AlwaysPrintSign != FALSE) {
- Properties.SpaceForPlus = FALSE;
- }
- //
- // Process a field width. It could have already been sucked in, be a
- // decimal, be a star, or be a star followed by a position and a dollar
- // sign.
- //
- if (*CurrentFormat == FIELD_IN_ARGUMENT) {
- CurrentFormat += 1;
- if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- if (*CurrentFormat != POSITIONAL_ARGUMENT) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- CurrentFormat += 1;
- Properties.FieldWidth = (INT)RtlpGetPositionalArgumentWide(
- Format,
- (ULONG)Integer,
- Arguments);
- } else {
- Properties.FieldWidth = va_arg(*Arguments, INT);
- }
- } else if ((*CurrentFormat >= L'1') && (*CurrentFormat <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- Properties.FieldWidth = (ULONG)Integer;
- }
- if (Properties.FieldWidth < 0) {
- Properties.LeftJustified = TRUE;
- Properties.FieldWidth = -Properties.FieldWidth;
- }
- //
- // If there's a dot, then the precision follows. Like the field width, it
- // could either be a decimal, a star, or a star plus a position and a
- // dollar sign.
- //
- if (*CurrentFormat == PRECISION_SPECIFIED) {
- CurrentFormat += 1;
- if (*CurrentFormat == FIELD_IN_ARGUMENT) {
- CurrentFormat += 1;
- if ((*CurrentFormat >= L'0') && (*CurrentFormat <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- if (*CurrentFormat != POSITIONAL_ARGUMENT) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- CurrentFormat += 1;
- Properties.Precision = (INT)RtlpGetPositionalArgumentWide(
- Format,
- (ULONG)Integer,
- Arguments);
- } else {
- Properties.Precision = va_arg(*Arguments, INT);
- }
- } else if ((*CurrentFormat >= L'0') && (*CurrentFormat <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- if (Integer >= 0) {
- Properties.Precision = (ULONG)Integer;
- }
- }
- }
- //
- // A negative precision is taken as precision being omitted.
- //
- if (Properties.Precision < 0) {
- Properties.Precision = -1;
- }
- //
- // Look for the length modifiers: hh, h, l, ll, j, z, t, L, I64.
- //
- LongSpecified = FALSE;
- LongDoubleSpecified = FALSE;
- Properties.IntegerSize = sizeof(INT);
- if (*CurrentFormat == FORMAT_SHORT) {
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(SHORT);
- if (*CurrentFormat == FORMAT_SHORT) {
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(CHAR);
- }
- } else if (*CurrentFormat == FORMAT_LONG) {
- LongSpecified = TRUE;
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(LONG);
- if (*CurrentFormat == FORMAT_LONG) {
- LongSpecified = FALSE;
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(LONGLONG);
- }
- } else if (*CurrentFormat == FORMAT_INTMAX) {
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(intmax_t);
- } else if (*CurrentFormat == FORMAT_SIZE_T) {
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(size_t);
- } else if (*CurrentFormat == FORMAT_LONG_DOUBLE) {
- //
- // Printing of long doubles is not currently supported.
- //
- ASSERT(FALSE);
- LongDoubleSpecified = TRUE;
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(long double);
- } else if ((*CurrentFormat == FORMAT_LONGLONG_START) &&
- (*(CurrentFormat + 1) == '6') &&
- (*(CurrentFormat + 2) == '4')) {
- CurrentFormat += 3;
- Properties.IntegerSize = sizeof(LONGLONG);
- }
- //
- // Now, finally, get the conversion specifier
- //
- Specifier = *CurrentFormat;
- if (LongSpecified != FALSE) {
- if (Specifier == FORMAT_CHARACTER) {
- Specifier = FORMAT_LONG_CHARACTER;
- } else if (Specifier == FORMAT_STRING) {
- Specifier = FORMAT_LONG_STRING;
- }
- }
- IsInteger = FALSE;
- IsFloat = FALSE;
- Properties.Unsigned = TRUE;
- switch (Specifier) {
- case FORMAT_DECIMAL:
- case FORMAT_DECIMAL2:
- IsInteger = TRUE;
- Properties.Radix = 10;
- Properties.Unsigned = FALSE;
- break;
- case FORMAT_OCTAL:
- IsInteger = TRUE;
- Properties.Radix = 8;
- break;
- case FORMAT_UNSIGNED:
- IsInteger = TRUE;
- Properties.Radix = 10;
- break;
- case FORMAT_HEX:
- IsInteger = TRUE;
- Properties.Radix = 16;
- break;
- case FORMAT_POINTER:
- IsInteger = TRUE;
- Properties.IntegerSize = sizeof(UINTN);
- Properties.Radix = 16;
- Properties.PrintUpperCase = TRUE;
- break;
- case FORMAT_HEX_CAPITAL:
- IsInteger = TRUE;
- Properties.Radix = 16;
- Properties.PrintUpperCase = TRUE;
- break;
- case FORMAT_BYTES_PRINTED:
- IsInteger = TRUE;
- Properties.IntegerSize = sizeof(PVOID);
- break;
- case FORMAT_FLOAT:
- IsFloat = TRUE;
- Properties.FloatFormat = TRUE;
- break;
- case FORMAT_FLOAT_CAPITAL:
- IsFloat = TRUE;
- Properties.FloatFormat = TRUE;
- Properties.PrintUpperCase = TRUE;
- break;
- case FORMAT_DOUBLE:
- IsFloat = TRUE;
- Properties.SignificantDigitPrecision = TRUE;
- break;
- case FORMAT_DOUBLE_CAPITAL:
- IsFloat = TRUE;
- Properties.PrintUpperCase = TRUE;
- Properties.SignificantDigitPrecision = TRUE;
- break;
- case FORMAT_SCIENTIFIC:
- IsFloat = TRUE;
- Properties.ScientificFormat = TRUE;
- break;
- case FORMAT_SCIENTIFIC_CAPITAL:
- IsFloat = TRUE;
- Properties.ScientificFormat = TRUE;
- Properties.PrintUpperCase = TRUE;
- break;
- case FORMAT_DOUBLE_HEX:
- IsFloat = TRUE;
- Properties.ScientificFormat = TRUE;
- Properties.Radix = 16;
- break;
- case FORMAT_DOUBLE_HEX_CAPITAL:
- IsFloat = TRUE;
- Properties.ScientificFormat = TRUE;
- Properties.PrintUpperCase = TRUE;
- Properties.Radix = 16;
- break;
- case FORMAT_LONG_CHARACTER:
- if (Position != 0) {
- CharacterArgument = (WCHAR)RtlpGetPositionalArgumentWide(Format,
- Position,
- Arguments);
- } else {
- CharacterArgument = va_arg(*Arguments, int);
- }
- Result = RtlpPrintStringWide(Context,
- &CharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- break;
- case FORMAT_CHARACTER:
- RtlResetMultibyteState(&(Context->State));
- if (Position != 0) {
- ByteCharacterArgument = (UCHAR)RtlpGetPositionalArgumentWide(
- Format,
- Position,
- Arguments);
- } else {
- ByteCharacterArgument = (CHAR)va_arg(*Arguments, INT);
- }
- Result = RtlpPrintByteStringWide(Context,
- &ByteCharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- break;
- case FORMAT_LONG_STRING:
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgumentWide(Format,
- Position,
- Arguments);
- StringArgument = (PWSTR)(UINTN)IntegerArgument;
- } else {
- StringArgument = va_arg(*Arguments, PWSTR);
- }
- Result = RtlpPrintStringWide(Context,
- StringArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- FALSE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- break;
- case FORMAT_STRING:
- RtlResetMultibyteState(&(Context->State));
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgumentWide(Format,
- Position,
- Arguments);
- ByteStringArgument = (PSTR)(UINTN)IntegerArgument;
- } else {
- ByteStringArgument = va_arg(*Arguments, PSTR);
- }
- Result = RtlpPrintByteStringWide(Context,
- ByteStringArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- FALSE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- break;
- case FORMAT_NONE:
- IsInteger = FALSE;
- CharacterArgument = FORMAT_NONE;
- Result = RtlpPrintStringWide(Context,
- &CharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- break;
- default:
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- CurrentFormat += 1;
- //
- // If it's an integer, get the argument and process it.
- //
- if (IsInteger != FALSE) {
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgumentWide(Format,
- Position,
- Arguments);
- switch (Properties.IntegerSize) {
- case 0:
- break;
- case sizeof(CHAR):
- IntegerArgument = (UCHAR)IntegerArgument;
- break;
- case sizeof(SHORT):
- IntegerArgument = (USHORT)IntegerArgument;
- break;
- case sizeof(LONG):
- IntegerArgument = (ULONG)IntegerArgument;
- break;
- case sizeof(LONGLONG):
- break;
- default:
- ASSERT(FALSE);
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- } else {
- switch (Properties.IntegerSize) {
- case 0:
- break;
- case sizeof(CHAR):
- IntegerArgument = (CHAR)va_arg(*Arguments, UINT);
- break;
- case sizeof(SHORT):
- IntegerArgument = (SHORT)va_arg(*Arguments, UINT);
- break;
- case sizeof(LONG):
- IntegerArgument = va_arg(*Arguments, ULONG);
- break;
- case sizeof(LONGLONG):
- IntegerArgument = va_arg(*Arguments, ULONGLONG);
- break;
- default:
- ASSERT(FALSE);
- Result = FALSE;
- goto ConvertFormatSpecifierWideEnd;
- }
- }
- if (Specifier == FORMAT_BYTES_PRINTED) {
- ASSERT(IntegerArgument != (UINTN)NULL);
- *((PINT)(UINTN)IntegerArgument) = Context->CharactersWritten;
- } else {
- Result = RtlpPrintIntegerWide(Context,
- IntegerArgument,
- &Properties);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- }
- //
- // If it's an float, get the argument and process it.
- //
- } else if (IsFloat != FALSE) {
- if (Position != 0) {
- //
- // TODO: Support long double.
- //
- DoubleParts.Ulonglong = RtlpGetPositionalArgumentWide(Format,
- Position,
- Arguments);
- } else {
- if (LongDoubleSpecified != FALSE) {
- DoubleParts.Double = (double)va_arg(*Arguments, long double);
- } else {
- DoubleParts.Double = va_arg(*Arguments, double);
- }
- }
- Result = RtlpPrintDoubleWide(Context, DoubleParts.Double, &Properties);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierWideEnd;
- }
- }
- Result = TRUE;
- ConvertFormatSpecifierWideEnd:
- *Index += ((UINTN)CurrentFormat - (UINTN)(Format + *Index)) / sizeof(WCHAR);
- return Result;
- }
- ULONG
- RtlpPrintIntegerWide (
- PPRINT_FORMAT_CONTEXT Context,
- ULONGLONG Integer,
- PPRINT_FORMAT_PROPERTIES Properties
- )
- /*++
- Routine Description:
- This routine prints an integer to the destination given the style
- properties.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- DestinationSize - Supplies the size of the destination buffer. If NULL was
- passed as the Destination argument, then this argument is ignored.
- Integer - Supplies the integer argument to convert to a string.
- Properties - Supplies the style characteristics to use when printing this
- integer.
- Return Value:
- Returns the length of the final string after the format conversion has
- completed. The length will be returned even if NULL is passed as the
- destination.
- --*/
- {
- WCHAR Character;
- ULONG FieldCount;
- ULONG FieldIndex;
- ULONG IntegerLength;
- WCHAR LocalBuffer[MAX_INTEGER_STRING_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- ULONGLONG NextInteger;
- LONG Precision;
- ULONG PrecisionCount;
- ULONG PrecisionIndex;
- WCHAR Prefix[4];
- ULONG PrefixIndex;
- ULONG PrefixSize;
- ULONGLONG Remainder;
- BOOL Result;
- IntegerLength = 0;
- Negative = FALSE;
- Precision = Properties->Precision;
- if (Precision == -1) {
- Precision = 1;
- }
- //
- // Get the integer. If it's signed, allow it to be extended to a signed
- // long long (as a signed char is probably just sitting as 0x0000...00FF).
- //
- if (Properties->Unsigned == FALSE) {
- switch (Properties->IntegerSize) {
- case sizeof(CHAR):
- Integer = (CHAR)Integer;
- break;
- case sizeof(SHORT):
- Integer = (SHORT)Integer;
- break;
- case sizeof(LONG):
- Integer = (LONG)Integer;
- break;
- default:
- break;
- }
- }
- //
- // If the integer is zero and a zero length precision was explicitly
- // asked for, print no characters.
- //
- if ((Integer == 0) && (Precision == 0)) {
- return TRUE;
- }
- //
- // If the integer is signed and negative, make it positive.
- //
- if ((Properties->Unsigned == FALSE) && ((LONGLONG)Integer < 0)) {
- Negative = TRUE;
- Integer = -Integer;
- }
- //
- // Convert the integer into a reversed string.
- //
- RtlZeroMemory(LocalBuffer, sizeof(LocalBuffer));
- do {
- //
- // Get the least significant digit.
- //
- NextInteger = RtlDivideUnsigned64(Integer,
- Properties->Radix,
- &Remainder);
- Character = (WCHAR)Remainder;
- if (Character > 9) {
- if (Properties->PrintUpperCase != FALSE) {
- Character = Character - 10 + L'A';
- } else {
- Character = Character - 10 + L'a';
- }
- } else {
- Character += L'0';
- }
- //
- // Write out the character.
- //
- LocalBuffer[IntegerLength] = Character;
- IntegerLength += 1;
- //
- // Use the divided integer to get the next least significant digit.
- //
- Integer = NextInteger;
- } while (Integer > 0);
- //
- // Reverse the integer string.
- //
- RtlStringReverseWide(LocalBuffer, LocalBuffer + IntegerLength);
- //
- // Figure out what kind of decorations can go on the integer. There could
- // be up to 1 character for the sign ('+', '-', or ' '), and up to two for
- // the radix ('0x').
- //
- PrefixSize = 0;
- if ((Properties->Unsigned == FALSE) && (Negative != FALSE)) {
- Prefix[PrefixSize] = L'-';
- PrefixSize += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix[PrefixSize] = L'+';
- PrefixSize += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix[PrefixSize] = L' ';
- PrefixSize += 1;
- }
- if (Properties->PrintRadix != FALSE) {
- if (Properties->Radix == 8) {
- if (LocalBuffer[0] != L'0') {
- Prefix[PrefixSize] = L'0';
- PrefixSize += 1;
- }
- } else if (Properties->Radix == 16) {
- Prefix[PrefixSize] = L'0';
- PrefixSize += 1;
- if (Properties->PrintUpperCase != 0) {
- Prefix[PrefixSize] = L'X';
- } else {
- Prefix[PrefixSize] = L'x';
- }
- PrefixSize += 1;
- }
- }
- //
- // Also remember if there are additional precision digits that will need to
- // go on the number.
- //
- PrecisionCount = 0;
- if (IntegerLength < Precision) {
- PrecisionCount = Precision - IntegerLength;
- }
- //
- // If the field width is bigger than the integer, there will need to be
- // some field spacing characters.
- //
- FieldCount = 0;
- if (IntegerLength + PrefixSize + PrecisionCount < Properties->FieldWidth) {
- FieldCount = Properties->FieldWidth -
- (IntegerLength + PrefixSize + PrecisionCount);
- }
- //
- // Everything's ready, start writing out the number to the destination. If
- // the field is not left justified or leading zeros are supposed to be
- // printed, start with the extra field width.
- //
- if ((Properties->LeftJustified == FALSE) ||
- (Properties->PrintLeadingZeroes != FALSE)) {
- //
- // If the field is leading zero padding, then the prefix needs to go
- // first, otherwise -0001 would look like 00-1.
- //
- Character = L' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = L'0';
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context,
- Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Zero out the prefix size so it won't be written again.
- //
- PrefixSize = 0;
- }
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, Character);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- FieldCount = 0;
- }
- //
- // Now write the prefix, followed by the precision leading zeroes,
- // followed by the integer itself.
- //
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- for (PrecisionIndex = 0;
- PrecisionIndex < PrecisionCount;
- PrecisionIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, L'0');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- for (LocalIndex = 0; LocalIndex < IntegerLength; LocalIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, LocalBuffer[LocalIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Finally, if there are still field characters to be spit out, print them.
- // They must be spaces, as there can't be leading zeroes on the end.
- //
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- ULONG
- RtlpPrintDoubleWide (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- )
- /*++
- Routine Description:
- This routine prints a double to the destination given the style
- properties.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- DestinationSize - Supplies the size of the destination buffer. If NULL was
- passed as the Destination argument, then this argument is ignored.
- Value - Supplies a pointer to the value to convert to a string.
- Properties - Supplies the style characteristics to use when printing this
- integer.
- Return Value:
- Returns the length of the final string after the format conversion has
- completed. The length will be returned even if NULL is passed as the
- destination.
- --*/
- {
- WCHAR Character;
- LONG CurrentExponent;
- WCHAR Digit;
- LONG DigitCount;
- LONG Exponent;
- WCHAR ExponentCharacter;
- ULONG ExponentIndex;
- WCHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
- ULONG FieldCount;
- ULONG FieldIndex;
- WCHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- PWSTR NonNumberString;
- ULONG NumberLength;
- DOUBLE_PARTS Parts;
- LONG Precision;
- LONG PrecisionIndex;
- WCHAR Prefix;
- BOOL PrintExponent;
- BOOL Result;
- double RoundingAmount;
- LONG SignificantDigits;
- double TenPower;
- NumberLength = 0;
- Negative = FALSE;
- Parts.Double = Value;
- Precision = Properties->Precision;
- if (Precision == -1) {
- Precision = DEFAULT_FLOAT_PRECISION;
- }
- if ((Properties->SignificantDigitPrecision != FALSE) && (Precision == 0)) {
- Precision = 1;
- }
- Prefix = 0;
- //
- // Handle NaN and the infinities.
- //
- if ((Parts.Ulong.High & (~DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) >=
- NAN_HIGH_WORD) {
- //
- // NaN is the only value that doesn't equal itself.
- //
- if (Value != Value) {
- if (Properties->PrintUpperCase != FALSE) {
- NonNumberString = L"NAN";
- } else {
- NonNumberString = L"nan";
- }
- //
- // Also handle positive and negative infinity.
- //
- } else {
- if (Properties->PrintUpperCase != FALSE) {
- NonNumberString = L"INF";
- } else {
- NonNumberString = L"inf";
- }
- if (Value < 0) {
- Negative = TRUE;
- }
- }
- //
- // Create a string in the local buffer containing a sign (maybe) and
- // the weird string.
- //
- LocalIndex = 0;
- if (Negative != FALSE) {
- LocalBuffer[LocalIndex] = L'-';
- LocalIndex += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- LocalBuffer[LocalIndex] = L'+';
- LocalIndex += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- LocalBuffer[LocalIndex] = L' ';
- LocalIndex += 1;
- }
- RtlStringCopyWide(LocalBuffer + LocalIndex,
- NonNumberString,
- sizeof(LocalBuffer) - LocalIndex);
- Result = RtlpPrintStringWide(Context,
- LocalBuffer,
- Properties->FieldWidth,
- Properties->Precision,
- Properties->LeftJustified,
- FALSE);
- return Result;
- }
- //
- // Use a special routine for hex formats.
- //
- if (Properties->Radix == 16) {
- return RtlpPrintHexDoubleWide(Context, Value, Properties);
- }
- //
- // If the value is negative, make it positive.
- //
- if ((Parts.Ulong.High & (DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) != 0) {
- Negative = TRUE;
- Value = -Value;
- }
- //
- // Get the base 10 exponent of the value to determine whether or not to
- // print the exponent.
- //
- Exponent = RtlpGetDoubleBase10Exponent(Value, &TenPower);
- RoundingAmount = 0.5;
- //
- // Figure out whether or not to print the exponent. If not explicitly
- // specified, print it out if the exponent is less than -4 or greater than
- // the precision.
- //
- PrintExponent = Properties->ScientificFormat;
- if ((PrintExponent == FALSE) && (Properties->FloatFormat == FALSE)) {
- if ((Exponent < SCIENTIFIC_NOTATION_AUTO_LOWER_LIMIT) ||
- (Exponent >= Precision)) {
- PrintExponent = TRUE;
- }
- }
- DigitCount = 0;
- if (Value != 0.0) {
- //
- // In scientific notation or with significant digit based precision,
- // the rounding amount should be adjusted by the exponent.
- //
- if ((PrintExponent != FALSE) ||
- (Properties->SignificantDigitPrecision != FALSE)) {
- RoundingAmount /= TenPower;
- //
- // Scoot the rounding amount up by one because the loop below is
- // going to go one too far because it's not taking into account
- // the integral digit as a precision digit.
- //
- if (Properties->SignificantDigitPrecision != FALSE) {
- RoundingAmount *= 10.0;
- }
- }
- //
- // Figure out the rounding amount to add for the proper precision.
- //
- for (PrecisionIndex = 0;
- PrecisionIndex < Precision;
- PrecisionIndex += 1) {
- RoundingAmount *= 0.1;
- }
- Value += RoundingAmount;
- //
- // Normalize the value into the range 1 to 10 to take the rounding
- // amount into account.
- //
- Value = Value * TenPower;
- //
- // The rounding could have bumped it up by a power of 10 (ie 0.99999999
- // rounding to 1.000000, so adjust for that if needed.
- //
- if ((LONG)Value > 9) {
- Value *= 0.1;
- Exponent += 1;
- }
- //
- // Convert this batch of numbers into characters, not worrying about
- // the decimal point.
- //
- while ((Value != 0.0) && (DigitCount < MAX_DOUBLE_DIGITS_SIZE)) {
- LocalBuffer[DigitCount] = (LONG)Value + L'0';
- DigitCount += 1;
- Value = (Value - (double)(LONG)Value) * 10.0;
- }
- //
- // If significant digits matter, chop the digits down to the precision.
- // This lops off any digits that were added solely by the rounding
- // value.
- //
- if (Properties->SignificantDigitPrecision != FALSE) {
- ASSERT(Precision > 0);
- if (DigitCount > Precision) {
- DigitCount = Precision;
- }
- }
- //
- // Remove any zero characters on the end.
- //
- while ((DigitCount > 1) && (LocalBuffer[DigitCount - 1] == L'0')) {
- DigitCount -= 1;
- }
- }
- //
- // Figure out what kind of decorations can go on the integer. There could
- // be up to 1 character for the sign ('+', '-', or ' ').
- //
- if (Negative != FALSE) {
- Prefix = L'-';
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix = L'+';
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix = L' ';
- }
- //
- // If printing with significant digit precision, then the number of
- // significant digits is capped to the precision, and the precision
- // is capped to the number of significant digits. So %.4g with 0.01 prints
- // 0.01, and %.4g with 0.0123456 prints 0.1235.
- //
- SignificantDigits = DigitCount;
- if (Properties->SignificantDigitPrecision != FALSE) {
- if (SignificantDigits > Precision) {
- SignificantDigits = Precision;
- }
- if (Precision > SignificantDigits) {
- Precision = SignificantDigits;
- //
- // For a number like 100, there's only one significant digit, but
- // a precision of 3 indicates that all three digits should be
- // printed.
- //
- if ((PrintExponent == FALSE) && ((Exponent + 1) > Precision)) {
- Precision = Exponent + 1;
- }
- if (Precision == 0) {
- Precision = 1;
- }
- }
- }
- NumberLength = Precision;
- //
- // Figure out if a radix character is going to come out of here.
- //
- if (Properties->PrintRadix != FALSE) {
- NumberLength += 1;
- } else if (Properties->SignificantDigitPrecision != FALSE) {
- if (PrintExponent != FALSE) {
- if (Precision > 1) {
- NumberLength += 1;
- }
- } else {
- //
- // A radix character is printed if the number of significant digits
- // (capped to the precision) is greater than the number of integral
- // digits. For example, 10.1 has 3 significant digits, only 2 of
- // which are integral, so any precision greater than 2 causes the
- // radix to be printed. Anything not in scientific notation with
- // a negative exponent also has a radix.
- //
- if ((Exponent < 0) || ((Exponent + 1) - SignificantDigits < 0)) {
- NumberLength += 1;
- }
- }
- } else if (Precision != 0) {
- NumberLength += 1;
- }
- //
- // Figure out the total length of the number.
- //
- if (PrintExponent != FALSE) {
- //
- // Add extras for the exponent character, sign, and (at least) two
- // exponent digits.
- //
- NumberLength += 4;
- //
- // If the precision only represents the fractional part, add one more
- // for the integer portion.
- //
- if (Properties->SignificantDigitPrecision == FALSE) {
- NumberLength += 1;
- }
- //
- // Figure out how wide the exponent is. Negative exponents look like
- // 1e-01.
- //
- if (Exponent < 0) {
- if (Exponent <= -100) {
- NumberLength += 1;
- if (Exponent <= -1000) {
- NumberLength += 1;
- }
- }
- } else {
- if (Exponent >= 100) {
- NumberLength += 1;
- if (Exponent >= 1000) {
- NumberLength += 1;
- }
- }
- }
- //
- // This is the regular float format where all the digits are printed.
- //
- } else {
- //
- // If the exponent is not negative, then the number of digits before
- // a radix character is the exponent.
- //
- if (Exponent >= 0) {
- if (Properties->SignificantDigitPrecision == FALSE) {
- NumberLength += Exponent + 1;
- }
- //
- // The exponent is negative, so add 1 for the zero.
- //
- } else {
- NumberLength += 1;
- //
- // If the precision is the fractional part, that's all that needs
- // to be done. If the precision is the number of significant digits,
- // add the exponent to the precision so that the precision again
- // just represents the fractional part.
- //
- if (Properties->SignificantDigitPrecision != FALSE) {
- Precision += (-Exponent) - 1;
- NumberLength += (-Exponent) - 1;
- }
- }
- }
- if (Prefix != 0) {
- NumberLength += 1;
- }
- //
- // If the field width is bigger than the integer, there will need to be
- // some field spacing characters.
- //
- FieldCount = 0;
- if (NumberLength < Properties->FieldWidth) {
- FieldCount = Properties->FieldWidth - NumberLength;
- }
- //
- // If the field is left justified or the extra field width is leading
- // zeroes, print the prefix now.
- //
- if ((Properties->LeftJustified != FALSE) ||
- (Properties->PrintLeadingZeroes != FALSE)) {
- if (Prefix != 0) {
- Result = RtlpFormatWriteCharacterWide(Context, Prefix);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Zero out the prefix so it won't be written again.
- //
- Prefix = 0;
- }
- //
- // If the field is not right justified or leading zeros are supposed to be
- // printed, spit out the extra field width.
- //
- if ((Properties->LeftJustified == FALSE) ||
- (Properties->PrintLeadingZeroes != FALSE)) {
- Character = L' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = L'0';
- }
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, Character);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- FieldCount = 0;
- }
- //
- // In the case of a right justified number with no leading zeroes, the
- // extra field width comes before the prefix. So print the prefix now if
- // it has not yet been printed.
- //
- if (Prefix != 0) {
- Result = RtlpFormatWriteCharacterWide(Context, Prefix);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Time to print the number itself.
- //
- LocalIndex = 0;
- if (PrintExponent != FALSE) {
- //
- // Print the first character, always.
- //
- if (DigitCount == 0) {
- Digit = L'0';
- } else {
- Digit = LocalBuffer[LocalIndex];
- ASSERT(Digit != L'0');
- LocalIndex += 1;
- }
- Result = RtlpFormatWriteCharacterWide(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- //
- // If the precision is the number of significant digits, then this
- // guy counts as a significant digit.
- //
- if ((Properties->SignificantDigitPrecision != FALSE) &&
- (Precision != 0)) {
- Precision -= 1;
- }
- //
- // Print the radix character.
- //
- if ((Precision != 0) || (Properties->PrintRadix != FALSE)) {
- Result = RtlpFormatWriteCharacterWide(Context, L'.');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the rest of the desired precision.
- //
- for (PrecisionIndex = 0;
- PrecisionIndex < Precision;
- PrecisionIndex += 1) {
- if (LocalIndex < DigitCount) {
- Digit = LocalBuffer[LocalIndex];
- LocalIndex += 1;
- } else {
- Digit = L'0';
- }
- Result = RtlpFormatWriteCharacterWide(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Determine the exponent character.
- //
- ExponentCharacter = L'e';
- if (Properties->PrintUpperCase != FALSE) {
- ExponentCharacter = L'E';
- }
- //
- // Print the exponent.
- //
- RtlPrintToStringWide(ExponentString,
- MAX_DOUBLE_EXPONENT_SIZE,
- Context->State.Encoding,
- L"%c%+0.2d",
- ExponentCharacter,
- Exponent);
- for (ExponentIndex = 0;
- ExponentIndex < MAX_DOUBLE_EXPONENT_SIZE;
- ExponentIndex += 1) {
- if (ExponentString[ExponentIndex] == '\0') {
- break;
- }
- Result = RtlpFormatWriteCharacterWide(
- Context,
- ExponentString[ExponentIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // This is being printed in non-scientific notation. Could be a lot of
- // zeros here.
- //
- } else {
- if (Exponent >= 0) {
- CurrentExponent = Exponent;
- //
- // Print the integral portion.
- //
- while (CurrentExponent >= 0) {
- if (LocalIndex < DigitCount) {
- Digit = LocalBuffer[LocalIndex];
- LocalIndex += 1;
- } else {
- Digit = L'0';
- }
- Result = RtlpFormatWriteCharacterWide(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- CurrentExponent -= 1;
- //
- // Count this as a precision digit if the precision is the
- // number of significant digits.
- //
- if ((Properties->SignificantDigitPrecision != FALSE) &&
- (Precision != 0)) {
- Precision -= 1;
- }
- }
- //
- // Print the integer part, which is 0.
- //
- } else {
- Result = RtlpFormatWriteCharacterWide(Context, L'0');
- if (Result == FALSE) {
- return FALSE;
- }
- CurrentExponent = -1;
- }
- //
- // Print the radix character.
- //
- if ((Precision != 0) || (Properties->PrintRadix != FALSE)) {
- Result = RtlpFormatWriteCharacterWide(Context, L'.');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print as many digits of precision as are desired. If the precision
- // is significant digits and the exponent is way negative, the
- // precision variable should have already been adjusted above.
- //
- for (PrecisionIndex = 0;
- PrecisionIndex < Precision;
- PrecisionIndex += 1) {
- //
- // If the current exponent has not yet met up with the exponent
- // of the digits, it's a leading zero (something like
- // 0.00000000000000000000000000012345.
- //
- if (CurrentExponent > Exponent) {
- Digit = L'0';
- } else if (LocalIndex < DigitCount) {
- Digit = LocalBuffer[LocalIndex];
- LocalIndex += 1;
- } else {
- Digit = L'0';
- }
- Result = RtlpFormatWriteCharacterWide(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- CurrentExponent -= 1;
- }
- }
- //
- // Finally, if there are still field characters to be spit out, print them.
- // They must be spaces, as there can't be leading zeroes on the end.
- //
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- ULONG
- RtlpPrintHexDoubleWide (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- )
- /*++
- Routine Description:
- This routine prints a double to the destination in hex given the style
- properties.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- DestinationSize - Supplies the size of the destination buffer. If NULL was
- passed as the Destination argument, then this argument is ignored.
- Value - Supplies a pointer to the value to convert to a string.
- Properties - Supplies the style characteristics to use when printing this
- integer.
- Return Value:
- Returns the length of the final string after the format conversion has
- completed. The length will be returned even if NULL is passed as the
- destination.
- --*/
- {
- LONG AbsoluteExponent;
- WCHAR Character;
- WCHAR Digit;
- LONG Exponent;
- WCHAR ExponentCharacter;
- WCHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
- ULONG FieldCount;
- ULONG FieldIndex;
- ULONGLONG HalfWay;
- WCHAR IntegerPortion;
- WCHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- ULONG NumberLength;
- DOUBLE_PARTS Parts;
- LONG Precision;
- ULONG PrecisionIndex;
- WCHAR Prefix[4];
- ULONG PrefixIndex;
- ULONG PrefixSize;
- BOOL Result;
- ULONGLONG RoundingValue;
- ULONGLONG Significand;
- Negative = FALSE;
- Precision = Properties->Precision;
- Parts.Double = Value;
- //
- // If the integer is negative, make it positive.
- //
- if ((Parts.Ulong.High & (DOUBLE_SIGN_BIT >> DOUBLE_HIGH_WORD_SHIFT)) != 0) {
- Negative = TRUE;
- Parts.Double = -Parts.Double;
- }
- Exponent = (Parts.Ulong.High &
- (DOUBLE_EXPONENT_MASK >> DOUBLE_HIGH_WORD_SHIFT)) >>
- (DOUBLE_EXPONENT_SHIFT - DOUBLE_HIGH_WORD_SHIFT);
- Exponent -= DOUBLE_EXPONENT_BIAS;
- AbsoluteExponent = Exponent;
- if (AbsoluteExponent < 0) {
- AbsoluteExponent = -AbsoluteExponent;
- }
- if (Value == 0.0) {
- Exponent = 0;
- AbsoluteExponent = 0;
- Significand = 0;
- IntegerPortion = L'0';
- if (Precision == -1) {
- Precision = 0;
- }
- for (LocalIndex = 0;
- LocalIndex < DOUBLE_SIGNIFICAND_HEX_DIGITS;
- LocalIndex += 1) {
- LocalBuffer[LocalIndex] = L'0';
- }
- } else {
- Significand = Parts.Ulong.Low |
- ((ULONGLONG)(Parts.Ulong.High & DOUBLE_HIGH_VALUE_MASK) <<
- (sizeof(ULONG) * BITS_PER_BYTE));
- //
- // If there's a precision, add a half (8 of 16) to the digit beyond the
- // precision.
- //
- IntegerPortion = L'1';
- if (Precision != -1) {
- HalfWay = 1ULL << (DOUBLE_EXPONENT_SHIFT - 1);
- RoundingValue = HalfWay;
- if (4 * Precision > (sizeof(ULONGLONG) * BITS_PER_BYTE)) {
- RoundingValue = 0;
- } else {
- RoundingValue = RoundingValue >> (4 * Precision);
- }
- Significand += RoundingValue;
- if (Significand >= (1ULL << DOUBLE_EXPONENT_SHIFT)) {
- Significand -= (1ULL << DOUBLE_EXPONENT_SHIFT);
- IntegerPortion += 1;
- }
- }
- //
- // Convert the significand into a hex string.
- //
- ASSERT(MAX_DOUBLE_DIGITS_SIZE >= DOUBLE_SIGNIFICAND_HEX_DIGITS);
- for (LocalIndex = 0;
- LocalIndex < DOUBLE_SIGNIFICAND_HEX_DIGITS;
- LocalIndex += 1) {
- Digit = (Significand >> (LocalIndex * 4)) & 0xF;
- if (Digit < 10) {
- Character = Digit + L'0';
- } else if (Properties->PrintUpperCase != FALSE) {
- Character = Digit + L'A' - 10;
- } else {
- Character = Digit + L'a' - 10;
- }
- LocalBuffer[DOUBLE_SIGNIFICAND_HEX_DIGITS - LocalIndex - 1] =
- Character;
- }
- //
- // Figure out how many significant digits there are if there is no
- // precision.
- //
- if (Precision == -1) {
- Precision = DOUBLE_SIGNIFICAND_HEX_DIGITS;
- while ((Precision - 1 >= 0) &&
- (LocalBuffer[Precision - 1] == L'0')) {
- Precision -= 1;
- }
- }
- }
- //
- // Figure out what kind of decorations can go on the integer. There could
- // be up to 1 character for the sign ('+', '-', or ' '), and up to two for
- // the radix ('0x').
- //
- PrefixSize = 0;
- if (Negative != FALSE) {
- Prefix[PrefixSize] = L'-';
- PrefixSize += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix[PrefixSize] = L'+';
- PrefixSize += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix[PrefixSize] = L' ';
- PrefixSize += 1;
- }
- Prefix[PrefixSize] = L'0';
- PrefixSize += 1;
- if (Properties->PrintUpperCase != 0) {
- Prefix[PrefixSize] = L'X';
- } else {
- Prefix[PrefixSize] = L'x';
- }
- PrefixSize += 1;
- //
- // Figure out the size of the number, which is the integer portion plus
- // the precision, plus one more for a radix character if there was a
- // precision.
- //
- NumberLength = 1 + Precision;
- if ((Properties->PrintRadix != FALSE) || (Precision != 0)) {
- NumberLength += 1;
- }
- //
- // Don't forget about the exponent (the 'p', a sign, and at least one
- // digit).
- //
- NumberLength += 3;
- if (AbsoluteExponent > 10) {
- NumberLength += 1;
- if (AbsoluteExponent > 100) {
- NumberLength += 1;
- if (AbsoluteExponent > 1000) {
- NumberLength += 1;
- }
- }
- }
- ExponentCharacter = L'p';
- if (Properties->PrintUpperCase != FALSE) {
- ExponentCharacter = L'P';
- }
- RtlPrintToStringWide(ExponentString,
- sizeof(ExponentString),
- Context->State.Encoding,
- L"%c%+d",
- ExponentCharacter,
- Exponent);
- //
- // If the field width is bigger than the integer, there will need to be
- // some field spacing characters.
- //
- FieldCount = 0;
- if (NumberLength + PrefixSize < Properties->FieldWidth) {
- FieldCount = Properties->FieldWidth - (NumberLength + PrefixSize);
- }
- //
- // Everything's ready, start writing out the number to the destination. If
- // the field is not left justified or leading zeros are supposed to be
- // printed, start with the extra field width.
- //
- if ((Properties->LeftJustified == FALSE) ||
- (Properties->PrintLeadingZeroes != FALSE)) {
- //
- // If the field is leading zero padding, then the prefix needs to go
- // first, otherwise -0001 would look like 00-1.
- //
- Character = L' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = L'0';
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context,
- Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Zero out the prefix size so it won't be written again.
- //
- PrefixSize = 0;
- }
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, Character);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- FieldCount = 0;
- }
- //
- // Now write the prefix, followed by the precision leading zeroes,
- // followed by the integer itself.
- //
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the integer portion.
- //
- Result = RtlpFormatWriteCharacterWide(Context, IntegerPortion);
- if (Result == FALSE) {
- return FALSE;
- }
- //
- // Print a radix if needed.
- //
- if ((Properties->PrintRadix != FALSE) || (Precision != 0)) {
- Result = RtlpFormatWriteCharacterWide(Context, L'.');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the precision digits.
- //
- for (PrecisionIndex = 0; PrecisionIndex < Precision; PrecisionIndex += 1) {
- if (PrecisionIndex >= DOUBLE_SIGNIFICAND_HEX_DIGITS) {
- Digit = L'0';
- } else {
- Digit = LocalBuffer[PrecisionIndex];
- }
- Result = RtlpFormatWriteCharacterWide(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the exponent.
- //
- RtlpPrintStringWide(Context, ExponentString, 0, -1, FALSE, FALSE);
- //
- // Finally, if there are still field characters to be spit out, print them.
- // They must be spaces, as there can't be leading zeroes on the end.
- //
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- BOOL
- RtlpPrintStringWide (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- )
- /*++
- Routine Description:
- This routine prints a string destination buffer given the style properties.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- String - Supplies a pointer to the string to print.
- FieldWidth - Supplies the width of the string or character field. If the
- argument doesn't fill up this space, it will be padded with spaces.
- Precision - Supplies the precision of the string (the maximum number of
- characters to print). Supply -1 to print the whole string.
- LeftJustified - Supplies a flag indicating whether or not the character in
- the string is to be left justfied.
- Character - Supplies a boolean indicating that this is a character rather
- than a full string.
- Return Value:
- TRUE if all characters were written to the destination.
- FALSE if the destination crapped out before all characters could be written.
- --*/
- {
- ULONG PaddingIndex;
- ULONG PaddingLength;
- BOOL Result;
- ULONG StringLength;
- if (String == NULL) {
- String = L"(null)";
- }
- if (Character != FALSE) {
- StringLength = 1;
- } else {
- StringLength = RtlStringLengthWide(String);
- }
- if ((Precision >= 0) && (StringLength > Precision)) {
- StringLength = Precision;
- }
- //
- // Find out how much padding to add to the field.
- //
- PaddingLength = 0;
- if (FieldWidth > StringLength) {
- PaddingLength = FieldWidth - StringLength;
- }
- PaddingIndex = PaddingLength;
- //
- // Pad left, if required.
- //
- if (LeftJustified == FALSE) {
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- }
- //
- // Copy the string.
- //
- while (StringLength != 0) {
- Result = RtlpFormatWriteCharacterWide(Context, *String);
- if (Result == FALSE) {
- return FALSE;
- }
- String += 1;
- StringLength -= 1;
- }
- //
- // Pad right, if required.
- //
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- return TRUE;
- }
- BOOL
- RtlpPrintByteStringWide (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- )
- /*++
- Routine Description:
- This routine prints a byte-based string to a wide print destination.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- String - Supplies a pointer to the string to print.
- FieldWidth - Supplies the width of the string or character field. If the
- argument doesn't fill up this space, it will be padded with spaces.
- Precision - Supplies the precision of the string (the maximum number of
- characters to print). Supply -1 to print the whole string.
- LeftJustified - Supplies a flag indicating whether or not the character in
- the string is to be left justfied.
- Character - Supplies a boolean indicating that this is a character rather
- than a full string.
- Return Value:
- TRUE if all characters were written to the destination.
- FALSE if the destination crapped out before all characters could be written.
- --*/
- {
- ULONG PaddingIndex;
- ULONG PaddingLength;
- BOOL Result;
- KSTATUS Status;
- ULONG StringLength;
- WCHAR WideCharacter;
- if (String == NULL) {
- String = "(null)";
- }
- if (Character != FALSE) {
- StringLength = 1;
- } else {
- StringLength = RtlStringLength(String);
- }
- //
- // Find out how much padding to add to the field.
- //
- PaddingLength = 0;
- if (FieldWidth > StringLength) {
- PaddingLength = FieldWidth - StringLength;
- }
- PaddingIndex = PaddingLength;
- //
- // Pad left, if required.
- //
- if (LeftJustified == FALSE) {
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- }
- //
- // Copy the string by converting bytes into wide characters.
- //
- while (StringLength != 0) {
- Status = RtlConvertMultibyteCharacterToWide(&String,
- &StringLength,
- &WideCharacter,
- &(Context->State));
- if (!KSUCCESS(Status)) {
- return FALSE;
- }
- Result = RtlpFormatWriteCharacterWide(Context, WideCharacter);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Pad right, if required.
- //
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacterWide(Context, L' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- return TRUE;
- }
- BOOL
- RtlpFormatWriteCharacterWide (
- PPRINT_FORMAT_CONTEXT Context,
- WCHAR Character
- )
- /*++
- Routine Description:
- This routine writes a wide character to the print format destination.
- Arguments:
- Context - Supplies a pointer to the print format context.
- Character - Supplies the character to write.
- Return Value:
- TRUE if the character was written.
- FALSE on failure.
- --*/
- {
- BOOL Result;
- Result = Context->U.WriteWideCharacter(Character, Context);
- if (Result == FALSE) {
- return FALSE;
- }
- Context->CharactersWritten += 1;
- return TRUE;
- }
- ULONGLONG
- RtlpGetPositionalArgumentWide (
- PWSTR Format,
- ULONG ArgumentNumber,
- va_list *Arguments
- )
- /*++
- Routine Description:
- This routine attempts to get a positional argument by rescanning the
- string from the beginning and counting up all arguments less than it. This
- is more than a little slow (O(N^2) for each argument), but it doesn't
- require allocations, which is nice for a library like this shared between
- several environments.
- Arguments:
- Format - Supplies the format string.
- ArgumentNumber - Supplies the argument number to retrieve.
- Arguments - Supplies a pointer to a VA list initialized at the beginning
- of the printf arguments. This list will be copied.
- Return Value:
- Returns the argument.
- --*/
- {
- ULONGLONG Argument;
- ULONG ArgumentIndex;
- va_list ArgumentsCopy;
- ULONG ArgumentSize;
- ASSERT(ArgumentNumber != 0);
- va_copy(ArgumentsCopy, *Arguments);
- for (ArgumentIndex = 1;
- ArgumentIndex < ArgumentNumber;
- ArgumentIndex += 1) {
- //
- // Get the size of this argument.
- //
- ArgumentSize = RtlpGetPositionalArgumentSizeWide(Format, ArgumentIndex);
- switch (ArgumentSize) {
- case 0:
- break;
- case sizeof(CHAR):
- Argument = va_arg(ArgumentsCopy, INT);
- break;
- case sizeof(SHORT):
- Argument = va_arg(ArgumentsCopy, INT);
- break;
- case sizeof(LONG):
- Argument = va_arg(ArgumentsCopy, LONG);
- break;
- case sizeof(LONGLONG):
- Argument = va_arg(ArgumentsCopy, LONGLONG);
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- }
- //
- // Now the important one, get the size of the specified argument.
- //
- Argument = 0;
- ArgumentSize = RtlpGetPositionalArgumentSizeWide(Format, ArgumentNumber);
- switch (ArgumentSize) {
- case 0:
- break;
- case sizeof(CHAR):
- Argument = (UCHAR)va_arg(ArgumentsCopy, INT);
- break;
- case sizeof(SHORT):
- Argument = (USHORT)va_arg(ArgumentsCopy, INT);
- break;
- case sizeof(LONG):
- Argument = va_arg(ArgumentsCopy, LONG);
- break;
- case sizeof(LONGLONG):
- Argument = va_arg(ArgumentsCopy, LONGLONG);
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- va_end(ArgumentsCopy);
- return Argument;
- }
- ULONG
- RtlpGetPositionalArgumentSizeWide (
- PWSTR Format,
- ULONG ArgumentNumber
- )
- /*++
- Routine Description:
- This routine scans through the format string to determine the size of the
- given positional argument.
- Arguments:
- Format - Supplies the format string.
- ArgumentNumber - Supplies the argument number to retrieve.
- Return Value:
- Returns the size of the argument.
- 0 if the given positional argument was not found.
- --*/
- {
- ULONG ArgumentSize;
- ULONG CurrentArgumentSize;
- LONGLONG Integer;
- ULONG Position;
- ULONG RemainingSize;
- KSTATUS Status;
- ArgumentSize = 0;
- while (*Format != WIDE_STRING_TERMINATOR) {
- if (*Format != CONVERSION_CHARACTER) {
- Format += 1;
- continue;
- }
- Position = 0;
- Format += 1;
- //
- // If there's a non-zero digit, grab it. It could be the position or
- // field width.
- //
- if ((*Format >= L'1') && (*Format <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&Format,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- return 0;
- }
- if (*Format == POSITIONAL_ARGUMENT) {
- Position = (ULONG)Integer;
- Format += 1;
- }
- }
- //
- // Get past any flags.
- //
- while (TRUE) {
- if ((*Format != THOUSANDS_GROUPING) &&
- (*Format != LEFT_JUSTIFIED) &&
- (*Format != SPACE_FOR_PLUS) &&
- (*Format != PRINT_SIGN) &&
- (*Format != PRINT_RADIX_IDENTIFIER) &&
- (*Format != PRINT_LEADING_ZEROES)) {
- break;
- }
- Format += 1;
- }
- //
- // Process a field width. It could have already been sucked in, be a
- // decimal, be a star, or be a star followed by a position and a dollar
- // sign.
- //
- if (*Format == FIELD_IN_ARGUMENT) {
- Format += 1;
- if ((*Format >= L'1') && (*Format <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&Format,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- return 0;
- }
- if (*Format != POSITIONAL_ARGUMENT) {
- return 0;
- }
- Format += 1;
- //
- // This is a positional argument and its size is int.
- //
- if ((Integer == ArgumentNumber) &&
- (ArgumentSize < sizeof(INT))) {
- ArgumentSize = sizeof(INT);
- }
- }
- } else if ((*Format >= L'1') && (*Format <= L'9')) {
- RemainingSize = -1;
- RtlStringScanIntegerWide(&Format,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- }
- //
- // If there's a dot, then the precision follows. Like the field width,
- // it could either be a decimal, a star, or a star plus a position and a
- // dollar sign.
- //
- if (*Format == PRECISION_SPECIFIED) {
- Format += 1;
- if (*Format == FIELD_IN_ARGUMENT) {
- Format += 1;
- if ((*Format >= L'1') && (*Format <= L'9')) {
- RemainingSize = -1;
- Status = RtlStringScanIntegerWide(&Format,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- return 0;
- }
- if (*Format != POSITIONAL_ARGUMENT) {
- return 0;
- }
- Format += 1;
- //
- // This is a positional argument and its size is int.
- //
- if ((Integer == ArgumentNumber) &&
- (ArgumentSize < sizeof(INT))) {
- ArgumentSize = sizeof(INT);
- }
- }
- } else if ((*Format >= L'1') && (*Format <= L'9')) {
- RemainingSize = -1;
- RtlStringScanIntegerWide(&Format,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- }
- }
- //
- // Look for the length modifiers: hh, h, l, ll, j, z, t, L, I64.
- //
- CurrentArgumentSize = sizeof(INT);
- if (*Format == FORMAT_SHORT) {
- Format += 1;
- CurrentArgumentSize = sizeof(SHORT);
- if (*Format == FORMAT_SHORT) {
- Format += 1;
- CurrentArgumentSize = sizeof(CHAR);
- }
- } else if (*Format == FORMAT_LONG) {
- Format += 1;
- CurrentArgumentSize = sizeof(LONG);
- if (*Format == FORMAT_LONG) {
- Format += 1;
- CurrentArgumentSize = sizeof(LONGLONG);
- }
- } else if (*Format == FORMAT_INTMAX) {
- Format += 1;
- CurrentArgumentSize = sizeof(intmax_t);
- } else if (*Format == FORMAT_SIZE_T) {
- Format += 1;
- CurrentArgumentSize = sizeof(size_t);
- } else if (*Format == FORMAT_LONG_DOUBLE) {
- Format += 1;
- CurrentArgumentSize = sizeof(long double);
- } else if ((*Format == FORMAT_LONGLONG_START) &&
- (*(Format + 1) == L'6') &&
- (*(Format + 1) == L'4')) {
- Format += 3;
- CurrentArgumentSize = sizeof(LONGLONG);
- }
- //
- // Now, finally, get the conversion specifier.
- //
- if ((*Format == FORMAT_POINTER) || (*Format == FORMAT_BYTES_PRINTED)) {
- CurrentArgumentSize = sizeof(PVOID);
- } else if (*Format == FORMAT_LONG_CHARACTER) {
- CurrentArgumentSize = sizeof(SHORT);
- } else if (*Format == FORMAT_CHARACTER) {
- CurrentArgumentSize = sizeof(CHAR);
- } else if ((*Format == FORMAT_LONG_STRING) ||
- (*Format == FORMAT_STRING)) {
- CurrentArgumentSize = sizeof(PVOID);
- } else if (*Format == FORMAT_NONE) {
- CurrentArgumentSize = 0;
- }
- //
- // If the argument is the right position, up the argument size.
- //
- if ((Position == ArgumentNumber) &&
- (CurrentArgumentSize > ArgumentSize)) {
- ArgumentSize = CurrentArgumentSize;
- }
- Format += 1;
- }
- return ArgumentSize;
- }
- BOOL
- RtlpStringFormatWriteCharacterWide (
- WCHAR Character,
- PPRINT_FORMAT_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine writes a character to the string during a printf-style
- formatting operation.
- Arguments:
- Character - Supplies the character to be written.
- Context - Supplies a pointer to the printf-context.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PWSTR String;
- String = Context->Context;
- if ((String != NULL) && (Context->CharactersWritten < Context->Limit)) {
- String[Context->CharactersWritten] = Character;
- }
- return TRUE;
- }
|