Option.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. //---------------------------------------------------------------------------
  2. #include <CorePCH.h>
  3. #pragma hdrstop
  4. #include "Option.h"
  5. //---------------------------------------------------------------------------
  6. #pragma package(smart_init)
  7. //---------------------------------------------------------------------------
  8. const wchar_t ArrayValueDelimiter = L'[';
  9. const wchar_t ArrayValueEnd = L']';
  10. //---------------------------------------------------------------------------
  11. __fastcall TOptions::TOptions()
  12. {
  13. FSwitchMarks = L"/-";
  14. FSwitchValueDelimiters = UnicodeString(L"=:") + ArrayValueDelimiter;
  15. FNoMoreSwitches = false;
  16. FParamCount = 0;
  17. }
  18. //---------------------------------------------------------------------------
  19. __fastcall TOptions::TOptions(const TOptions & Source)
  20. {
  21. FSwitchMarks = Source.FSwitchMarks;
  22. FSwitchValueDelimiters = Source.FSwitchValueDelimiters;
  23. FOptions = Source.FOptions;
  24. FOriginalOptions = Source.FOriginalOptions;
  25. FNoMoreSwitches = Source.FNoMoreSwitches;
  26. FParamCount = Source.FParamCount;
  27. }
  28. //---------------------------------------------------------------------------
  29. void __fastcall TOptions::Parse(const UnicodeString & CmdLine)
  30. {
  31. UnicodeString ACmdLine = CmdLine;
  32. UnicodeString Param;
  33. while (CutToken(ACmdLine, Param))
  34. {
  35. Add(Param);
  36. }
  37. }
  38. //---------------------------------------------------------------------------
  39. void __fastcall TOptions::Add(UnicodeString Value)
  40. {
  41. if (!FNoMoreSwitches &&
  42. (Value.Length() == 2) &&
  43. (Value[1] == Value[2]) &&
  44. (FSwitchMarks.Pos(Value[1]) > 0))
  45. {
  46. FNoMoreSwitches = true;
  47. }
  48. else
  49. {
  50. bool Switch = false;
  51. int Index = 0; // shut up
  52. wchar_t SwitchMark = L'\0';
  53. wchar_t ValueDelimiter = L'\0';
  54. if (!FNoMoreSwitches &&
  55. (Value.Length() >= 2) &&
  56. (FSwitchMarks.Pos(Value[1]) > 0))
  57. {
  58. Index = 2;
  59. Switch = true;
  60. SwitchMark = Value[1];
  61. while (Switch && (Index <= Value.Length()))
  62. {
  63. if (Value.IsDelimiter(FSwitchValueDelimiters, Index))
  64. {
  65. ValueDelimiter = Value[Index];
  66. break;
  67. }
  68. // This is to treat /home/martin as parameter, not as switch.
  69. else if ((Value[Index] == L'?') ||
  70. IsLetter(Value[Index]) ||
  71. ((Value[Index] == L'-') && (SwitchMark == L'-') && (Value[2] == L'-'))) // allow --puttygen-switches
  72. {
  73. // noop
  74. }
  75. else
  76. {
  77. Switch = false;
  78. break;
  79. }
  80. ++Index;
  81. }
  82. }
  83. TOption Option;
  84. if (Switch)
  85. {
  86. Option.Type = otSwitch;
  87. Option.Name = Value.SubString(2, Index - 2);
  88. Option.Value = Value.SubString(Index + 1, Value.Length());
  89. if ((ValueDelimiter == ArrayValueDelimiter) && EndsStr(ArrayValueEnd, Option.Value))
  90. {
  91. Option.Value.SetLength(Option.Value.Length() - 1);
  92. }
  93. Option.ValueSet = (Index <= Value.Length());
  94. }
  95. else
  96. {
  97. Option.Type = otParam;
  98. Option.Value = Value;
  99. Option.ValueSet = false; // unused
  100. ++FParamCount;
  101. }
  102. Option.Used = false;
  103. Option.SwitchMark = SwitchMark;
  104. FOptions.push_back(Option);
  105. }
  106. FOriginalOptions = FOptions;
  107. }
  108. //---------------------------------------------------------------------------
  109. UnicodeString __fastcall TOptions::GetParam(int Index)
  110. {
  111. DebugAssert((Index >= 1) && (Index <= FParamCount));
  112. UnicodeString Result;
  113. size_t I = 0;
  114. while ((I < FOptions.size()) && (Index > 0))
  115. {
  116. if (FOptions[I].Type == otParam)
  117. {
  118. --Index;
  119. if (Index == 0)
  120. {
  121. Result = FOptions[I].Value;
  122. FOptions[I].Used = true;
  123. }
  124. }
  125. ++I;
  126. }
  127. return Result;
  128. }
  129. //---------------------------------------------------------------------------
  130. UnicodeString TOptions::ConsumeParam()
  131. {
  132. UnicodeString Result = Param[1];
  133. ParamsProcessed(1, 1);
  134. return Result;
  135. }
  136. //---------------------------------------------------------------------------
  137. bool __fastcall TOptions::GetEmpty()
  138. {
  139. return FOptions.empty();
  140. }
  141. //---------------------------------------------------------------------------
  142. bool __fastcall TOptions::FindSwitch(const UnicodeString Switch,
  143. UnicodeString & Value, int & ParamsStart, int & ParamsCount, bool CaseSensitive, bool & ValueSet)
  144. {
  145. ParamsStart = 0;
  146. ValueSet = false;
  147. int Index = 0;
  148. bool Found = false;
  149. while ((Index < int(FOptions.size())) && !Found)
  150. {
  151. if (FOptions[Index].Type == otParam)
  152. {
  153. ParamsStart++;
  154. }
  155. else if (FOptions[Index].Type == otSwitch)
  156. {
  157. if ((!CaseSensitive && SameText(FOptions[Index].Name, Switch)) ||
  158. (CaseSensitive && SameStr(FOptions[Index].Name, Switch)))
  159. {
  160. Found = true;
  161. Value = FOptions[Index].Value;
  162. ValueSet = FOptions[Index].ValueSet;
  163. FOptions[Index].Used = true;
  164. }
  165. }
  166. Index++;
  167. }
  168. ParamsCount = 0;
  169. if (Found)
  170. {
  171. ParamsStart++;
  172. while ((Index + ParamsCount < int(FOptions.size())) &&
  173. (FOptions[Index + ParamsCount].Type == otParam))
  174. {
  175. ParamsCount++;
  176. }
  177. }
  178. else
  179. {
  180. ParamsStart = 0;
  181. }
  182. return Found;
  183. }
  184. //---------------------------------------------------------------------------
  185. bool __fastcall TOptions::FindSwitch(const UnicodeString Switch, UnicodeString & Value)
  186. {
  187. bool ValueSet;
  188. return FindSwitch(Switch, Value, ValueSet);
  189. }
  190. //---------------------------------------------------------------------------
  191. bool __fastcall TOptions::FindSwitch(const UnicodeString Switch, UnicodeString & Value, bool & ValueSet)
  192. {
  193. int ParamsStart;
  194. int ParamsCount;
  195. return FindSwitch(Switch, Value, ParamsStart, ParamsCount, false, ValueSet);
  196. }
  197. //---------------------------------------------------------------------------
  198. bool __fastcall TOptions::FindSwitch(const UnicodeString Switch)
  199. {
  200. UnicodeString Value;
  201. int ParamsStart;
  202. int ParamsCount;
  203. bool ValueSet;
  204. return FindSwitch(Switch, Value, ParamsStart, ParamsCount, false, ValueSet);
  205. }
  206. //---------------------------------------------------------------------------
  207. bool __fastcall TOptions::FindSwitchCaseSensitive(const UnicodeString Switch)
  208. {
  209. UnicodeString Value;
  210. int ParamsStart;
  211. int ParamsCount;
  212. bool ValueSet;
  213. return FindSwitch(Switch, Value, ParamsStart, ParamsCount, true, ValueSet);
  214. }
  215. //---------------------------------------------------------------------------
  216. bool __fastcall TOptions::FindSwitch(const UnicodeString Switch,
  217. TStrings * Params, int ParamsMax)
  218. {
  219. return DoFindSwitch(Switch, Params, ParamsMax, false);
  220. }
  221. //---------------------------------------------------------------------------
  222. bool __fastcall TOptions::FindSwitchCaseSensitive(const UnicodeString Switch,
  223. TStrings * Params, int ParamsMax)
  224. {
  225. return DoFindSwitch(Switch, Params, ParamsMax, true);
  226. }
  227. //---------------------------------------------------------------------------
  228. bool __fastcall TOptions::DoFindSwitch(const UnicodeString Switch,
  229. TStrings * Params, int ParamsMax, bool CaseSensitive)
  230. {
  231. UnicodeString Value;
  232. int ParamsStart;
  233. int ParamsCount;
  234. bool ValueSet;
  235. bool Result = FindSwitch(Switch, Value, ParamsStart, ParamsCount, CaseSensitive, ValueSet);
  236. if (Result)
  237. {
  238. int AParamsCount;
  239. if (TryStrToInt(Value, AParamsCount) && (AParamsCount < ParamsCount))
  240. {
  241. ParamsCount = AParamsCount;
  242. }
  243. if ((ParamsMax >= 0) && (ParamsCount > ParamsMax))
  244. {
  245. ParamsCount = ParamsMax;
  246. }
  247. int Index = 0;
  248. while (Index < ParamsCount)
  249. {
  250. Params->Add(Param[ParamsStart + Index]);
  251. Index++;
  252. }
  253. ParamsProcessed(ParamsStart, ParamsCount);
  254. }
  255. return Result;
  256. }
  257. //---------------------------------------------------------------------------
  258. UnicodeString __fastcall TOptions::SwitchValue(const UnicodeString Switch,
  259. const UnicodeString Default)
  260. {
  261. UnicodeString Value;
  262. FindSwitch(Switch, Value);
  263. if (Value.IsEmpty())
  264. {
  265. Value = Default;
  266. }
  267. return Value;
  268. }
  269. //---------------------------------------------------------------------------
  270. bool __fastcall TOptions::SwitchValue(const UnicodeString Switch, bool Default, bool DefaultOnNonExistence)
  271. {
  272. bool Result;
  273. int IntValue;
  274. UnicodeString Value;
  275. if (!FindSwitch(Switch, Value))
  276. {
  277. Result = DefaultOnNonExistence;
  278. }
  279. else if (Value.IsEmpty())
  280. {
  281. Result = Default;
  282. }
  283. else if (SameText(Value, "on"))
  284. {
  285. Result = true;
  286. }
  287. else if (SameText(Value, "off"))
  288. {
  289. Result = false;
  290. }
  291. else if (TryStrToInt(Value, IntValue))
  292. {
  293. Result = (IntValue != 0);
  294. }
  295. else
  296. {
  297. throw Exception(FMTLOAD(URL_OPTION_BOOL_VALUE_ERROR, (Value)));
  298. }
  299. return Result;
  300. }
  301. //---------------------------------------------------------------------------
  302. bool __fastcall TOptions::SwitchValue(const UnicodeString Switch, bool Default)
  303. {
  304. return SwitchValue(Switch, Default, Default);
  305. }
  306. //---------------------------------------------------------------------------
  307. bool __fastcall TOptions::UnusedSwitch(UnicodeString & Switch)
  308. {
  309. bool Result = false;
  310. size_t Index = 0;
  311. while (!Result && (Index < FOptions.size()))
  312. {
  313. if ((FOptions[Index].Type == otSwitch) &&
  314. !FOptions[Index].Used)
  315. {
  316. Switch = FOptions[Index].Name;
  317. Result = true;
  318. }
  319. ++Index;
  320. }
  321. return Result;
  322. }
  323. //---------------------------------------------------------------------------
  324. bool __fastcall TOptions::WasSwitchAdded(UnicodeString & Switch, UnicodeString & Value, wchar_t & SwitchMark)
  325. {
  326. bool Result =
  327. DebugAlwaysTrue(FOptions.size() > 0) &&
  328. (FOptions.back().Type == otSwitch);
  329. if (Result)
  330. {
  331. TOption & Option = FOptions.back();
  332. Switch = Option.Name;
  333. Value = Option.Value;
  334. SwitchMark = Option.SwitchMark;
  335. }
  336. return Result;
  337. }
  338. //---------------------------------------------------------------------------
  339. void __fastcall TOptions::ParamsProcessed(int ParamsStart, int ParamsCount)
  340. {
  341. if (ParamsCount > 0)
  342. {
  343. DebugAssert((ParamsStart >= 0) && ((ParamsStart - ParamsCount + 1) <= FParamCount));
  344. size_t Index = 0;
  345. while ((Index < FOptions.size()) && (ParamsStart > 0))
  346. {
  347. if (FOptions[Index].Type == otParam)
  348. {
  349. --ParamsStart;
  350. if (ParamsStart == 0)
  351. {
  352. while (ParamsCount > 0)
  353. {
  354. DebugAssert(Index < FOptions.size());
  355. DebugAssert(FOptions[Index].Type == otParam);
  356. FOptions.erase(FOptions.begin() + Index);
  357. --FParamCount;
  358. --ParamsCount;
  359. }
  360. }
  361. }
  362. Index++;
  363. }
  364. }
  365. }
  366. //---------------------------------------------------------------------------
  367. void __fastcall TOptions::LogOptions(TLogOptionEvent OnLogOption)
  368. {
  369. for (size_t Index = 0; Index < FOriginalOptions.size(); Index++)
  370. {
  371. const TOption & Option = FOriginalOptions[Index];
  372. UnicodeString LogStr;
  373. switch (Option.Type)
  374. {
  375. case otParam:
  376. LogStr = FORMAT(L"Parameter: %s", (Option.Value));
  377. DebugAssert(Option.Name.IsEmpty());
  378. break;
  379. case otSwitch:
  380. LogStr =
  381. FORMAT(L"Switch: %s%s%s%s",
  382. (FSwitchMarks[1], Option.Name, (Option.Value.IsEmpty() ? UnicodeString() : FSwitchValueDelimiters.SubString(1, 1)), Option.Value));
  383. break;
  384. default:
  385. DebugFail();
  386. break;
  387. }
  388. OnLogOption(LogStr);
  389. }
  390. }