1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- print.c
- Abstract:
- This module implements common printf-like routines in the kernel.
- Author:
- Evan Green 24-Jul-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "rtlp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define CONVERSION_CHARACTER '%'
- #define POSITIONAL_ARGUMENT '$'
- #define FIELD_IN_ARGUMENT '*'
- #define THOUSANDS_GROUPING '\''
- #define LEFT_JUSTIFIED '-'
- #define SPACE_FOR_PLUS ' '
- #define PRINT_SIGN '+'
- #define PRINT_RADIX_IDENTIFIER '#'
- #define PRINT_LEADING_ZEROES '0'
- #define PRECISION_SPECIFIED '.'
- #define FORMAT_SHORT 'h'
- #define FORMAT_LONG 'l'
- #define FORMAT_INTMAX 'j'
- #define FORMAT_SIZE_T 'z'
- #define FORMAT_PTRDIFF_T 't'
- #define FORMAT_LONG_DOUBLE 'L'
- #define FORMAT_DOUBLE_HEX 'a'
- #define FORMAT_DOUBLE_HEX_CAPITAL 'A'
- #define FORMAT_FLOAT 'f'
- #define FORMAT_FLOAT_CAPITAL 'F'
- #define FORMAT_SCIENTIFIC 'e'
- #define FORMAT_SCIENTIFIC_CAPITAL 'E'
- #define FORMAT_DOUBLE 'g'
- #define FORMAT_DOUBLE_CAPITAL 'G'
- #define FORMAT_CHARACTER 'c'
- #define FORMAT_LONG_CHARACTER 'C'
- #define FORMAT_STRING 's'
- #define FORMAT_LONG_STRING 'S'
- #define FORMAT_BYTES_PRINTED 'n'
- #define FORMAT_POINTER 'p'
- #define FORMAT_NONE '%'
- #define FORMAT_DECIMAL 'd'
- #define FORMAT_DECIMAL2 'i'
- #define FORMAT_OCTAL 'o'
- #define FORMAT_UNSIGNED 'u'
- #define FORMAT_HEX 'x'
- #define FORMAT_HEX_CAPITAL 'X'
- #define FORMAT_LONGLONG_START 'I'
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOL
- RtlpConvertFormatSpecifier (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR Format,
- PULONG Index,
- va_list *Arguments
- );
- ULONG
- RtlpPrintInteger (
- PPRINT_FORMAT_CONTEXT Context,
- ULONGLONG Integer,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- ULONG
- RtlpPrintDouble (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- ULONG
- RtlpPrintHexDouble (
- PPRINT_FORMAT_CONTEXT Context,
- double Value,
- PPRINT_FORMAT_PROPERTIES Properties
- );
- BOOL
- RtlpPrintString (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- );
- BOOL
- RtlpPrintWideString (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- );
- BOOL
- RtlpFormatWriteCharacter (
- PPRINT_FORMAT_CONTEXT Context,
- CHAR Character
- );
- ULONGLONG
- RtlpGetPositionalArgument (
- PSTR Format,
- ULONG ArgumentNumber,
- va_list *Arguments
- );
- ULONG
- RtlpGetPositionalArgumentSize (
- PSTR Format,
- ULONG ArgumentNumber
- );
- BOOL
- RtlpStringFormatWriteCharacter (
- CHAR Character,
- PPRINT_FORMAT_CONTEXT Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- RTL_API
- ULONG
- RtlPrintToString (
- PSTR Destination,
- ULONG DestinationSize,
- CHARACTER_ENCODING Encoding,
- PSTR Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a formatted 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 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 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 = RtlFormatString(Destination,
- DestinationSize,
- Encoding,
- Format,
- ArgumentList);
- va_end(ArgumentList);
- return Result;
- }
- RTL_API
- ULONG
- RtlFormatString (
- PSTR Destination,
- ULONG DestinationSize,
- CHARACTER_ENCODING Encoding,
- PSTR Format,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine converts a printf-style 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 when converting any
- wide strings or characters.
- 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.WriteCharacter = RtlpStringFormatWriteCharacter;
- Context.Context = Destination;
- if (DestinationSize != 0) {
- Context.Limit = DestinationSize - 1;
- }
- RtlInitializeMultibyteState(&(Context.State), Encoding);
- RtlFormat(&Context, Format, ArgumentList);
- CharactersWritten = Context.CharactersWritten;
- if (DestinationSize != 0) {
- if (Context.CharactersWritten > Context.Limit) {
- Context.CharactersWritten = Context.Limit;
- }
- Context.Limit = DestinationSize;
- }
- RtlpFormatWriteCharacter(&Context, STRING_TERMINATOR);
- return CharactersWritten + 1;
- }
- RTL_API
- BOOL
- RtlFormat (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR Format,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine converts a printf-style 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.WriteCharacter != NULL) &&
- (Context->CharactersWritten == 0) &&
- (RtlIsCharacterEncodingSupported(Context->State.Encoding) != FALSE));
- if (Format == NULL) {
- Format = "(null)";
- }
- //
- // Copy each character to the destination, handling formats along the way.
- //
- Result = TRUE;
- Index = 0;
- va_copy(ArgumentListCopy, ArgumentList);
- while (Format[Index] != STRING_TERMINATOR) {
- if (Format[Index] == CONVERSION_CHARACTER) {
- Result = RtlpConvertFormatSpecifier(Context,
- Format,
- &Index,
- &ArgumentListCopy);
- if (Result == FALSE) {
- goto FormatEnd;
- }
- } else {
- Result = RtlpFormatWriteCharacter(Context, Format[Index]);
- if (Result == FALSE) {
- goto FormatEnd;
- }
- Index += 1;
- }
- }
- FormatEnd:
- va_end(ArgumentListCopy);
- return Result;
- }
- LONG
- RtlpGetDoubleBase10Exponent (
- double Value,
- double *InversePowerOfTen
- )
- /*++
- Routine Description:
- This routine gets the base 10 exponent of the given double.
- Arguments:
- Value - Supplies the value to get the base 10 exponent of.
- InversePowerOfTen - Supplies a pointer where the power of 10 correponding
- to the returned exponent will be returned.
- Return Value:
- Returns the base 10 exponent of the given value.
- --*/
- {
- LONG Base2Exponent;
- LONG CurrentExponent;
- LONG Exponent;
- ULONG ExponentMask;
- ULONG ExponentShift;
- DOUBLE_PARTS Parts;
- double TenPower;
- ExponentMask = DOUBLE_EXPONENT_MASK >> DOUBLE_HIGH_WORD_SHIFT;
- ExponentShift = DOUBLE_EXPONENT_SHIFT - DOUBLE_HIGH_WORD_SHIFT;
- if (Value == 0.0) {
- *InversePowerOfTen = 1.0;
- return 0;
- }
- Parts.Double = Value;
- Base2Exponent = ((Parts.Ulong.High & ExponentMask) >> ExponentShift) -
- DOUBLE_EXPONENT_BIAS;
- //
- // Get the base 10 exponent by multiplying by log10(2).
- //
- Exponent = (LONG)((double)Base2Exponent * LOG2) + 1;
- //
- // Make a double with the inverse of that power of 10 to get the value in
- // the range of 1 to 10.
- //
- CurrentExponent = 0;
- TenPower = 1.0;
- if (Exponent > 0) {
- while (CurrentExponent + 10 <= Exponent) {
- TenPower *= 1.0E-10;
- CurrentExponent += 10;
- }
- while (CurrentExponent + 1 <= Exponent) {
- TenPower *= 0.1;
- CurrentExponent += 1;
- }
- } else {
- while (CurrentExponent - 10 >= Exponent) {
- TenPower *= 1.0E10;
- CurrentExponent -= 10;
- }
- while (CurrentExponent - 1 >= Exponent) {
- TenPower *= 10.0;
- CurrentExponent -= 1;
- }
- }
- //
- // Normalize the value.
- //
- Value *= TenPower;
- //
- // Skip any leading zeros.
- //
- while ((Value != 0) && ((LONG)Value == 0)) {
- Value *= 10.0;
- Exponent -= 1;
- TenPower *= 10.0;
- }
- *InversePowerOfTen = TenPower;
- return Exponent;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOL
- RtlpConvertFormatSpecifier (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR Format,
- PULONG Index,
- va_list *Arguments
- )
- /*++
- Routine Description:
- This routine converts one printf-style format specifier to its 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
- '%' 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 CharacterArgument;
- PSTR 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;
- CHAR Specifier;
- KSTATUS Status;
- PSTR StringArgument;
- WCHAR WideCharacterArgument;
- PWSTR WideStringArgument;
- 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 ConvertFormatSpecifierEnd;
- }
- CurrentFormat += 1;
- Position = 0;
- //
- // If there's a non-zero digit, grab it. It could be the position or field
- // width.
- //
- if ((*CurrentFormat >= '1') && (*CurrentFormat <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Integer = 0;
- }
- if (*CurrentFormat == POSITIONAL_ARGUMENT) {
- if (Integer < 0) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- 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 >= '1') && (*CurrentFormat <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- if (*CurrentFormat != POSITIONAL_ARGUMENT) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- CurrentFormat += 1;
- Properties.FieldWidth = (INT)RtlpGetPositionalArgument(
- Format,
- (ULONG)Integer,
- Arguments);
- } else {
- Properties.FieldWidth = va_arg(*Arguments, INT);
- }
- } else if ((*CurrentFormat >= '1') && (*CurrentFormat <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- 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 >= '0') && (*CurrentFormat <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if ((!KSUCCESS(Status)) || (Integer < 0)) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- if (*CurrentFormat != POSITIONAL_ARGUMENT) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- CurrentFormat += 1;
- Properties.Precision = (INT)RtlpGetPositionalArgument(
- Format,
- (ULONG)Integer,
- Arguments);
- } else {
- Properties.Precision = va_arg(*Arguments, INT);
- }
- } else if ((*CurrentFormat >= '0') && (*CurrentFormat <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&CurrentFormat,
- &RemainingSize,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(Status)) {
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- 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_PTRDIFF_T) {
- CurrentFormat += 1;
- Properties.IntegerSize = sizeof(UINT);
- } else if (*CurrentFormat == FORMAT_LONG_DOUBLE) {
- CurrentFormat += 1;
- LongDoubleSpecified = TRUE;
- } 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:
- RtlResetMultibyteState(&(Context->State));
- if (Position != 0) {
- WideCharacterArgument = (WCHAR)RtlpGetPositionalArgument(
- Format,
- Position,
- Arguments);
- } else {
- WideCharacterArgument = (WCHAR)va_arg(*Arguments, INT);
- }
- Result = RtlpPrintWideString(Context,
- &WideCharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- break;
- case FORMAT_CHARACTER:
- if (Position != 0) {
- CharacterArgument = (UCHAR)RtlpGetPositionalArgument(Format,
- Position,
- Arguments);
- } else {
- CharacterArgument = (CHAR)va_arg(*Arguments, INT);
- }
- Result = RtlpPrintString(Context,
- &CharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- break;
- case FORMAT_LONG_STRING:
- RtlResetMultibyteState(&(Context->State));
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgument(Format,
- Position,
- Arguments);
- WideStringArgument = (PWSTR)(UINTN)IntegerArgument;
- } else {
- WideStringArgument = va_arg(*Arguments, PWSTR);
- }
- Result = RtlpPrintWideString(Context,
- WideStringArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- FALSE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- break;
- case FORMAT_STRING:
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgument(Format,
- Position,
- Arguments);
- StringArgument = (PSTR)(UINTN)IntegerArgument;
- } else {
- StringArgument = va_arg(*Arguments, PSTR);
- }
- Result = RtlpPrintString(Context,
- StringArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- FALSE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- break;
- case FORMAT_NONE:
- IsInteger = FALSE;
- CharacterArgument = FORMAT_NONE;
- Result = RtlpPrintString(Context,
- &CharacterArgument,
- Properties.FieldWidth,
- Properties.Precision,
- Properties.LeftJustified,
- TRUE);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- break;
- default:
- Result = FALSE;
- goto ConvertFormatSpecifierEnd;
- }
- CurrentFormat += 1;
- //
- // If it's an integer, get the argument and process it.
- //
- if (IsInteger != FALSE) {
- if (Position != 0) {
- IntegerArgument = RtlpGetPositionalArgument(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 ConvertFormatSpecifierEnd;
- }
- } 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 ConvertFormatSpecifierEnd;
- }
- }
- if (Specifier == FORMAT_BYTES_PRINTED) {
- ASSERT(IntegerArgument != (UINTN)NULL);
- *((PINT)(UINTN)IntegerArgument) = (INT)Context->CharactersWritten;
- Result = TRUE;
- } else {
- Result = RtlpPrintInteger(Context, IntegerArgument, &Properties);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- }
- //
- // If it's an float, get the argument and process it.
- //
- } else if (IsFloat != FALSE) {
- if (Position != 0) {
- //
- // TODO: Support long doubles.
- //
- DoubleParts.Ulonglong = RtlpGetPositionalArgument(Format,
- Position,
- Arguments);
- } else {
- if (LongDoubleSpecified != FALSE) {
- DoubleParts.Double = (double)va_arg(*Arguments, long double);
- } else {
- DoubleParts.Double = va_arg(*Arguments, double);
- }
- }
- Result = RtlpPrintDouble(Context, DoubleParts.Double, &Properties);
- if (Result == FALSE) {
- goto ConvertFormatSpecifierEnd;
- }
- }
- Result = TRUE;
- ConvertFormatSpecifierEnd:
- *Index += ((UINTN)CurrentFormat - (UINTN)(Format + *Index));
- return Result;
- }
- ULONG
- RtlpPrintInteger (
- 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.
- --*/
- {
- UCHAR Character;
- ULONG FieldCount;
- ULONG FieldIndex;
- ULONG IntegerLength;
- CHAR LocalBuffer[MAX_INTEGER_STRING_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- ULONGLONG NextInteger;
- LONG Precision;
- ULONG PrecisionCount;
- ULONG PrecisionIndex;
- UCHAR 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 = (UCHAR)Remainder;
- if (Character > 9) {
- if (Properties->PrintUpperCase != FALSE) {
- Character = Character - 10 + 'A';
- } else {
- Character = Character - 10 + 'a';
- }
- } else {
- Character += '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.
- //
- RtlStringReverse(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] = '-';
- PrefixSize += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix[PrefixSize] = '+';
- PrefixSize += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix[PrefixSize] = ' ';
- PrefixSize += 1;
- }
- if (Properties->PrintRadix != FALSE) {
- if (Properties->Radix == 8) {
- if (LocalBuffer[0] != '0') {
- Prefix[PrefixSize] = '0';
- PrefixSize += 1;
- }
- } else if (Properties->Radix == 16) {
- Prefix[PrefixSize] = '0';
- PrefixSize += 1;
- if (Properties->PrintUpperCase != 0) {
- Prefix[PrefixSize] = 'X';
- } else {
- Prefix[PrefixSize] = '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 = ' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = '0';
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- for (PrecisionIndex = 0;
- PrecisionIndex < PrecisionCount;
- PrecisionIndex += 1) {
- Result = RtlpFormatWriteCharacter(Context, '0');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- for (LocalIndex = 0; LocalIndex < IntegerLength; LocalIndex += 1) {
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- ULONG
- RtlpPrintDouble (
- 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.
- --*/
- {
- UCHAR Character;
- LONG CurrentExponent;
- CHAR Digit;
- LONG DigitCount;
- LONG Exponent;
- CHAR ExponentCharacter;
- ULONG ExponentIndex;
- CHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
- ULONG FieldCount;
- ULONG FieldIndex;
- CHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- PSTR NonNumberString;
- ULONG NumberLength;
- DOUBLE_PARTS Parts;
- LONG Precision;
- LONG PrecisionIndex;
- CHAR 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 = "NAN";
- } else {
- NonNumberString = "nan";
- }
- //
- // Also handle positive and negative infinity.
- //
- } else {
- if (Properties->PrintUpperCase != FALSE) {
- NonNumberString = "INF";
- } else {
- NonNumberString = "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] = '-';
- LocalIndex += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- LocalBuffer[LocalIndex] = '+';
- LocalIndex += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- LocalBuffer[LocalIndex] = ' ';
- LocalIndex += 1;
- }
- RtlStringCopy(LocalBuffer + LocalIndex,
- NonNumberString,
- sizeof(LocalBuffer) - LocalIndex);
- Result = RtlpPrintString(Context,
- LocalBuffer,
- Properties->FieldWidth,
- Properties->Precision,
- Properties->LeftJustified,
- FALSE);
- return Result;
- }
- //
- // Use a special routine for hex formats.
- //
- if (Properties->Radix == 16) {
- return RtlpPrintHexDouble(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 + '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] == '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 = '-';
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix = '+';
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix = ' ';
- }
- //
- // 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 = RtlpFormatWriteCharacter(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 = ' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = '0';
- }
- for (FieldIndex = 0; FieldIndex < FieldCount; FieldIndex += 1) {
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(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 = '0';
- } else {
- Digit = LocalBuffer[LocalIndex];
- ASSERT(Digit != '0');
- LocalIndex += 1;
- }
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, '.');
- 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 = '0';
- }
- Result = RtlpFormatWriteCharacter(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Determine the exponent character.
- //
- ExponentCharacter = 'e';
- if (Properties->PrintUpperCase != FALSE) {
- ExponentCharacter = 'E';
- }
- //
- // Print the exponent.
- //
- RtlPrintToString(ExponentString,
- MAX_DOUBLE_EXPONENT_SIZE,
- Context->State.Encoding,
- "%c%+0.2d",
- ExponentCharacter,
- Exponent);
- for (ExponentIndex = 0;
- ExponentIndex < MAX_DOUBLE_EXPONENT_SIZE;
- ExponentIndex += 1) {
- if (ExponentString[ExponentIndex] == '\0') {
- break;
- }
- Result = RtlpFormatWriteCharacter(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 = '0';
- }
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, '0');
- if (Result == FALSE) {
- return FALSE;
- }
- CurrentExponent = -1;
- }
- //
- // Print the radix character.
- //
- if ((Precision != 0) || (Properties->PrintRadix != FALSE)) {
- Result = RtlpFormatWriteCharacter(Context, '.');
- 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 = '0';
- } else if (LocalIndex < DigitCount) {
- Digit = LocalBuffer[LocalIndex];
- LocalIndex += 1;
- } else {
- Digit = '0';
- }
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- ULONG
- RtlpPrintHexDouble (
- 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;
- UCHAR Character;
- CHAR Digit;
- LONG Exponent;
- CHAR ExponentCharacter;
- CHAR ExponentString[MAX_DOUBLE_EXPONENT_SIZE];
- ULONG FieldCount;
- ULONG FieldIndex;
- ULONGLONG HalfWay;
- CHAR IntegerPortion;
- CHAR LocalBuffer[MAX_DOUBLE_DIGITS_SIZE];
- ULONG LocalIndex;
- BOOL Negative;
- ULONG NumberLength;
- DOUBLE_PARTS Parts;
- LONG Precision;
- ULONG PrecisionIndex;
- UCHAR 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 = '0';
- if (Precision == -1) {
- Precision = 0;
- }
- for (LocalIndex = 0;
- LocalIndex < DOUBLE_SIGNIFICAND_HEX_DIGITS;
- LocalIndex += 1) {
- LocalBuffer[LocalIndex] = '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 = '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 + '0';
- } else if (Properties->PrintUpperCase != FALSE) {
- Character = Digit + 'A' - 10;
- } else {
- Character = Digit + '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] == '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] = '-';
- PrefixSize += 1;
- } else if (Properties->AlwaysPrintSign != FALSE) {
- Prefix[PrefixSize] = '+';
- PrefixSize += 1;
- } else if (Properties->SpaceForPlus != FALSE) {
- Prefix[PrefixSize] = ' ';
- PrefixSize += 1;
- }
- Prefix[PrefixSize] = '0';
- PrefixSize += 1;
- if (Properties->PrintUpperCase != 0) {
- Prefix[PrefixSize] = 'X';
- } else {
- Prefix[PrefixSize] = '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 = 'p';
- if (Properties->PrintUpperCase != FALSE) {
- ExponentCharacter = 'P';
- }
- RtlPrintToString(ExponentString,
- sizeof(ExponentString),
- Context->State.Encoding,
- "%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 = ' ';
- if (Properties->PrintLeadingZeroes != FALSE) {
- Character = '0';
- for (PrefixIndex = 0; PrefixIndex < PrefixSize; PrefixIndex += 1) {
- Result = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(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 = RtlpFormatWriteCharacter(Context, Prefix[PrefixIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the integer portion.
- //
- Result = RtlpFormatWriteCharacter(Context, IntegerPortion);
- if (Result == FALSE) {
- return FALSE;
- }
- //
- // Print a radix if needed.
- //
- if ((Properties->PrintRadix != FALSE) || (Precision != 0)) {
- Result = RtlpFormatWriteCharacter(Context, '.');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the precision digits.
- //
- for (PrecisionIndex = 0; PrecisionIndex < Precision; PrecisionIndex += 1) {
- if (PrecisionIndex >= DOUBLE_SIGNIFICAND_HEX_DIGITS) {
- Digit = '0';
- } else {
- Digit = LocalBuffer[PrecisionIndex];
- }
- Result = RtlpFormatWriteCharacter(Context, Digit);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- //
- // Print the exponent.
- //
- RtlpPrintString(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 = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- }
- return TRUE;
- }
- BOOL
- RtlpPrintString (
- PPRINT_FORMAT_CONTEXT Context,
- PSTR 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 = "(null)";
- }
- if (Character != FALSE) {
- StringLength = 1;
- } else {
- StringLength = RtlStringLength(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 = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- }
- //
- // Copy the string.
- //
- while (StringLength != 0) {
- Result = RtlpFormatWriteCharacter(Context, *String);
- if (Result == FALSE) {
- return FALSE;
- }
- String += 1;
- StringLength -= 1;
- }
- //
- // Pad right, if required.
- //
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- return TRUE;
- }
- BOOL
- RtlpPrintWideString (
- PPRINT_FORMAT_CONTEXT Context,
- PWSTR String,
- LONG FieldWidth,
- LONG Precision,
- BOOL LeftJustified,
- BOOL Character
- )
- /*++
- Routine Description:
- This routine prints a wide string out to a byte based print output.
- Arguments:
- Context - Supplies a pointer to the initialized context structure.
- String - Supplies a pointer to the wide 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 ByteIndex;
- CHAR MultibyteCharacter[MULTIBYTE_MAX];
- ULONG PaddingIndex;
- ULONG PaddingLength;
- BOOL Result;
- ULONG Size;
- KSTATUS Status;
- ULONG StringLength;
- if (String == NULL) {
- String = L"(null)";
- }
- if (Character != FALSE) {
- StringLength = 1;
- } else {
- //
- // Do a manual string length calculation to avoid adding references to
- // wide string functions if they're not currently included.
- //
- StringLength = 0;
- while (String[StringLength] != WIDE_STRING_TERMINATOR) {
- StringLength += 1;
- }
- }
- 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 = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- }
- //
- // Copy the string by repeatedly converting wide characters to multibyte
- // sequences and spitting those out.
- //
- while (StringLength != 0) {
- Size = MULTIBYTE_MAX;
- Status = RtlConvertWideCharacterToMultibyte(*String,
- MultibyteCharacter,
- &Size,
- &(Context->State));
- if (!KSUCCESS(Status)) {
- return FALSE;
- }
- for (ByteIndex = 0; ByteIndex < Size; ByteIndex += 1) {
- Result = RtlpFormatWriteCharacter(Context,
- MultibyteCharacter[ByteIndex]);
- if (Result == FALSE) {
- return FALSE;
- }
- }
- String += 1;
- StringLength -= 1;
- }
- //
- // Pad right, if required.
- //
- while (PaddingIndex > 0) {
- Result = RtlpFormatWriteCharacter(Context, ' ');
- if (Result == FALSE) {
- return FALSE;
- }
- PaddingIndex -= 1;
- }
- return TRUE;
- }
- BOOL
- RtlpFormatWriteCharacter (
- PPRINT_FORMAT_CONTEXT Context,
- CHAR Character
- )
- /*++
- Routine Description:
- This routine writes a 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.WriteCharacter(Character, Context);
- if (Result == FALSE) {
- return FALSE;
- }
- Context->CharactersWritten += 1;
- return TRUE;
- }
- ULONGLONG
- RtlpGetPositionalArgument (
- PSTR 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 = RtlpGetPositionalArgumentSize(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 = RtlpGetPositionalArgumentSize(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
- RtlpGetPositionalArgumentSize (
- PSTR 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 != 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 >= '1') && (*Format <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&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 >= '1') && (*Format <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&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 >= '1') && (*Format <= '9')) {
- RemainingSize = -1;
- RtlStringScanInteger(&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 >= '1') && (*Format <= '9')) {
- RemainingSize = -1;
- Status = RtlStringScanInteger(&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 >= '1') && (*Format <= '9')) {
- RemainingSize = -1;
- RtlStringScanInteger(&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) == '6') &&
- (*(Format + 1) == '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
- RtlpStringFormatWriteCharacter (
- CHAR 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.
- --*/
- {
- PSTR String;
- String = Context->Context;
- if ((String != NULL) && (Context->CharactersWritten < Context->Limit)) {
- String[Context->CharactersWritten] = Character;
- }
- return TRUE;
- }
|