| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "CommonCorePch.h"
- #include "Core/ICustomConfigFlags.h"
- #include "Core/CmdParser.h"
- using namespace Js;
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParseString
- ///
- /// Parses a string token. There are 2 ways to specify it.
- /// 1. Quoted - " " Any character within quotes is parsed as string.
- /// if the quotes are not closed, its an error.
- /// 2. UnQuoted - End of string is indicated by a space/end of stream.
- /// If fTreatColonAsSeparator is mentioned, then we break
- /// at colon also.
- ///
- ///
- /// Empty string "" is treated as Exception()
- ///
- ///----------------------------------------------------------------------------
- LPWSTR
- CmdLineArgsParser::ParseString(__inout_ecount(ceBuffer) LPWSTR buffer, size_t ceBuffer, bool fTreatColonAsSeparator)
- {
- char16 *out = buffer;
- size_t len = 0;
- if('"' == CurChar())
- {
- NextChar();
- while('"' != CurChar())
- {
- if(0 == CurChar())
- {
- throw Exception(_u("Unmatched quote"));
- }
- //
- // MaxTokenSize - 1 because we need 1 extra position for null termination
- //
- if (len >= ceBuffer - 1)
- {
- throw Exception(_u("String token too large to parse"));
- }
- out[len++] = CurChar();
- NextChar();
- }
- NextChar();
- }
- else
- {
- bool fDone = false;
- while(!fDone)
- {
- switch(CurChar())
- {
- case ' ':
- case ',':
- case 0:
- fDone = true;
- break;
- case '-':
- case '=':
- case ':':
- if (fTreatColonAsSeparator)
- {
- fDone = true;
- break;
- }
- else
- {
- // Fallthrough
- }
- default:
- if (len >= MaxTokenSize - 1)
- {
- throw Exception(_u("String token too large to parse"));
- }
- out[len++] = CurChar();
- NextChar();
- }
- }
- }
- if(0 == len)
- {
- throw Exception(_u("String Token Expected"));
- }
- out[len] = '\0';
- return buffer;
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParseSourceFunctionIds
- ///
- /// Parses for sourceContextId and FunctionId pairs
- ///----------------------------------------------------------------------------
- Js::SourceFunctionNode
- CmdLineArgsParser::ParseSourceFunctionIds()
- {
- uint functionId, sourceId;
- if ('*' == CurChar())
- {
- sourceId = 1;
- functionId = (uint)-2;
- NextChar();
- }
- else if ('+' == CurChar())
- {
- sourceId = 1;
- functionId = (uint)-1;
- NextChar();
- }
- else
- {
- functionId = sourceId = ParseInteger();
- if ('.' == CurChar())
- {
- NextChar();
- if ('*' == CurChar())
- {
- functionId = (uint)-2;
- NextChar();
- }
- else if ('+' == CurChar())
- {
- functionId = (uint)-1;
- NextChar();
- }
- else
- {
- functionId = ParseInteger();
- }
- }
- else
- {
- sourceId = 1;
- }
- }
- return SourceFunctionNode(sourceId, functionId);
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParseInteger
- ///
- /// Parses signed integer. Checks for overflow and underflows.
- ///----------------------------------------------------------------------------
- int
- CmdLineArgsParser::ParseInteger()
- {
- int result = 0;
- int sign = 1;
- if('-' == CurChar())
- {
- sign = -1;
- NextChar();
- }
- if(!IsDigit())
- {
- throw Exception(_u("Integer Expected"));
- }
- int base = 10;
- if ('0' == CurChar())
- {
- NextChar();
- if (CurChar() == 'x')
- {
- NextChar();
- base = 16;
- }
- // Should the else case be parse as octal?
- }
- while(IsDigit() || (base == 16 && IsHexDigit()))
- {
- int currentDigit = (int)(CurChar() - '0');
- if (currentDigit > 9)
- {
- Assert(base == 16);
- if (CurChar() < 'F')
- {
- currentDigit = 10 + (int)(CurChar() - 'A');
- }
- else
- {
- currentDigit = 10 + (int)(CurChar() - 'a');
- }
- Assert(currentDigit < 16);
- }
- result = result * base + (int)(CurChar() - '0');
- if(result < 0)
- {
- // overflow or underflow in case sign = -1
- throw Exception(_u("Integer too large to parse"));
- }
- NextChar();
- }
- return result * sign;
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParseRange
- ///
- /// Parses :-
- /// range = int | int '-' int | range, range
- ///
- ///----------------------------------------------------------------------------
- void
- CmdLineArgsParser::ParseRange(Js::Range *pRange, Js::Range *oppositeRange)
- {
- SourceFunctionNode r1 = ParseSourceFunctionIds();
- SourceFunctionNode r2;
- switch(CurChar())
- {
- case '-':
- NextChar();
- r2 = ParseSourceFunctionIds();
- if (r1.sourceContextId > r2.sourceContextId)
- {
- throw Exception(_u("Left source index must be smaller than the Right source Index"));
- }
- if ((r1.sourceContextId == r2.sourceContextId) &&
- (r1.functionId > r2.functionId))
- {
- throw Exception(_u("Left functionId must be smaller than the Right functionId when Source file is the same"));
- }
- pRange->Add(r1, r2, oppositeRange);
- switch(CurChar())
- {
- case ',':
- NextChar();
- ParseRange(pRange, oppositeRange);
- break;
- case ' ':
- case 0:
- break;
- default:
- throw Exception(_u("Unexpected character while parsing Range"));
- }
- break;
- case ',':
- pRange->Add(r1, oppositeRange);
- NextChar();
- ParseRange(pRange, oppositeRange);
- break;
- case ' ':
- case 0:
- pRange->Add(r1, oppositeRange);
- break;
- default:
- throw Exception(_u("Unexpected character while parsing Range"));
- }
- }
- void
- CmdLineArgsParser::ParseNumberRange(Js::NumberRange *pRange)
- {
- int start = ParseInteger();
- int end;
- switch (CurChar())
- {
- case '-':
- NextChar();
- end = ParseInteger();
- if (start > end)
- {
- throw Exception(_u("Range start must be less than range end"));
- }
- pRange->Add(start, end);
- switch (CurChar())
- {
- case ',':
- NextChar();
- ParseNumberRange(pRange);
- break;
- case ' ':
- case 0:
- break;
- default:
- throw Exception(_u("Unexpected character while parsing Range"));
- }
- break;
- case ',':
- pRange->Add(start);
- NextChar();
- ParseNumberRange(pRange);
- break;
- case ' ':
- case 0:
- pRange->Add(start);
- break;
- default:
- throw Exception(_u("Unexpected character while parsing Range"));
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParsePhase
- ///
- /// Parses comma separated list of:
- /// phase[:range]
- /// phase is a string defined in Js:PhaseNames.
- ///
- ///----------------------------------------------------------------------------
- void
- CmdLineArgsParser::ParsePhase(Js::Phases *pPhaseList, Js::Phases *oppositePhase)
- {
- char16 buffer[MaxTokenSize];
- ZeroMemory(buffer, sizeof(buffer));
- Phase phase = ConfigFlagsTable::GetPhase(ParseString(buffer));
- if(InvalidPhase == phase)
- {
- throw Exception(_u("Invalid phase :"));
- }
- pPhaseList->Enable(phase);
- switch(CurChar())
- {
- case ':':
- {
- NextChar();
- Js::Range* oppositeRange = nullptr;
- if (oppositePhase && oppositePhase->IsEnabled(phase))
- {
- oppositeRange = oppositePhase->GetRange(phase);
- }
- ParseRange(pPhaseList->GetRange(phase), oppositeRange);
- break;
- }
- case ',':
- NextChar();
- if (oppositePhase)
- {
- // The whole phase is turned on/off so disable the opposite
- oppositePhase->Disable(phase);
- }
- ParsePhase(pPhaseList, oppositePhase);
- break;
- default:
- if (oppositePhase)
- {
- // The whole phase is turned on/off so disable the opposite
- oppositePhase->Disable(phase);
- }
- pPhaseList->GetRange(phase)->Clear();
- break;
- }
- }
- void
- CmdLineArgsParser::ParseNumberSet(Js::NumberSet * numberPairSet)
- {
- while (true)
- {
- int x = ParseInteger();
- numberPairSet->Add(x);
- if (CurChar() != ';')
- {
- break;
- }
- NextChar();
- }
- }
- void
- CmdLineArgsParser::ParseNumberPairSet(Js::NumberPairSet * numberPairSet)
- {
- while (true)
- {
- int line = ParseInteger();
- int col = -1;
- if (CurChar() == ',')
- {
- NextChar();
- col = ParseInteger();
- }
- numberPairSet->Add(line, col);
- if (CurChar() != ';')
- {
- break;
- }
- NextChar();
- }
- }
- void
- CmdLineArgsParser::ParseNumberTrioSet(Js::NumberTrioSet * numberTrioSet)
- {
- while (true)
- {
- int line = ParseInteger();
- int col = -1;
- int stmt = -1;
- if (CurChar() == ',')
- {
- NextChar();
- col = ParseInteger();
- }
- if (CurChar() == ',')
- {
- NextChar();
- stmt = ParseInteger();
- }
- numberTrioSet->Add(line, col, stmt);
- if (CurChar() != ';')
- {
- break;
- }
- NextChar();
- }
- }
- bool
- CmdLineArgsParser::ParseBoolean()
- {
- if (CurChar() == ':')
- {
- throw Exception(_u("':' not expected with a boolean flag"));
- }
- else if (CurChar() != '-' && CurChar() != ' ' && CurChar() != 0)
- {
- throw Exception(_u("Invalid character after boolean flag"));
- }
- else
- {
- return (CurChar() != '-');
- }
- }
- BSTR
- CmdLineArgsParser::GetCurrentString()
- {
- char16 buffer[MaxTokenSize];
- ZeroMemory(buffer, sizeof(buffer));
- switch (CurChar())
- {
- case ':':
- NextChar();
- return SysAllocString(ParseString(buffer, MaxTokenSize, false));
- case ' ':
- case 0:
- NextChar();
- return nullptr;
- default:
- throw Exception(_u("Expected ':'"));
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::ParseFlag
- ///
- /// Parses:
- /// flag[:parameter]
- /// Flag is a string defined in Js:FlagNames.
- /// The type of expected parameter depends upon the flag. It can be
- /// 1. String
- /// 2. Number
- /// 3. Boolean
- /// 4. Phase
- ///
- /// In case of boolean the presence no parameter is expected. the value of the
- /// boolean flag is set to 'true'
- ///
- ///----------------------------------------------------------------------------
- void
- CmdLineArgsParser::ParseFlag()
- {
- char16 buffer[MaxTokenSize];
- ZeroMemory(buffer, sizeof(buffer));
- LPWSTR flagString = ParseString(buffer);
- Flag flag = ConfigFlagsTable::GetFlag(flagString);
- if(InvalidFlag == flag)
- {
- if (pCustomConfigFlags != nullptr)
- {
- if (pCustomConfigFlags->ParseFlag(flagString, this))
- {
- return;
- }
- }
- throw Exception(_u("Invalid Flag"));
- }
- FlagTypes flagType = ConfigFlagsTable::GetFlagType(flag);
- AssertMsg(InvalidFlagType != flagType, "Invalid flag type");
- this->flagTable.Enable(flag);
- if(FlagBoolean == flagType)
- {
- Boolean boolValue = ParseBoolean();
- this->flagTable.SetAsBoolean(flag, boolValue);
- }
- else
- {
- switch(CurChar())
- {
- case ':':
- NextChar();
- switch(flagType)
- {
- case FlagPhases:
- {
- Flag oppositeFlag = this->flagTable.GetOppositePhaseFlag(flag);
- Phases* oppositePhase = nullptr;
- if (oppositeFlag != InvalidFlag)
- {
- this->flagTable.Enable(oppositeFlag);
- oppositePhase = this->flagTable.GetAsPhase(oppositeFlag);
- }
- ParsePhase(this->flagTable.GetAsPhase(flag), oppositePhase);
- break;
- }
- case FlagString:
- *this->flagTable.GetAsString(flag) = ParseString(buffer, MaxTokenSize, false);
- break;
- case FlagNumber:
- *this->flagTable.GetAsNumber(flag) = ParseInteger();
- break;
- case FlagNumberSet:
- ParseNumberSet(this->flagTable.GetAsNumberSet(flag));
- break;
- case FlagNumberPairSet:
- ParseNumberPairSet(this->flagTable.GetAsNumberPairSet(flag));
- break;
- case FlagNumberTrioSet:
- ParseNumberTrioSet(this->flagTable.GetAsNumberTrioSet(flag));
- break;
- case FlagNumberRange:
- ParseNumberRange(this->flagTable.GetAsNumberRange(flag));
- break;
- default:
- AssertMsg(0, "Flag not Handled");
- }
- break;
- case ' ':
- case 0:
- break;
- default:
- throw Exception(_u("Expected ':'"));
- }
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::Parse
- ///
- /// The main loop which parses 1 flag at a time
- ///
- ///----------------------------------------------------------------------------
- int
- CmdLineArgsParser::Parse(int argc, __in_ecount(argc) LPWSTR argv[])
- {
- int err = 0;
- for(int i = 1; i < argc; i++)
- {
- if ((err = Parse(argv[i])) != 0)
- {
- break;
- }
- }
- if(this->flagTable.Filename == nullptr)
- {
- this->flagTable.Filename = _u("ttdSentinal.js");
- }
- return err;
- }
- int CmdLineArgsParser::Parse(__in LPWSTR oneArg) throw()
- {
- int err = 0;
- char16 buffer[MaxTokenSize];
- ZeroMemory(buffer, sizeof(buffer));
- this->pszCurrentArg = oneArg;
- AssertMsg(NULL != this->pszCurrentArg, "How can command line give NULL argv's");
- try
- {
- switch(CurChar())
- {
- case '-' :
- if ('-' == PeekChar())
- {
- //support --
- NextChar();
- }
- //fallthrough
- #ifdef _WIN32
- // Only support '/' as a command line switch start char on Windows
- // for legacy reason. Deprecate on xplat, as it starts a path on Unix.
- case '/':
- #endif
- NextChar();
- if('?' == CurChar())
- {
- PrintUsage();
- return -1;
- }
- ParseFlag();
- break;
- default:
- if(NULL != this->flagTable.Filename)
- {
- throw Exception(_u("Duplicate filename entry"));
- }
- this->flagTable.Filename = ParseString(buffer, MaxTokenSize, false);
- break;
- }
- }
- catch(Exception &exp)
- {
- Output::Print(_u("%s : %s\n"), (LPCWSTR)exp, oneArg);
- err = -1;
- }
- return err;
- }
- ///----------------------------------------------------------------------------
- ///
- /// CmdLineArgsParser::CmdLineArgsParser
- ///
- /// Constructor
- ///
- ///----------------------------------------------------------------------------
- CmdLineArgsParser::CmdLineArgsParser(ICustomConfigFlags * pCustomConfigFlags, Js::ConfigFlagsTable& flagTable) :
- flagTable(flagTable), pCustomConfigFlags(pCustomConfigFlags)
- {
- this->pszCurrentArg = NULL;
- }
- CmdLineArgsParser::~CmdLineArgsParser()
- {
- flagTable.FinalizeConfiguration();
- }
- void CmdLineArgsParser::PrintUsage()
- {
- if (pCustomConfigFlags)
- {
- pCustomConfigFlags->PrintUsage();
- return;
- }
- Js::ConfigFlagsTable::PrintUsageString();
- }
|