Option.cpp 11 KB

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