mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
405 lines
11 KiB
C++
405 lines
11 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <CorePCH.h>
|
|
#pragma hdrstop
|
|
|
|
#include "Option.h"
|
|
//---------------------------------------------------------------------------
|
|
const wchar_t ArrayValueDelimiter = L'[';
|
|
const wchar_t ArrayValueEnd = L']';
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TOptions::TOptions()
|
|
{
|
|
FSwitchMarks = L"/-";
|
|
FSwitchValueDelimiters = UnicodeString(L"=:") + ArrayValueDelimiter;
|
|
FNoMoreSwitches = false;
|
|
FParamCount = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TOptions::TOptions(const TOptions & Source)
|
|
{
|
|
FSwitchMarks = Source.FSwitchMarks;
|
|
FSwitchValueDelimiters = Source.FSwitchValueDelimiters;
|
|
FOptions = Source.FOptions;
|
|
FOriginalOptions = Source.FOriginalOptions;
|
|
FNoMoreSwitches = Source.FNoMoreSwitches;
|
|
FParamCount = Source.FParamCount;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TOptions::Parse(const UnicodeString & CmdLine)
|
|
{
|
|
UnicodeString ACmdLine = CmdLine;
|
|
UnicodeString Param;
|
|
while (CutToken(ACmdLine, Param))
|
|
{
|
|
Add(Param);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TOptions::Add(UnicodeString Value)
|
|
{
|
|
if (!FNoMoreSwitches &&
|
|
(Value.Length() == 2) &&
|
|
(Value[1] == Value[2]) &&
|
|
(FSwitchMarks.Pos(Value[1]) > 0))
|
|
{
|
|
FNoMoreSwitches = true;
|
|
}
|
|
else
|
|
{
|
|
bool Switch = false;
|
|
int Index = 0; // shut up
|
|
wchar_t SwitchMark = L'\0';
|
|
wchar_t ValueDelimiter = L'\0';
|
|
if (!FNoMoreSwitches &&
|
|
(Value.Length() >= 2) &&
|
|
(FSwitchMarks.Pos(Value[1]) > 0))
|
|
{
|
|
Index = 2;
|
|
Switch = true;
|
|
SwitchMark = Value[1];
|
|
while (Switch && (Index <= Value.Length()))
|
|
{
|
|
if (Value.IsDelimiter(FSwitchValueDelimiters, Index))
|
|
{
|
|
ValueDelimiter = Value[Index];
|
|
break;
|
|
}
|
|
// This is to treat /home/martin as parameter, not as switch.
|
|
else if ((Value[Index] == L'?') ||
|
|
IsLetter(Value[Index]) ||
|
|
((Value[Index] == L'-') && (SwitchMark == L'-') && (Value[2] == L'-'))) // allow --puttygen-switches
|
|
{
|
|
// noop
|
|
}
|
|
else
|
|
{
|
|
Switch = false;
|
|
break;
|
|
}
|
|
++Index;
|
|
}
|
|
}
|
|
|
|
TOption Option;
|
|
|
|
if (Switch)
|
|
{
|
|
Option.Type = otSwitch;
|
|
Option.Name = Value.SubString(2, Index - 2);
|
|
Option.Value = Value.SubString(Index + 1, Value.Length());
|
|
if ((ValueDelimiter == ArrayValueDelimiter) && EndsStr(ArrayValueEnd, Option.Value))
|
|
{
|
|
Option.Value.SetLength(Option.Value.Length() - 1);
|
|
}
|
|
Option.ValueSet = (Index <= Value.Length());
|
|
}
|
|
else
|
|
{
|
|
Option.Type = otParam;
|
|
Option.Value = Value;
|
|
Option.ValueSet = false; // unused
|
|
++FParamCount;
|
|
}
|
|
|
|
Option.Used = false;
|
|
Option.SwitchMark = SwitchMark;
|
|
|
|
FOptions.push_back(Option);
|
|
}
|
|
|
|
FOriginalOptions = FOptions;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TOptions::GetParam(int Index)
|
|
{
|
|
DebugAssert((Index >= 1) && (Index <= FParamCount));
|
|
|
|
UnicodeString Result;
|
|
size_t I = 0;
|
|
while ((I < FOptions.size()) && (Index > 0))
|
|
{
|
|
if (FOptions[I].Type == otParam)
|
|
{
|
|
--Index;
|
|
if (Index == 0)
|
|
{
|
|
Result = FOptions[I].Value;
|
|
FOptions[I].Used = true;
|
|
}
|
|
}
|
|
++I;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString TOptions::ConsumeParam()
|
|
{
|
|
UnicodeString Result = Param[1];
|
|
ParamsProcessed(1, 1);
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::GetEmpty()
|
|
{
|
|
return FOptions.empty();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitch(const UnicodeString Switch,
|
|
UnicodeString & Value, int & ParamsStart, int & ParamsCount, bool CaseSensitive, bool & ValueSet)
|
|
{
|
|
ParamsStart = 0;
|
|
ValueSet = false;
|
|
int Index = 0;
|
|
bool Found = false;
|
|
while ((Index < int(FOptions.size())) && !Found)
|
|
{
|
|
if (FOptions[Index].Type == otParam)
|
|
{
|
|
ParamsStart++;
|
|
}
|
|
else if (FOptions[Index].Type == otSwitch)
|
|
{
|
|
if ((!CaseSensitive && SameText(FOptions[Index].Name, Switch)) ||
|
|
(CaseSensitive && SameStr(FOptions[Index].Name, Switch)))
|
|
{
|
|
Found = true;
|
|
Value = FOptions[Index].Value;
|
|
ValueSet = FOptions[Index].ValueSet;
|
|
FOptions[Index].Used = true;
|
|
}
|
|
}
|
|
Index++;
|
|
}
|
|
|
|
ParamsCount = 0;
|
|
if (Found)
|
|
{
|
|
ParamsStart++;
|
|
while ((Index + ParamsCount < int(FOptions.size())) &&
|
|
(FOptions[Index + ParamsCount].Type == otParam))
|
|
{
|
|
ParamsCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParamsStart = 0;
|
|
}
|
|
|
|
return Found;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitch(const UnicodeString Switch, UnicodeString & Value)
|
|
{
|
|
bool ValueSet;
|
|
return FindSwitch(Switch, Value, ValueSet);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitch(const UnicodeString Switch, UnicodeString & Value, bool & ValueSet)
|
|
{
|
|
int ParamsStart;
|
|
int ParamsCount;
|
|
return FindSwitch(Switch, Value, ParamsStart, ParamsCount, false, ValueSet);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitch(const UnicodeString Switch)
|
|
{
|
|
UnicodeString Value;
|
|
int ParamsStart;
|
|
int ParamsCount;
|
|
bool ValueSet;
|
|
return FindSwitch(Switch, Value, ParamsStart, ParamsCount, false, ValueSet);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitchCaseSensitive(const UnicodeString Switch)
|
|
{
|
|
UnicodeString Value;
|
|
int ParamsStart;
|
|
int ParamsCount;
|
|
bool ValueSet;
|
|
return FindSwitch(Switch, Value, ParamsStart, ParamsCount, true, ValueSet);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitch(const UnicodeString Switch,
|
|
TStrings * Params, int ParamsMax)
|
|
{
|
|
return DoFindSwitch(Switch, Params, ParamsMax, false);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::FindSwitchCaseSensitive(const UnicodeString Switch,
|
|
TStrings * Params, int ParamsMax)
|
|
{
|
|
return DoFindSwitch(Switch, Params, ParamsMax, true);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::DoFindSwitch(const UnicodeString Switch,
|
|
TStrings * Params, int ParamsMax, bool CaseSensitive)
|
|
{
|
|
UnicodeString Value;
|
|
int ParamsStart;
|
|
int ParamsCount;
|
|
bool ValueSet;
|
|
bool Result = FindSwitch(Switch, Value, ParamsStart, ParamsCount, CaseSensitive, ValueSet);
|
|
if (Result)
|
|
{
|
|
int AParamsCount;
|
|
if (TryStrToInt(Value, AParamsCount) && (AParamsCount < ParamsCount))
|
|
{
|
|
ParamsCount = AParamsCount;
|
|
}
|
|
if ((ParamsMax >= 0) && (ParamsCount > ParamsMax))
|
|
{
|
|
ParamsCount = ParamsMax;
|
|
}
|
|
|
|
int Index = 0;
|
|
while (Index < ParamsCount)
|
|
{
|
|
Params->Add(Param[ParamsStart + Index]);
|
|
Index++;
|
|
}
|
|
ParamsProcessed(ParamsStart, ParamsCount);
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
UnicodeString __fastcall TOptions::SwitchValue(const UnicodeString Switch,
|
|
const UnicodeString Default)
|
|
{
|
|
UnicodeString Value;
|
|
FindSwitch(Switch, Value);
|
|
if (Value.IsEmpty())
|
|
{
|
|
Value = Default;
|
|
}
|
|
return Value;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::SwitchValue(const UnicodeString Switch, bool Default, bool DefaultOnNonExistence)
|
|
{
|
|
bool Result;
|
|
int IntValue;
|
|
UnicodeString Value;
|
|
if (!FindSwitch(Switch, Value))
|
|
{
|
|
Result = DefaultOnNonExistence;
|
|
}
|
|
else if (Value.IsEmpty())
|
|
{
|
|
Result = Default;
|
|
}
|
|
else if (SameText(Value, "on"))
|
|
{
|
|
Result = true;
|
|
}
|
|
else if (SameText(Value, "off"))
|
|
{
|
|
Result = false;
|
|
}
|
|
else if (TryStrToInt(Value, IntValue))
|
|
{
|
|
Result = (IntValue != 0);
|
|
}
|
|
else
|
|
{
|
|
throw Exception(FMTLOAD(URL_OPTION_BOOL_VALUE_ERROR, (Value)));
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::SwitchValue(const UnicodeString Switch, bool Default)
|
|
{
|
|
return SwitchValue(Switch, Default, Default);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::UnusedSwitch(UnicodeString & Switch)
|
|
{
|
|
bool Result = false;
|
|
size_t Index = 0;
|
|
while (!Result && (Index < FOptions.size()))
|
|
{
|
|
if ((FOptions[Index].Type == otSwitch) &&
|
|
!FOptions[Index].Used)
|
|
{
|
|
Switch = FOptions[Index].Name;
|
|
Result = true;
|
|
}
|
|
++Index;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
bool __fastcall TOptions::WasSwitchAdded(UnicodeString & Switch, UnicodeString & Value, wchar_t & SwitchMark)
|
|
{
|
|
bool Result =
|
|
DebugAlwaysTrue(FOptions.size() > 0) &&
|
|
(FOptions.back().Type == otSwitch);
|
|
if (Result)
|
|
{
|
|
TOption & Option = FOptions.back();
|
|
Switch = Option.Name;
|
|
Value = Option.Value;
|
|
SwitchMark = Option.SwitchMark;
|
|
}
|
|
return Result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
|
|
{
|
|
if (ParamsCount > 0)
|
|
{
|
|
DebugAssert((ParamsStart >= 0) && ((ParamsStart - ParamsCount + 1) <= FParamCount));
|
|
|
|
size_t Index = 0;
|
|
while ((Index < FOptions.size()) && (ParamsStart > 0))
|
|
{
|
|
if (FOptions[Index].Type == otParam)
|
|
{
|
|
--ParamsStart;
|
|
|
|
if (ParamsStart == 0)
|
|
{
|
|
while (ParamsCount > 0)
|
|
{
|
|
DebugAssert(Index < FOptions.size());
|
|
DebugAssert(FOptions[Index].Type == otParam);
|
|
FOptions.erase(FOptions.begin() + Index);
|
|
--FParamCount;
|
|
--ParamsCount;
|
|
}
|
|
}
|
|
}
|
|
Index++;
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TOptions::LogOptions(TLogOptionEvent OnLogOption)
|
|
{
|
|
for (size_t Index = 0; Index < FOriginalOptions.size(); Index++)
|
|
{
|
|
const TOption & Option = FOriginalOptions[Index];
|
|
UnicodeString LogStr;
|
|
switch (Option.Type)
|
|
{
|
|
case otParam:
|
|
LogStr = FORMAT(L"Parameter: %s", (Option.Value));
|
|
DebugAssert(Option.Name.IsEmpty());
|
|
break;
|
|
|
|
case otSwitch:
|
|
LogStr =
|
|
FORMAT(L"Switch: %s%s%s%s",
|
|
(FSwitchMarks[1], Option.Name, (Option.Value.IsEmpty() ? UnicodeString() : FSwitchValueDelimiters.SubString(1, 1)), Option.Value));
|
|
break;
|
|
|
|
default:
|
|
DebugFail();
|
|
break;
|
|
}
|
|
OnLogOption(LogStr);
|
|
}
|
|
}
|