123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- scan.c
- Abstract:
- This module implements scanning strings into various other forms, such as
- integers.
- Author:
- Evan Green 25-May-2013
- Environment:
- Kernel and User Modes
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "rtlp.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define INFINITY_STRING "infinity"
- #define NAN_STRING "nan"
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- RtlpScanInteger (
- PSCAN_INPUT Input,
- ULONG Base,
- ULONG FieldSize,
- BOOL Signed,
- PLONGLONG Integer,
- PULONG CharactersConsumed
- );
- KSTATUS
- RtlpScanDouble (
- PSCAN_INPUT Input,
- ULONG FieldSize,
- double *Double,
- PULONG CharactersConsumed
- );
- VOID
- RtlpScannerUnput (
- PSCAN_INPUT Input,
- CHAR Character
- );
- VOID
- RtlpScannerWideUnput (
- PSCAN_INPUT Input,
- WCHAR Character
- );
- BOOL
- RtlpScannerGetInput (
- PSCAN_INPUT Input,
- PCHAR Character
- );
- BOOL
- RtlpScannerGetWideInput (
- PSCAN_INPUT Input,
- PWCHAR WideCharacter
- );
- BOOL
- RtlpStringScannerGetInput (
- PSCAN_INPUT Input,
- PCHAR Character
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- double RtlFirst16PowersOf10[16] = {
- 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13,
- 1E14, 1E15
- };
- double RtlFirst16NegativePowersOf10[16] = {
- 1E0, 1E-1, 1E-2, 1E-3, 1E-4, 1E-5, 1E-6, 1E-7, 1E-8, 1E-9, 1E-10, 1E-11,
- 1E-12, 1E-13, 1E-14, 1E-15
- };
- double RtlPositivePowersOf2[5] = {
- 1E16, 1E32, 1E64, 1E128, 1E256
- };
- double RtlNegativePowersOf2[5] = {
- 1E-16, 1E-32, 1E-64, 1E-128, 1E-256
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- RTL_API
- KSTATUS
- RtlStringScan (
- PSTR Input,
- ULONG InputSize,
- PSTR Format,
- ULONG FormatSize,
- CHARACTER_ENCODING Encoding,
- PULONG ItemsScanned,
- ...
- )
- /*++
- Routine Description:
- This routine scans in a string and converts it to a number of arguments
- based on a format string.
- Arguments:
- Input - Supplies a pointer to the input string to scan.
- InputSize - Supplies the size of the string in bytes including the null
- terminator.
- Format - Supplies the format string that specifies how to convert the input
- to the arguments.
- FormatSize - Supplies the size of the format string in bytes, including
- the null terminator.
- Encoding - Supplies the character encoding to use when scanning into
- wide strings or characters.
- ItemsScanned - Supplies a pointer where the number of items scanned will
- be returned (not counting any %n specifiers).
- ... - Supplies the remaining pointer arguments where the scanned data will
- be returned.
- Return Value:
- STATUS_SUCCESS if the input was successfully scanned according to the
- format.
- STATUS_INVALID_SEQUENCE if the input did not match the format or the
- format was invalid.
- STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
- format.
- STATUS_END_OF_FILE if the input ended before any arguments were converted
- or any matching failures occurred.
- --*/
- {
- va_list ArgumentList;
- KSTATUS Status;
- va_start(ArgumentList, ItemsScanned);
- Status = RtlStringScanVaList(Input,
- InputSize,
- Format,
- FormatSize,
- Encoding,
- ItemsScanned,
- ArgumentList);
- va_end(ArgumentList);
- return Status;
- }
- RTL_API
- KSTATUS
- RtlStringScanVaList (
- PSTR Input,
- ULONG InputSize,
- PSTR Format,
- ULONG FormatSize,
- CHARACTER_ENCODING Encoding,
- PULONG ItemsScanned,
- va_list Arguments
- )
- /*++
- Routine Description:
- This routine scans in a string and converts it to a number of arguments
- based on a format string.
- Arguments:
- Input - Supplies a pointer to the input string to scan.
- InputSize - Supplies the size of the string in bytes including the null
- terminator.
- Format - Supplies the format string that specifies how to convert the input
- to the arguments.
- FormatSize - Supplies the size of the format string in bytes, including
- the null terminator.
- Encoding - Supplies the character encoding to use when scanning into
- wide strings or characters.
- ItemsScanned - Supplies a pointer where the number of items scanned will
- be returned (not counting any %n specifiers).
- Arguments - Supplies the initialized arguments list where various pieces
- of the formatted string will be returned.
- Return Value:
- STATUS_SUCCESS if the input was successfully scanned according to the
- format.
- STATUS_INVALID_SEQUENCE if the input did not match the format or the
- format was invalid.
- STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
- format.
- STATUS_END_OF_FILE if the input ended before any arguments were converted
- or any matching failures occurred.
- --*/
- {
- SCAN_INPUT InputParameters;
- KSTATUS Status;
- if (Input == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- InputParameters.ReadU.GetInput = RtlpStringScannerGetInput;
- InputParameters.DataU.String = Input;
- InputParameters.StringSize = InputSize;
- InputParameters.ValidUnputCharacters = 0;
- InputParameters.CharactersRead = 0;
- RtlInitializeMultibyteState(&(InputParameters.State), Encoding);
- Status = RtlScan(&InputParameters,
- Format,
- FormatSize,
- ItemsScanned,
- Arguments);
- return Status;
- }
- RTL_API
- KSTATUS
- RtlStringScanInteger (
- PSTR *String,
- PULONG StringSize,
- ULONG Base,
- BOOL Signed,
- PLONGLONG Integer
- )
- /*++
- Routine Description:
- This routine converts a string into an integer. It scans past leading
- whitespace.
- Arguments:
- String - Supplies a pointer that on input contains a pointer to the string
- to scan. On output, the string advanced past the scanned value (if any)
- will be returned. If the entire string is whitespace or starts with an
- invalid character, this parameter will not be modified.
- StringSize - Supplies a pointer that on input contains the size of the
- string, in bytes, including the null terminator. On output, this will
- contain the size of the string minus the number of bytes scanned by
- this routine. Said differently, it will return the size of the output
- to the string parameter in bytes including the null terminator.
- Base - Supplies the base of the integer to scan. Valid values are zero and
- two through thirty six. If zero is supplied, this routine will attempt
- to automatically detect what the base is out of bases 8, 10, and 16.
- Signed - Supplies a boolean indicating whether the integer to scan is
- signed or not.
- Integer - Supplies a pointer where the resulting integer is returned on
- success.
- Return Value:
- STATUS_SUCCESS if an integer was successfully scanned.
- STATUS_INVALID_SEQUENCE if a valid integer could not be scanned.
- STATUS_INTEGER_OVERFLOW if the result overflowed. In this case the integer
- returned will be MAX_LONGLONG, MIN_LONGLONG, or MAX_ULONGLONG depending on
- the signedness and value.
- STATUS_END_OF_FILE if the input ended before the value was converted
- or a matching failure occurred.
- --*/
- {
- ULONG CharactersConsumed;
- SCAN_INPUT Input;
- KSTATUS Status;
- if (String == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- Input.ReadU.GetInput = RtlpStringScannerGetInput;
- Input.DataU.String = *String;
- Input.StringSize = *StringSize;
- Input.ValidUnputCharacters = 0;
- Input.CharactersRead = 0;
- RtlInitializeMultibyteState(&(Input.State), CharacterEncodingDefault);
- Status = RtlpScanInteger(&Input,
- Base,
- *StringSize,
- Signed,
- Integer,
- &CharactersConsumed);
- *StringSize -= CharactersConsumed;
- *String += CharactersConsumed;
- return Status;
- }
- RTL_API
- KSTATUS
- RtlStringScanDouble (
- PSTR *String,
- PULONG StringSize,
- double *Double
- )
- /*++
- Routine Description:
- This routine converts a string into a floating point double. It scans past
- leading whitespace.
- Arguments:
- String - Supplies a pointer that on input contains a pointer to the string
- to scan. On output, the string advanced past the scanned value (if any)
- will be returned. If the entire string is whitespace or starts with an
- invalid character, this parameter will not be modified.
- StringSize - Supplies a pointer that on input contains the size of the
- string, in bytes, including the null terminator. On output, this will
- contain the size of the string minus the number of bytes scanned by
- this routine. Said differently, it will return the size of the output
- to the string parameter in bytes including the null terminator.
- Double - Supplies a pointer where the resulting double is returned on
- success.
- Return Value:
- STATUS_SUCCESS if an integer was successfully scanned.
- STATUS_INVALID_SEQUENCE if a valid double could not be scanned.
- STATUS_OUT_OF_BOUNDS if the exponent was out of range.
- STATUS_END_OF_FILE if the input ended before the value was converted
- or a matching failure occurred.
- --*/
- {
- ULONG CharactersConsumed;
- SCAN_INPUT Input;
- KSTATUS Status;
- if (String == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- Input.ReadU.GetInput = RtlpStringScannerGetInput;
- Input.DataU.String = *String;
- Input.StringSize = *StringSize;
- Input.ValidUnputCharacters = 0;
- Input.CharactersRead = 0;
- RtlInitializeMultibyteState(&(Input.State), CharacterEncodingDefault);
- Status = RtlpScanDouble(&Input, *StringSize, Double, &CharactersConsumed);
- *StringSize -= CharactersConsumed;
- *String += CharactersConsumed;
- return Status;
- }
- RTL_API
- KSTATUS
- RtlScan (
- PSCAN_INPUT Input,
- PSTR Format,
- ULONG FormatLength,
- PULONG ItemsScanned,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine scans from an input and converts the input to various
- parameters according to a specified format.
- Arguments:
- Input - Supplies a pointer to the filled out scan input structure which
- will be used to retrieve more input.
- Format - Supplies the format string which specifies how to convert the
- input to the argument list.
- FormatLength - Supplies the size of the format length string in bytes,
- including the null terminator.
- ItemsScanned - Supplies a pointer where the number of parameters filled in
- (not counting %n) will be returned.
- ArgumentList - Supplies the list of arguments that will get filled out
- based on the input and format string.
- Return Value:
- STATUS_SUCCESS if the input was successfully scanned according to the
- format.
- STATUS_INVALID_SEQUENCE if the input did not match the format or the
- format was invalid.
- STATUS_ARGUMENT_EXPECTED if not enough arguments were supplied for the
- format.
- STATUS_END_OF_FILE if the input ended before any arguments were converted
- or any matching failures occurred.
- --*/
- {
- BOOL AdvanceFormat;
- PCHAR Argument;
- ULONG ArgumentsWritten;
- BOOL AssignmentSuppression;
- ULONG Base;
- CHAR Character;
- ULONG CharactersConsumed;
- double Double;
- ULONG FieldWidth;
- CHAR InputCharacter;
- BOOL InScanSet;
- LONGLONG Integer;
- ULONG LengthModifier;
- BOOL LongSpecified;
- ULONG Position;
- BOOL Result;
- PSTR ScanSetBegin;
- BOOL ScanSetGotSomething;
- ULONG ScanSetIndex;
- ULONG ScanSetLength;
- BOOL ScanSetNegated;
- KSTATUS ScanStatus;
- BOOL Signed;
- KSTATUS Status;
- WCHAR WideCharacter;
- PWSTR WideStringArgument;
- ASSERT(RtlIsCharacterEncodingSupported(Input->State.Encoding) != FALSE);
- ArgumentsWritten = 0;
- *ItemsScanned = 0;
- Result = FALSE;
- //
- // Loop getting characters.
- //
- while (FormatLength != 0) {
- AssignmentSuppression = FALSE;
- FieldWidth = -1;
- LengthModifier = 0;
- Position = -1;
- Character = *Format;
- //
- // Any whitespace in the format blasts through all whitespace in the
- // input.
- //
- if (RtlIsCharacterSpace(Character) != FALSE) {
- do {
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if (Result == FALSE) {
- break;
- }
- } while (RtlIsCharacterSpace(InputCharacter) != FALSE);
- //
- // This went one too far, put the non-whitespace character back.
- //
- if (Result != FALSE) {
- RtlpScannerUnput(Input, InputCharacter);
- }
- //
- // If it's a terminator, stop scanning.
- //
- } else if (Character == '\0') {
- break;
- //
- // If it's not a percent, then it's just a regular character, match it
- // up.
- //
- } else if (Character != '%') {
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if (Result == FALSE) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- if (InputCharacter != Character) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // Big boy land, it's a format specifier (percent sign).
- //
- } else {
- ASSERT(Character == '%');
- Format += 1;
- FormatLength -= 1;
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- //
- // Potentially get a positional argument (or field length, it's
- // unclear yet).
- //
- if ((Character >= '0') && (Character <= '9')) {
- ScanStatus = RtlStringScanInteger(&Format,
- &FormatLength,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(ScanStatus)) {
- Status = ScanStatus;
- goto ScanEnd;
- }
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- if (Integer <= 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // A dollar sign means it was a positional argument, none means
- // it was a field width.
- //
- Character = *Format;
- if (Character == '$') {
- Position = (ULONG)Integer;
- Format += 1;
- FormatLength -= 1;
- if (FormatLength == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- if (Character == '\0') {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- } else {
- FieldWidth = (ULONG)Integer;
- }
- }
- //
- // Watch out for assignment suppression.
- //
- if (Character == '*') {
- AssignmentSuppression = TRUE;
- Format += 1;
- FormatLength -= 1;
- if (FormatLength == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- }
- //
- // If not already found, try again to scan a field width, as it
- // could have been after the asterisk.
- //
- if ((FieldWidth == -1) &&
- (Character >= '0') && (Character <= '9')) {
- ScanStatus = RtlStringScanInteger(&Format,
- &FormatLength,
- 10,
- FALSE,
- &Integer);
- if (!KSUCCESS(ScanStatus)) {
- Status = ScanStatus;
- goto ScanEnd;
- }
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- if (Integer <= 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- FieldWidth = (ULONG)Integer;
- Character = *Format;
- }
- //
- // Look for a length modifier. There are two-character wide
- // length modifiers hh for char and ll for long long.
- //
- AdvanceFormat = FALSE;
- LongSpecified = FALSE;
- //
- // If the character is 'h', then the parameter points to a short.
- // Advance manually here to look for 'hh' as well, which makes the
- // parameter a char.
- //
- if (Character == 'h') {
- LengthModifier = sizeof(SHORT);
- Format += 1;
- FormatLength -= 1;
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- if (Character == 'h') {
- LengthModifier = sizeof(CHAR);
- AdvanceFormat = TRUE;
- }
- //
- // If the character is 'l', then the parameter points to a long.
- // Advance manually here as well to look for the 'll', which is
- // long long.
- //
- } else if (Character == 'l') {
- LongSpecified = TRUE;
- LengthModifier = sizeof(LONG);
- Format += 1;
- FormatLength -= 1;
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- if (Character == 'l') {
- LongSpecified = FALSE;
- LengthModifier = sizeof(LONGLONG);
- AdvanceFormat = TRUE;
- }
- //
- // The 'j' override specifies an intmax_t type.
- //
- } else if (Character == 'j') {
- LengthModifier = sizeof(intmax_t);
- AdvanceFormat = TRUE;
- //
- // The 'z' override specifies a size_t type.
- //
- } else if (Character == 'z') {
- LengthModifier = sizeof(size_t);
- AdvanceFormat = TRUE;
- //
- // The 't' override specifies a ptrdiff_t type.
- //
- } else if (Character == 't') {
- LengthModifier = sizeof(ptrdiff_t);
- AdvanceFormat = TRUE;
- //
- // The 'L' override specifies a long double.
- //
- } else if (Character == 'L') {
- LengthModifier = sizeof(LONGLONG);
- AdvanceFormat = TRUE;
- }
- if (AdvanceFormat != FALSE) {
- Format += 1;
- FormatLength -= 1;
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- Character = *Format;
- }
- //
- // Get the argument unless the assignment is suppressed.
- //
- Argument = NULL;
- if ((AssignmentSuppression == FALSE) && (Character != '%')) {
- //
- // TODO: Handle positional arguments. Not sure how to do
- // that with just va_arg. If they're all pointer types
- // perhaps pointer arithmetic is fine if there were a way
- // to get the original address of the first argument.
- //
- if (Position != -1) {
- ASSERT(FALSE);
- Argument = NULL;
- } else {
- Argument = va_arg(ArgumentList, PCHAR);
- }
- if (Argument == NULL) {
- Status = STATUS_ARGUMENT_EXPECTED;
- goto ScanEnd;
- }
- }
- //
- // Convert an lc to a C and and ls to an S just to make the if
- // statements easier.
- //
- if (LongSpecified != FALSE) {
- if (Character == 'c') {
- Character = 'C';
- } else if (Character == 's') {
- Character = 'S';
- }
- }
- //
- // All the wiggly stuff is out of the way, get down to the real
- // format specifier. First check for an integer.
- //
- if ((Character == 'd') || (Character == 'i') ||
- (Character == 'o') || (Character == 'u') ||
- (Character == 'x') || (Character == 'X')) {
- if (LengthModifier == 0) {
- LengthModifier = sizeof(INT);
- }
- Signed = TRUE;
- if (Character == 'd') {
- Base = 10;
- } else if (Character == 'i') {
- Base = 0;
- } else if (Character == 'o') {
- Base = 8;
- } else if (Character == 'u') {
- Base = 10;
- Signed = FALSE;
- } else {
- Base = 16;
- }
- ScanStatus = RtlpScanInteger(Input,
- Base,
- FieldWidth,
- Signed,
- &Integer,
- &CharactersConsumed);
- if (!KSUCCESS(ScanStatus)) {
- Status = ScanStatus;
- goto ScanEnd;
- }
- if (AssignmentSuppression == FALSE) {
- //
- // Write the argument.
- //
- switch (LengthModifier) {
- case sizeof(CHAR):
- *((PCHAR)Argument) = (CHAR)Integer;
- break;
- case sizeof(SHORT):
- *((PSHORT)Argument) = (SHORT)Integer;
- break;
- case sizeof(LONG):
- *((PLONG)Argument) = (LONG)Integer;
- break;
- case sizeof(LONGLONG):
- *((PLONGLONG)Argument) = (LONGLONG)Integer;
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- ArgumentsWritten += 1;
- }
- //
- // Handle floats.
- //
- } else if ((Character == 'a') || (Character == 'A') ||
- (Character == 'e') || (Character == 'E') ||
- (Character == 'f') || (Character == 'F') ||
- (Character == 'g') || (Character == 'G')) {
- ScanStatus = RtlpScanDouble(Input,
- FieldWidth,
- &Double,
- &CharactersConsumed);
- if (!KSUCCESS(ScanStatus)) {
- Status = ScanStatus;
- goto ScanEnd;
- }
- if (AssignmentSuppression == FALSE) {
- switch (LengthModifier) {
- case sizeof(LONG):
- *((double *)Argument) = Double;
- break;
- case sizeof(LONGLONG):
- *((long double *)Argument) = Double;
- break;
- default:
- *((float *)Argument) = (float)Double;
- break;
- }
- ArgumentsWritten += 1;
- }
- //
- // Handle string copies.
- //
- } else if (Character == 's') {
- //
- // First get past any whitespace.
- //
- do {
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if ((Result == FALSE) || (InputCharacter == '\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- } while (RtlIsCharacterSpace(InputCharacter) != FALSE);
- //
- // Now loop putting non-whitespace characters into the
- // argument. Note how the destination argument buffer is
- // unbounded? Very dangerous to use without a field width.
- //
- do {
- if (AssignmentSuppression == FALSE) {
- *Argument = InputCharacter;
- }
- Argument += 1;
- FieldWidth -= 1;
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if ((Result == FALSE) || (InputCharacter == '\0')) {
- Status = STATUS_END_OF_FILE;
- break;
- }
- } while ((FieldWidth != 0) &&
- (RtlIsCharacterSpace(InputCharacter) == FALSE));
- //
- // Put the last character back.
- //
- if (Result != FALSE) {
- RtlpScannerUnput(Input, InputCharacter);
- }
- //
- // Null terminate the destination string.
- //
- if (AssignmentSuppression == FALSE) {
- *Argument = '\0';
- ArgumentsWritten += 1;
- }
- //
- // Handle wide string copies.
- //
- } else if (Character == 'S') {
- RtlResetMultibyteState(&(Input->State));
- //
- // First get past any whitespace.
- //
- do {
- Result = RtlpScannerGetWideInput(Input, &WideCharacter);
- if ((Result == FALSE) || (InputCharacter == L'\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- } while (RtlIsCharacterSpaceWide(WideCharacter) != FALSE);
- //
- // Now loop putting non-whitespace characters into the
- // argument. Note how the destination argument buffer is
- // unbounded? Very dangerous to use without a field width.
- //
- WideStringArgument = (PWSTR)Argument;
- do {
- if (AssignmentSuppression == FALSE) {
- *WideStringArgument = WideCharacter;
- }
- WideStringArgument += 1;
- FieldWidth -= 1;
- Result = RtlpScannerGetWideInput(Input, &WideCharacter);
- if ((Result == FALSE) || (WideCharacter == L'\0')) {
- Status = STATUS_END_OF_FILE;
- break;
- }
- } while ((FieldWidth != 0) &&
- (RtlIsCharacterSpaceWide(WideCharacter) == FALSE));
- //
- // Put the last character back.
- //
- if (Result != FALSE) {
- RtlpScannerWideUnput(Input, WideCharacter);
- }
- //
- // Null terminate the destination string.
- //
- if (AssignmentSuppression == FALSE) {
- *WideStringArgument = L'\0';
- ArgumentsWritten += 1;
- }
- //
- // Handle a character (or a bunch of them).
- //
- } else if (Character == 'c') {
- if (FieldWidth == -1) {
- FieldWidth = 1;
- }
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if ((Result == FALSE) || (InputCharacter == '\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- while (TRUE) {
- if (AssignmentSuppression == FALSE) {
- *Argument = InputCharacter;
- }
- Argument += 1;
- FieldWidth -= 1;
- if (FieldWidth == 0) {
- break;
- }
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if ((Result == FALSE) || (InputCharacter == '\0')) {
- Status = STATUS_END_OF_FILE;
- break;
- }
- }
- if (AssignmentSuppression == FALSE) {
- ArgumentsWritten += 1;
- }
- //
- // Handle a wide character (or a bunch of them).
- //
- } else if (Character == 'C') {
- RtlResetMultibyteState(&(Input->State));
- if (FieldWidth == -1) {
- FieldWidth = 1;
- }
- Result = RtlpScannerGetWideInput(Input, &WideCharacter);
- if ((Result == FALSE) || (WideCharacter == L'\0')) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- WideStringArgument = (PWSTR)Argument;
- while (TRUE) {
- if (AssignmentSuppression == FALSE) {
- *WideStringArgument = WideCharacter;
- }
- WideStringArgument += 1;
- FieldWidth -= 1;
- if (FieldWidth == 0) {
- break;
- }
- Result = RtlpScannerGetWideInput(Input, &WideCharacter);
- if ((Result == FALSE) || (WideCharacter == '\0')) {
- Status = STATUS_END_OF_FILE;
- break;
- }
- }
- if (AssignmentSuppression == FALSE) {
- ArgumentsWritten += 1;
- }
- //
- // Handle a scanset.
- //
- } else if (Character == '[') {
- Format += 1;
- FormatLength -= 1;
- if (FormatLength == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // The circumflex (^) negates the scanset.
- //
- ScanSetNegated = FALSE;
- if (*Format == '^') {
- ScanSetNegated = TRUE;
- Format += 1;
- FormatLength -= 1;
- if (FormatLength == 0) {
- break;
- }
- }
- //
- // Find the end of the scanset. If the scanset starts with
- // [] or [^] then the left bracket is considered to be part of
- // the scanset. Annoyingly, there is no way to specify a
- // sequence of just ^, which seems like a glaring hole to this
- // programmer.
- //
- ScanSetBegin = Format;
- ScanSetLength = 0;
- while ((FormatLength != 0) && (*Format != '\0')) {
- if ((*Format == ']') && (ScanSetLength != 0)) {
- break;
- }
- ScanSetLength += 1;
- Format += 1;
- FormatLength -= 1;
- }
- if ((FormatLength == 0) || (*Format == '\0')) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // Now grab characters that are either in the scanset or not in
- // the scanset.
- //
- ScanSetGotSomething = FALSE;
- if (LongSpecified != FALSE) {
- WideStringArgument = (PWSTR)Argument;
- do {
- Result = RtlpScannerGetWideInput(Input, &WideCharacter);
- if ((Result == FALSE) || (WideCharacter == L'\0')) {
- break;
- }
- InScanSet = FALSE;
- for (ScanSetIndex = 0;
- ScanSetIndex < ScanSetLength;
- ScanSetIndex += 1) {
- if (WideCharacter == ScanSetBegin[ScanSetIndex]) {
- InScanSet = TRUE;
- break;
- }
- }
- //
- // Break out if it's not negated and it's not in the
- // scanset, or it is negated and it is in the scanset.
- // Write it out the long way and the simplification will
- // be more obvious.
- //
- if (ScanSetNegated == InScanSet) {
- break;
- }
- if (AssignmentSuppression == FALSE) {
- *WideStringArgument = WideCharacter;
- WideStringArgument += 1;
- }
- FieldWidth -= 1;
- ScanSetGotSomething = TRUE;
- } while (FieldWidth != 0);
- if (ScanSetGotSomething == FALSE) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // Put the last character back.
- //
- if ((Result != FALSE) && (FieldWidth != 0)) {
- RtlpScannerWideUnput(Input, WideCharacter);
- }
- //
- // Null terminate the destination string.
- //
- if (AssignmentSuppression == FALSE) {
- *WideStringArgument = L'\0';
- ArgumentsWritten += 1;
- }
- //
- // Long was not specified, these are just normal bytes in the
- // input.
- //
- } else {
- do {
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if ((Result == FALSE) || (InputCharacter == '\0')) {
- break;
- }
- InScanSet = FALSE;
- for (ScanSetIndex = 0;
- ScanSetIndex < ScanSetLength;
- ScanSetIndex += 1) {
- if (InputCharacter == ScanSetBegin[ScanSetIndex]) {
- InScanSet = TRUE;
- break;
- }
- }
- //
- // Break out if it's not negated and it's not in the
- // scanset, or it is negated and it is in the scanset.
- // Write it out the long way and the simplification will
- // be more obvious.
- //
- if (ScanSetNegated == InScanSet) {
- break;
- }
- if (AssignmentSuppression == FALSE) {
- *Argument = InputCharacter;
- Argument += 1;
- }
- FieldWidth -= 1;
- ScanSetGotSomething = TRUE;
- } while (FieldWidth != 0);
- if (ScanSetGotSomething == FALSE) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // Put the last character back.
- //
- if ((Result != FALSE) && (FieldWidth != 0)) {
- RtlpScannerUnput(Input, InputCharacter);
- }
- //
- // Null terminate the destination string.
- //
- if (AssignmentSuppression == FALSE) {
- *Argument = '\0';
- ArgumentsWritten += 1;
- }
- }
- //
- // Handle a little old percent. Double percents are just the
- // percent sign literal.
- //
- } else if (Character == '%') {
- Result = RtlpScannerGetInput(Input, &InputCharacter);
- if (Result == FALSE) {
- Status = STATUS_END_OF_FILE;
- goto ScanEnd;
- }
- if (InputCharacter != Character) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanEnd;
- }
- //
- // Return the number of bytes read from the input to get to this
- // point. This doesn't count in the number of arguments written.
- //
- } else if (Character == 'n') {
- if (AssignmentSuppression == FALSE) {
- *((PINT)Argument) = Input->CharactersRead -
- Input->ValidUnputCharacters;
- }
- //
- // This is an unknown format specifier.
- //
- } else {
- Status = STATUS_NOT_SUPPORTED;
- goto ScanEnd;
- }
- }
- //
- // Advance to the next character in the format string.
- //
- Format += 1;
- FormatLength -= 1;
- }
- Status = STATUS_SUCCESS;
- ScanEnd:
- if ((Status == STATUS_INVALID_SEQUENCE) && (Result != FALSE)) {
- RtlpScannerUnput(Input, InputCharacter);
- }
- if ((Status == STATUS_END_OF_FILE) && (ArgumentsWritten != 0)) {
- Status = STATUS_SUCCESS;
- }
- *ItemsScanned = ArgumentsWritten;
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- RtlpScanInteger (
- PSCAN_INPUT Input,
- ULONG Base,
- ULONG FieldSize,
- BOOL Signed,
- PLONGLONG Integer,
- PULONG CharactersConsumed
- )
- /*++
- Routine Description:
- This routine converts a string into an integer. It scans past leading
- whitespace.
- Arguments:
- Input - Supplies a pointer to the filled out scan input structure which
- will be used to retrieve more input.
- Base - Supplies the base of the integer to scan. Valid values are zero and
- two through thirty six. If zero is supplied, this routine will attempt
- to automatically detect what the base is out of bases 8, 10, and 16.
- Signed - Supplies a boolean indicating if the integer is signed or not.
- FieldSize - Supplies the maximum number of characters to scan for the
- integer.
- Integer - Supplies a pointer where the resulting integer is returned on
- success.
- CharactersConsumed - Supplies a pointer where the number characters consumed
- will be stored.
- Return Value:
- STATUS_SUCCESS if an integer was successfully scanned.
- STATUS_INVALID_SEQUENCE if a valid integer could not be scanned.
- STATUS_INTEGER_OVERFLOW if the result overflowed. In this case the integer
- returned will be MAX_LONGLONG, MIN_LONGLONG, or MAX_ULONGLONG depending on
- the signedness and value.
- STATUS_END_OF_FILE if the end of the file was reached before any
- non-whitespace could be retrieved.
- --*/
- {
- CHAR Character;
- ULONG CharacterCount;
- CHAR MaxDigit;
- CHAR MaxLetter;
- BOOL Negative;
- ULONGLONG NewValue;
- BOOL Result;
- KSTATUS Status;
- BOOL ValidCharacterFound;
- ULONGLONG Value;
- *CharactersConsumed = 0;
- CharacterCount = 0;
- *Integer = 0;
- Negative = FALSE;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- return STATUS_END_OF_FILE;
- }
- //
- // Scan past any whitespace.
- //
- while (RtlIsCharacterSpace(Character) != FALSE) {
- CharacterCount += 1;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- return STATUS_END_OF_FILE;
- }
- }
- //
- // Get past any optional plus or minus.
- //
- if ((Character == '+') || (Character == '-')) {
- if (Character == '-') {
- Negative = TRUE;
- }
- if (FieldSize == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanIntegerEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanIntegerEnd;
- }
- }
- //
- // Get past an optional 0x or 0X for base 16 mode.
- //
- ValidCharacterFound = FALSE;
- if (((Base == 0) || (Base == 16)) && (Character == '0')) {
- //
- // Seeing a leading zero is an indication of octal mode, so start with
- // that in case the x coming up isn't there.
- //
- if (Base == 0) {
- Base = 8;
- }
- if (FieldSize == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanIntegerEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- ValidCharacterFound = TRUE;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
- *CharactersConsumed = CharacterCount;
- Status = STATUS_SUCCESS;
- goto ScanIntegerEnd;
- }
- //
- // Swallow an x. 0x by itself is allowed, and counts as just the zero.
- //
- if ((Character == 'x') || (Character == 'X')) {
- Base = 16;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) ||
- (RtlIsCharacterHexDigit(Character) == FALSE) ||
- (FieldSize == 0)) {
- *CharactersConsumed = CharacterCount;
- Status = STATUS_SUCCESS;
- goto ScanIntegerEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- }
- }
- //
- // If the base is undecided, take a look at the first digit to figure it
- // out.
- //
- if (Base == 0) {
- ASSERT(Character != '0');
- if ((Character >= '1') && (Character <= '9')) {
- Base = 10;
- } else {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanIntegerEnd;
- }
- }
- //
- // Compute the maximum digit or letter value.
- //
- ASSERT(Base != 0);
- if (Base <= 10) {
- MaxDigit = '0' + Base - 1;
- MaxLetter = 'A' - 1;
- } else {
- MaxDigit = '9';
- MaxLetter = 'A' + Base - 1 - 10;
- }
- Status = STATUS_SUCCESS;
- Value = 0;
- //
- // Loop through every digit.
- //
- while (TRUE) {
- //
- // Uppercase any letters.
- //
- if ((Character >= 'a') && (Character <= 'z')) {
- Character = 'A' + Character - 'a';
- }
- //
- // Potentially add the next digit.
- //
- if ((Character >= '0') && (Character <= '9')) {
- if (Character > MaxDigit) {
- break;
- }
- Character -= '0';
- //
- // It could also be a letter digit.
- //
- } else if ((Character >= 'A') && (Character <= 'Z')) {
- if (Character > MaxLetter) {
- break;
- }
- Character -= 'A' - 0xA;
- //
- // Or it could be something entirely different, in which case the
- // number is over.
- //
- } else {
- break;
- }
- //
- // Check for overflow by dividing back out.
- //
- NewValue = (Value * Base) + Character;
- if (((NewValue - Character) / Base) != Value) {
- Status = STATUS_INTEGER_OVERFLOW;
- }
- Value = NewValue;
- ValidCharacterFound = TRUE;
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- break;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- break;
- }
- }
- //
- // If the loop broke without ever finding a valid character, fail.
- //
- if (ValidCharacterFound == FALSE) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanIntegerEnd;
- }
- //
- // If the character that caused the loop to break wasn't an integer, put
- // the candle back.
- //
- if ((FieldSize != 0) && (Result != FALSE)) {
- RtlpScannerUnput(Input, Character);
- }
- *CharactersConsumed = CharacterCount;
- //
- // Handle overflow.
- //
- if (Status == STATUS_INTEGER_OVERFLOW) {
- if (Signed != FALSE) {
- if (Negative != FALSE) {
- *Integer = MIN_LONGLONG;
- } else {
- *Integer = MAX_LONGLONG;
- }
- } else {
- *(PULONGLONG)Integer = MAX_ULONGLONG;
- }
- } else {
- if (Negative != FALSE) {
- Value = -Value;
- }
- *Integer = Value;
- }
- ScanIntegerEnd:
- if ((!KSUCCESS(Status)) && (Result != FALSE)) {
- RtlpScannerUnput(Input, Character);
- }
- return Status;
- }
- KSTATUS
- RtlpScanDouble (
- PSCAN_INPUT Input,
- ULONG FieldSize,
- double *Double,
- PULONG CharactersConsumed
- )
- /*++
- Routine Description:
- This routine converts a string into a floating point double. It scans past
- leading whitespace.
- Arguments:
- Input - Supplies a pointer to the filled out scan input structure which
- will be used to retrieve more input.
- FieldSize - Supplies the maximum number of characters to scan for the
- double.
- Double - Supplies a pointer where the resulting double is returned on
- success.
- CharactersConsumed - Supplies a pointer where the number characters consumed
- will be stored.
- Return Value:
- STATUS_SUCCESS if an integer was successfully scanned.
- STATUS_INVALID_SEQUENCE if a valid double could not be scanned.
- STATUS_OUT_OF_BOUNDS if the exponent was out of range.
- STATUS_END_OF_FILE if the end of the file was reached before any
- non-whitespace could be retrieved.
- --*/
- {
- double Base;
- CHAR Character;
- ULONG CharacterCount;
- CHAR DecasedCharacter;
- double Digit;
- LONG Exponent;
- CHAR ExponentCharacter;
- double ExponentMultiplier;
- CHAR ExponentSign;
- double ExponentValue;
- BOOL Negative;
- double NegativeExponent;
- double OneOverBase;
- ULONG PowerIndex;
- BOOL Result;
- BOOL SeenDecimal;
- KSTATUS Status;
- CHAR String[DOUBLE_SCAN_STRING_SIZE];
- ULONG StringCharacterCount;
- BOOL ValidCharacterFound;
- double Value;
- Base = 10.0;
- OneOverBase = 1.0E-1;
- *CharactersConsumed = 0;
- CharacterCount = 0;
- *Double = 0.0;
- Negative = FALSE;
- Value = 0.0;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- return STATUS_END_OF_FILE;
- }
- //
- // Scan past any whitespace.
- //
- while (RtlIsCharacterSpace(Character) != FALSE) {
- CharacterCount += 1;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- return STATUS_END_OF_FILE;
- }
- }
- Status = STATUS_SUCCESS;
- //
- // Get past any optional plus or minus.
- //
- if ((Character == '+') || (Character == '-')) {
- if (Character == '-') {
- Negative = TRUE;
- }
- if (FieldSize == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanDoubleEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0') || (FieldSize == 0)) {
- return STATUS_INVALID_SEQUENCE;
- }
- }
- //
- // Look for inf and infinity, ignoring case.
- //
- StringCharacterCount = 0;
- DecasedCharacter = Character;
- if ((Character >= 'A') && (Character <= 'Z')) {
- DecasedCharacter = Character + 'a' - 'A';
- }
- while ((StringCharacterCount < sizeof(INFINITY_STRING) - 1) &&
- (DecasedCharacter == INFINITY_STRING[StringCharacterCount])) {
- String[StringCharacterCount] = Character;
- StringCharacterCount += 1;
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- break;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- break;
- }
- DecasedCharacter = Character;
- if ((Character >= 'A') && (Character <= 'Z')) {
- DecasedCharacter = Character + 'a' - 'A';
- }
- }
- if (StringCharacterCount >= 3) {
- //
- // If it didn't match the full infinity (but has matched inf), then
- // put back anything between inf and the failed infinity.
- //
- if (StringCharacterCount != sizeof(INFINITY_STRING) - 1) {
- RtlpScannerUnput(Input, Character);
- while (StringCharacterCount > 3) {
- RtlpScannerUnput(Input, String[StringCharacterCount]);
- StringCharacterCount -= 1;
- CharacterCount -= 1;
- }
- }
- Value = DOUBLE_INFINITY;
- goto ScanDoubleEnd;
- //
- // Unput all the characters looked at.
- //
- } else if (StringCharacterCount != 0) {
- RtlpScannerUnput(Input, Character);
- StringCharacterCount -= 1;
- CharacterCount -= 1;
- while (StringCharacterCount != 0) {
- RtlpScannerUnput(Input, String[StringCharacterCount]);
- StringCharacterCount -= 1;
- CharacterCount -= 1;
- }
- Character = String[0];
- }
- //
- // Also look for NaN.
- //
- DecasedCharacter = Character;
- if ((Character >= 'A') && (Character <= 'Z')) {
- DecasedCharacter = Character + 'a' - 'A';
- }
- while ((StringCharacterCount < sizeof(NAN_STRING) - 1) &&
- (DecasedCharacter == NAN_STRING[StringCharacterCount])) {
- String[StringCharacterCount] = Character;
- StringCharacterCount += 1;
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- break;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- break;
- }
- DecasedCharacter = Character;
- if ((Character >= 'A') && (Character <= 'Z')) {
- DecasedCharacter = Character + 'a' - 'A';
- }
- }
- if (StringCharacterCount == sizeof(NAN_STRING) - 1) {
- //
- // Also check for a () or (0) on the end.
- //
- if (Character == '(') {
- Result = RtlpScannerGetInput(Input, &Character);
- if (Result != FALSE) {
- if (Character == '0') {
- Result = RtlpScannerGetInput(Input, &Character);
- if (Result != FALSE) {
- if (Character == ')') {
- CharacterCount += 3;
- } else {
- RtlpScannerUnput(Input, Character);
- RtlpScannerUnput(Input, '0');
- RtlpScannerUnput(Input, '(');
- }
- } else {
- RtlpScannerUnput(Input, Character);
- RtlpScannerUnput(Input, '(');
- }
- } else if (Character == ')') {
- CharacterCount += 2;
- } else {
- RtlpScannerUnput(Input, Character);
- RtlpScannerUnput(Input, '(');
- }
- } else {
- RtlpScannerUnput(Input, Character);
- }
- } else {
- RtlpScannerUnput(Input, Character);
- }
- Value = DOUBLE_NAN;
- Negative = FALSE;
- goto ScanDoubleEnd;
- //
- // Unput all the characters looked at.
- //
- } else if (StringCharacterCount != 0) {
- RtlpScannerUnput(Input, Character);
- StringCharacterCount -= 1;
- CharacterCount -= 1;
- while (StringCharacterCount != 0) {
- RtlpScannerUnput(Input, String[StringCharacterCount]);
- StringCharacterCount -= 1;
- CharacterCount -= 1;
- }
- Character = String[0];
- }
- //
- // Get past an optional 0x or 0X for base 16 mode.
- //
- ValidCharacterFound = FALSE;
- if (Character == '0') {
- ValidCharacterFound = TRUE;
- if (FieldSize == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanDoubleEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- Result = RtlpScannerGetInput(Input, &Character);
- if (Result != FALSE) {
- //
- // If it was only a lonely zero, then handle that case specifically.
- //
- if ((FieldSize == 0) ||
- (Character == '\0') ||
- (RtlIsCharacterSpace(Character) != FALSE)) {
- *CharactersConsumed = CharacterCount;
- goto ScanDoubleEnd;
- }
- if ((Character == 'x') || (Character == 'X')) {
- Base = 16.0;
- OneOverBase = 0.0625;
- Result = RtlpScannerGetInput(Input, &Character);
- //
- // If it was just an 0x, then actually it was just a 0.
- //
- if ((Result == FALSE) ||
- (RtlIsCharacterHexDigit(Character) == FALSE)) {
- RtlpScannerUnput(Input, Character);
- goto ScanDoubleEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanDoubleEnd;
- }
- }
- }
- }
- Digit = 0.0;
- NegativeExponent = OneOverBase;
- //
- // Loop through every digit.
- //
- SeenDecimal = FALSE;
- while (TRUE) {
- //
- // Uppercase any letters.
- //
- if ((Character >= 'a') && (Character <= 'z')) {
- Character = 'A' + Character - 'a';
- }
- //
- // Potentially add the next digit.
- //
- if ((Character >= '0') && (Character <= '9')) {
- Digit = Character - '0';
- //
- // It could also be a letter digit.
- //
- } else if ((Base == 16.0) && (Character >= 'A') && (Character <= 'F')) {
- Digit = Character - 'A' + 10;
- //
- // Handle a decimal point. Hopefully it was the the first and only one.
- //
- } else if (Character == '.') {
- if (SeenDecimal != FALSE) {
- break;
- }
- SeenDecimal = TRUE;
- //
- // Or it could be something entirely different, in which case the
- // number is over.
- //
- } else {
- break;
- }
- if (Character != '.') {
- //
- // If a decimal point has not been seen yet, this is the next
- // integer digit, so multiply everything by the base and add
- // this digit.
- //
- if (SeenDecimal == FALSE) {
- Value = (Value * Base) + Digit;
- //
- // This is a fractional part, so multiply it by the current
- // negative exponent, add it to the value, and shrink down to the
- // next exponent.
- //
- } else {
- Value += Digit * NegativeExponent;
- NegativeExponent *= OneOverBase;
- }
- ValidCharacterFound = TRUE;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- goto ScanDoubleEnd;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- break;
- }
- }
- //
- // If the loop broke without ever finding a valid character, fail.
- //
- if (ValidCharacterFound == FALSE) {
- CharacterCount = 0;
- Status = STATUS_INVALID_SEQUENCE;
- goto ScanDoubleEnd;
- }
- if (FieldSize == 0) {
- goto ScanDoubleEnd;
- }
- //
- // Look for an exponent character, and if none is found, finish.
- //
- ExponentCharacter = 0;
- if (((Base == 10.0) && ((Character == 'e') || (Character == 'E'))) ||
- ((Base == 16.0) && ((Character == 'p') || (Character == 'P')))) {
- ExponentCharacter = Character;
- }
- if (ExponentCharacter == 0) {
- RtlpScannerUnput(Input, Character);
- goto ScanDoubleEnd;
- }
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- goto ScanDoubleEnd;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- RtlpScannerUnput(Input, ExponentCharacter);
- CharacterCount -= 1;
- goto ScanDoubleEnd;
- }
- //
- // Look for an optional plus or minus.
- //
- ExponentSign = 0;
- if ((Character == '+') || (Character == '-')) {
- ExponentSign = Character;
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- goto ScanDoubleEnd;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- RtlpScannerUnput(Input, ExponentSign);
- RtlpScannerUnput(Input, ExponentCharacter);
- CharacterCount -= 2;
- goto ScanDoubleEnd;
- }
- }
- //
- // If there are not exponent digits, the exponent and sign were a fakeout.
- //
- if (!((Character >= '0') && (Character <= '9'))) {
- RtlpScannerUnput(Input, Character);
- if (ExponentSign != 0) {
- RtlpScannerUnput(Input, ExponentSign);
- CharacterCount -= 1;
- }
- RtlpScannerUnput(Input, ExponentCharacter);
- CharacterCount -= 1;
- goto ScanDoubleEnd;
- }
- //
- // Scan the base decimal integer exponent (meaning the exponent is always
- // a string in base 10).
- //
- Exponent = 0;
- while ((Character >= '0') && (Character <= '9')) {
- Exponent = (Exponent * 10) + (Character - '0');
- CharacterCount += 1;
- FieldSize -= 1;
- if (FieldSize == 0) {
- break;
- }
- Result = RtlpScannerGetInput(Input, &Character);
- if ((Result == FALSE) || (Character == '\0')) {
- break;
- }
- }
- //
- // If the character that caused the loop to break wasn't an integer, put.
- // the candle. back.
- //
- if ((FieldSize != 0) && (Result != FALSE)) {
- RtlpScannerUnput(Input, Character);
- }
- if (Exponent > 300) {
- if (Value == 0.0) {
- goto ScanDoubleEnd;
- }
- Status = STATUS_OUT_OF_BOUNDS;
- Result = FALSE;
- if (ExponentSign == '-') {
- Value = 0.0;
- } else {
- Value = DOUBLE_HUGE_VALUE;
- }
- goto ScanDoubleEnd;
- }
- //
- // Create a value with the desired exponent.
- //
- if (Base == 10.0) {
- //
- // Put together the approximation using powers of 2.
- //
- if (ExponentSign == '-') {
- ExponentValue = RtlFirst16NegativePowersOf10[Exponent & 0x0F];
- } else {
- ExponentValue = RtlFirst16PowersOf10[Exponent & 0x0F];
- }
- Exponent = Exponent >> 4;
- for (PowerIndex = 0; PowerIndex < 5; PowerIndex += 1) {
- if (Exponent == 0) {
- break;
- }
- if ((Exponent & 0x1) != 0) {
- if (ExponentSign == '-') {
- ExponentValue *= RtlNegativePowersOf2[PowerIndex];
- } else {
- ExponentValue *= RtlPositivePowersOf2[PowerIndex];
- }
- }
- Exponent = Exponent >> 1;
- }
- //
- // For base 16, just multiply the power of 2 out.
- //
- } else {
- ExponentValue = 1.0;
- if (ExponentSign == '-') {
- ExponentMultiplier = 0.5;
- } else {
- ExponentMultiplier = 2.0;
- }
- while (Exponent != 0) {
- ExponentValue *= ExponentMultiplier;
- Exponent -= 1;
- }
- }
- Value *= ExponentValue;
- ScanDoubleEnd:
- if ((!KSUCCESS(Status)) && (Result != FALSE)) {
- RtlpScannerUnput(Input, Character);
- }
- *CharactersConsumed = CharacterCount;
- if (Negative != FALSE) {
- Value = -Value;
- }
- *Double = Value;
- return Status;
- }
- VOID
- RtlpScannerUnput (
- PSCAN_INPUT Input,
- CHAR Character
- )
- /*++
- Routine Description:
- This routine puts a byte of input back into the scanner's input stream.
- Arguments:
- Input - Supplies a pointer to the input scanner structure.
- Character - Supplies the character to put back.
- Return Value:
- None.
- --*/
- {
- ASSERT(Input->ValidUnputCharacters < SCANNER_UNPUT_SIZE);
- Input->UnputCharacters[Input->ValidUnputCharacters] = Character;
- Input->ValidUnputCharacters += 1;
- return;
- }
- VOID
- RtlpScannerWideUnput (
- PSCAN_INPUT Input,
- WCHAR Character
- )
- /*++
- Routine Description:
- This routine puts a wide character of input back into a byte-oriented
- scanner's input stream.
- Arguments:
- Input - Supplies a pointer to the input scanner structure.
- Character - Supplies the character to put back.
- Return Value:
- None.
- --*/
- {
- CHAR Buffer[MULTIBYTE_MAX];
- ULONG BufferSize;
- ULONG ByteIndex;
- KSTATUS Status;
- ASSERT(Input->ValidUnputCharacters < SCANNER_UNPUT_SIZE);
- BufferSize = MULTIBYTE_MAX;
- Status = RtlConvertWideCharacterToMultibyte(Character,
- Buffer,
- &BufferSize,
- &(Input->State));
- if (KSUCCESS(Status)) {
- for (ByteIndex = 0; ByteIndex < BufferSize; ByteIndex += 1) {
- if (Input->ValidUnputCharacters >= SCANNER_UNPUT_SIZE) {
- break;
- }
- Input->UnputCharacters[Input->ValidUnputCharacters] =
- Buffer[ByteIndex];
- Input->ValidUnputCharacters += 1;
- }
- }
- return;
- }
- BOOL
- RtlpScannerGetInput (
- PSCAN_INPUT Input,
- PCHAR Character
- )
- /*++
- Routine Description:
- This routine retrieves another byte of input from the input scanner.
- Arguments:
- Input - Supplies a pointer to the input scanner structure.
- Character - Supplies a pointer where the character will be returned on
- success.
- Return Value:
- TRUE if a character was read.
- FALSE if the end of the file or string was encountered.
- --*/
- {
- if (Input->ValidUnputCharacters != 0) {
- *Character = Input->UnputCharacters[Input->ValidUnputCharacters - 1];
- Input->ValidUnputCharacters -= 1;
- return TRUE;
- }
- return Input->ReadU.GetInput(Input, Character);
- }
- BOOL
- RtlpScannerGetWideInput (
- PSCAN_INPUT Input,
- PWCHAR WideCharacter
- )
- /*++
- Routine Description:
- This routine retrieves wide input character from a byte oriented scanner
- input.
- Arguments:
- Input - Supplies a pointer to the input scanner structure.
- WideCharacter - Supplies a pointer where the wide character will be
- returned on success.
- Return Value:
- TRUE if a character was read.
- FALSE if the end of the file or string was encountered.
- --*/
- {
- PSTR Buffer;
- ULONG BufferSize;
- CHAR MultibyteBuffer[MULTIBYTE_MAX];
- ULONG MultibyteBufferSize;
- BOOL Result;
- KSTATUS Status;
- MultibyteBufferSize = 0;
- while (TRUE) {
- Result = RtlpScannerGetInput(Input,
- &(MultibyteBuffer[MultibyteBufferSize]));
- if (Result == FALSE) {
- return FALSE;
- }
- MultibyteBufferSize += 1;
- Buffer = MultibyteBuffer;
- BufferSize = MultibyteBufferSize;
- Status = RtlConvertMultibyteCharacterToWide(&Buffer,
- &BufferSize,
- WideCharacter,
- &(Input->State));
- if (KSUCCESS(Status)) {
- break;
- } else if (Status != STATUS_BUFFER_TOO_SMALL) {
- return FALSE;
- }
- if (MultibyteBufferSize >= MULTIBYTE_MAX) {
- ASSERT(FALSE);
- return FALSE;
- }
- }
- return TRUE;
- }
- BOOL
- RtlpStringScannerGetInput (
- PSCAN_INPUT Input,
- PCHAR Character
- )
- /*++
- Routine Description:
- This routine retrieves another byte of input from the input scanner for a
- string based scanner.
- Arguments:
- Input - Supplies a pointer to the input scanner structure.
- Character - Supplies a pointer where the character will be returned on
- success.
- Return Value:
- TRUE if a character was read.
- FALSE if the end of the file or string was encountered.
- --*/
- {
- if (Input->StringSize == 0) {
- return FALSE;
- }
- Input->CharactersRead += 1;
- Input->StringSize -= 1;
- *Character = *(Input->DataU.String);
- Input->DataU.String += 1;
- return TRUE;
- }
|