1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/core/Option.cpp
Martin Prikryl b13e2e7c2b #pragma package(smart_init) is not useful out of packages
Source commit: 7635ac3b532214f27ea2b6fe6aa80398c857cfcd
2025-08-23 01:06:48 +02:00

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);
}
}