Quick.Parameters.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. { ***************************************************************************
  2. Copyright (c) 2016-2021 Kike Pérez
  3. Unit : Quick.Parameters
  4. Description : Map comandline to class
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 12/07/2020
  8. Modified : 01/08/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Parameters;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. StrUtils,
  28. Generics.Collections,
  29. Quick.Commons,
  30. {$IFDEF CONSOLE}
  31. Quick.Console,
  32. {$ENDIF}
  33. rtti,
  34. TypInfo,
  35. Quick.RTTI.Utils;
  36. type
  37. CommandDescription = class(TCustomAttribute)
  38. private
  39. fDescription : string;
  40. public
  41. constructor Create(const aDescription : string);
  42. property Description : string read fDescription;
  43. end;
  44. ParamCommand = class(TCustomAttribute)
  45. private
  46. fPosition : Integer;
  47. public
  48. constructor Create(aPosition : Integer);
  49. property Position : Integer read fPosition;
  50. end;
  51. ParamName = class(TCustomAttribute)
  52. private
  53. fName : string;
  54. fAlias : string;
  55. public
  56. constructor Create(const aName: string; const aAlias : string = '');
  57. property Name : string read fName;
  58. property Alias : string read fAlias;
  59. end;
  60. ParamValueIsNextParam = class(TCustomAttribute);
  61. ParamHelp = class(TCustomAttribute)
  62. private
  63. fHelp : string;
  64. fValueName : string;
  65. public
  66. constructor Create(const aHelp : string; const aValueName : string = '');
  67. property Help : string read fHelp;
  68. property ValueName : string read fValueName;
  69. end;
  70. ParamSwitchChar = class(TCustomAttribute)
  71. private
  72. fSwithChar : string;
  73. public
  74. constructor Create(const aSwitchChar : string);
  75. property SwitchChar : string read fSwithChar write fSwithChar;
  76. end;
  77. ParamValueSeparator = class(TCustomAttribute)
  78. private
  79. fValueSeparator : string;
  80. public
  81. constructor Create(const aValueSeparator : string);
  82. property ValueSeparator : string read fValueSeparator write fValueSeparator;
  83. end;
  84. ParamRequired = class(TCustomAttribute);
  85. {$IFDEF CONSOLE}
  86. TColorizeHelp = class
  87. private
  88. fCommandName : TConsoleColor;
  89. fCommandDescription : TConsoleColor;
  90. fCommandUsage : TConsoleColor;
  91. fSections : TConsoleColor;
  92. fArgumentName : TConsoleColor;
  93. fArgumentDescription : TConsoleColor;
  94. public
  95. property CommandName : TConsoleColor read fCommandName write fCommandName;
  96. property CommandDescription : TConsoleColor read fCommandDescription write fCommandDescription;
  97. property CommandUsage : TConsoleColor read fCommandUsage write fCommandUsage;
  98. property Sections : TConsoleColor read fSections write fSections;
  99. property ArgumentName : TConsoleColor read fArgumentName write fArgumentName;
  100. property ArgumentDescription : TConsoleColor read fArgumentDescription write fArgumentDescription;
  101. end;
  102. {$ENDIF}
  103. {$M+}
  104. TParameters = class
  105. type
  106. TValueType = (vtString, vtInteger, vtFloat, vtBoolean, vtEnumeration);
  107. TParam = class
  108. private
  109. fName : string;
  110. fAlias : string;
  111. fValue : string;
  112. fPrecisePosition : Integer;
  113. fParamType: TValueType;
  114. fRequired : Boolean;
  115. fHelp : string;
  116. fValueName : string;
  117. fValueIsNextParam: Boolean;
  118. fSwitchChar: string;
  119. fValueSeparator: string;
  120. fIsPresent: Boolean;
  121. public
  122. constructor Create;
  123. property Name : string read fName write fName;
  124. property Alias : string read fAlias write fAlias;
  125. property Value : string read fValue write fValue;
  126. property PrecisePosition : Integer read fPrecisePosition write fPrecisePosition;
  127. property ParamType : TValueType read fParamType write fParamType;
  128. property Required : Boolean read fRequired write fRequired;
  129. property SwitchChar : string read fSwitchChar write fSwitchChar;
  130. property ValueSeparator : string read fValueSeparator write fValueSeparator;
  131. property Help : string read fHelp write fHelp;
  132. property HepValueName : string read fValueName write fValueName;
  133. property ValueIsNextParam : Boolean read fValueIsNextParam write fValueIsNextParam;
  134. property IsPresent : Boolean read fIsPresent write fIsPresent;
  135. function IsSwitch : Boolean;
  136. function IsCommand : Boolean;
  137. function ValueIsSwitch : Boolean;
  138. end;
  139. private
  140. fParams : TObjectList<TParam>;
  141. fDescription : string;
  142. fHelp: Boolean;
  143. {$IFDEF CONSOLE}
  144. fColorizeHelp: TColorizeHelp;
  145. {$ENDIF}
  146. function ExistParam(aParameter : TParam; const aParam : string) : Boolean; overload;
  147. function GetParamName(aParameter : TParam; const aParam : string) : string;
  148. function GetParamValue(aParameter : TParam; const aParam : string) : string;
  149. function ValueType(const aProp : TRttiProperty) : TValueType;
  150. procedure ParseParams;
  151. function CheckHelpSwitch : Boolean;
  152. protected
  153. {$IFDEF CONSOLE}
  154. procedure GetColors; virtual;
  155. {$ENDIF}
  156. procedure Validate; virtual;
  157. public
  158. constructor Create(aAutoHelp : Boolean = True); virtual;
  159. destructor Destroy; override;
  160. property Description : string read fDescription write fDescription;
  161. {$IFDEF CONSOLE}
  162. property ColorizeHelp : TColorizeHelp read fColorizeHelp write fColorizeHelp;
  163. procedure ShowHelp; virtual;
  164. {$ENDIF}
  165. function GetHelp : TStringList;
  166. property Help : Boolean read fHelp write fHelp;
  167. function ExistsParam(const aParam : string; const aValueSeparator : string = ''): Boolean; overload;
  168. end;
  169. {$M-}
  170. TServiceParameters = class(TParameters)
  171. private
  172. fInstance : string;
  173. fInstall : Boolean;
  174. fRemove : Boolean;
  175. fConsole : Boolean;
  176. published
  177. [ParamHelp('Install service with a custom name','Service name')]
  178. property Instance : string read fInstance write fInstance;
  179. [ParamHelp('Install as a service')]
  180. property Install : Boolean read fInstall write fInstall;
  181. [ParamHelp('Remove service')]
  182. property &Remove : Boolean read fRemove write fRemove;
  183. [ParamHelp('Force run as a console application (when runned from another service)')]
  184. property Console : Boolean read fConsole write fConsole;
  185. end;
  186. ENotValidCommandlineParameter = class(Exception);
  187. ERequiredParameterNotFound = class(Exception);
  188. EParameterValueNotFound = class(Exception);
  189. EParamValueNotSupported = class(Exception);
  190. implementation
  191. { TParameter }
  192. constructor TParameters.Create(aAutoHelp : Boolean = True);
  193. begin
  194. {$IFDEF CONSOLE}
  195. fColorizeHelp := TColorizeHelp.Create;
  196. GetColors;
  197. {$ENDIF}
  198. fParams := TObjectList<TParam>.Create(True);
  199. ParseParams;
  200. {$IFDEF CONSOLE}
  201. if (aAutoHelp) and (fHelp) then
  202. begin
  203. ShowHelp;
  204. Halt;
  205. end;
  206. {$ENDIF}
  207. Validate;
  208. end;
  209. destructor TParameters.Destroy;
  210. begin
  211. fParams.Free;
  212. {$IFDEF CONSOLE}
  213. if Assigned(fColorizeHelp) then fColorizeHelp.Free;
  214. fColorizeHelp := nil;
  215. {$ENDIF}
  216. inherited;
  217. end;
  218. function TParameters.ExistParam(aParameter : TParam; const aParam : string) : Boolean;
  219. var
  220. i : Integer;
  221. parName : string;
  222. begin
  223. Result := False;
  224. if aParam.IsEmpty then Exit;
  225. for i := 1 to ParamCount do
  226. begin
  227. parName := ParamStr(i);
  228. if parName = aParameter.ValueSeparator then raise ENotValidCommandlineParameter.CreateFmt('Not valid commandline "%s"', [parName]);
  229. parName := GetParamName(aParameter,ParamStr(i));
  230. if CompareText(parName,aParam) = 0 then Exit(True);
  231. end;
  232. end;
  233. function TParameters.GetParamName(aParameter : TParam; const aParam : string) : string;
  234. var
  235. switch : string;
  236. begin
  237. if CompareText(aParam,'-' + aParameter.Alias) = 0 then switch := '-'
  238. else switch := aParameter.SwitchChar;
  239. if aParam.StartsWith(switch) then Result := aParam.Substring(switch.Length);
  240. if Result.Contains(aParameter.ValueSeparator) then Result := Result.Substring(0,Result.IndexOf(aParameter.ValueSeparator));
  241. end;
  242. function TParameters.GetParamValue(aParameter : TParam; const aParam : string) : string;
  243. var
  244. i : Integer;
  245. parName : string;
  246. param : string;
  247. begin
  248. Result := '';
  249. for i := 1 to ParamCount do
  250. begin
  251. param := ParamStr(i);
  252. parName := GetParamName(aParameter,param);
  253. if CompareText(parName,aParam) = 0 then
  254. begin
  255. if aParameter.ValueIsNextParam then
  256. begin
  257. if i < ParamCount then Result := ParamStr(i+1);
  258. end
  259. else
  260. begin
  261. if param.Contains(aParameter.ValueSeparator) then Result := param.Substring(param.IndexOf(aParameter.ValueSeparator)+(aParameter.ValueSeparator.Length));
  262. end;
  263. Exit;
  264. end;
  265. end;
  266. end;
  267. function TParameters.CheckHelpSwitch: Boolean;
  268. var
  269. param : TParam;
  270. begin
  271. param := TParam.Create;
  272. param.Name := 'help';
  273. param.Alias := 'h';
  274. try
  275. Result := ExistParam(param,param.Name);
  276. finally
  277. param.Free;
  278. end;
  279. end;
  280. function TParameters.ExistsParam(const aParam : string; const aValueSeparator : string = ''): Boolean;
  281. var
  282. param : TParam;
  283. begin
  284. param := TParam.Create;
  285. param.Name := aParam;
  286. if not aValueSeparator.IsEmpty then param.ValueSeparator := aValueSeparator;
  287. param.Alias := '';
  288. try
  289. Result := ExistParam(param,param.Name);
  290. finally
  291. param.Free;
  292. end;
  293. end;
  294. procedure TParameters.ParseParams;
  295. var
  296. param : TParam;
  297. value : TValue;
  298. valueint : Int64;
  299. valuefloat : Extended;
  300. rType : TRttiType;
  301. rProp : TRttiProperty;
  302. attr : TCustomAttribute;
  303. pinfo : PTypeInfo;
  304. found : Boolean;
  305. begin
  306. fHelp := CheckHelpSwitch;
  307. rType := TRTTI.GetType(Self.ClassInfo);
  308. //get main info
  309. for attr in rType.GetAttributes do
  310. begin
  311. if attr is CommandDescription then Self.Description := CommandDescription(attr).Description;
  312. end;
  313. //get parameters
  314. for rProp in TRTTI.GetProperties(rType,TRttiPropertyOrder.roFirstBase) do
  315. begin
  316. if rProp.Visibility <> TMemberVisibility.mvPublished then continue;
  317. param := TParam.Create;
  318. fParams.Add(param);
  319. param.Name := rProp.Name;
  320. for attr in rProp.GetAttributes do
  321. begin
  322. if attr is ParamHelp then
  323. begin
  324. param.Help := ParamHelp(attr).Help;
  325. param.HepValueName := ParamHelp(attr).ValueName;
  326. end;
  327. if attr is ParamName then
  328. begin
  329. param.Name := ParamName(attr).Name;
  330. param.Alias := ParamName(attr).Alias;
  331. end;
  332. if attr is ParamCommand then param.PrecisePosition := ParamCommand(attr).Position;
  333. if attr is ParamRequired then param.Required := True;
  334. if attr is ParamSwitchChar then param.SwitchChar := ParamSwitchChar(attr).SwitchChar;
  335. if attr is ParamValueSeparator then param.ValueSeparator := ParamValueSeparator(attr).ValueSeparator;
  336. if attr is ParamValueIsNextParam then param.ValueIsNextParam := True;
  337. end;
  338. param.ParamType := ValueType(rProp);
  339. if param.IsCommand then
  340. begin
  341. found := ParamCount >= param.PrecisePosition;
  342. param.SwitchChar := ' ';
  343. if param.ValueIsSwitch then found := False;
  344. end
  345. else found := (ExistParam(param,param.Name)) or (ExistParam(param,param.Alias));
  346. value := nil;
  347. if found then
  348. begin
  349. if param.IsSwitch then
  350. begin
  351. value := True;
  352. end
  353. else
  354. begin
  355. if param.IsCommand then param.Value := ParamStr(param.PrecisePosition)
  356. else param.Value := GetParamValue(param,param.Name);
  357. if (param.Value.IsEmpty) and (not param.Alias.IsEmpty) then param.Value := GetParamValue(param,param.Alias);
  358. if (not param.Value.IsEmpty) and (not fHelp) then
  359. case param.ParamType of
  360. TValueType.vtString :
  361. begin
  362. value := param.Value;
  363. end;
  364. TValueType.vtInteger :
  365. begin
  366. if not TryStrToInt64(param.Value,valueint) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a numeric value',[param.Name]);
  367. value := valueint;
  368. end;
  369. TValueType.vtFloat :
  370. begin
  371. if not TryStrToFloat(param.Value,valuefloat) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a float value',[param.Name]);
  372. value := valuefloat;
  373. end;
  374. TValueType.vtEnumeration :
  375. begin
  376. pinfo := TRTTI.GetPropertyValue(Self,param.Name).TypeInfo;
  377. if not IsInteger(param.Value) then TValue.Make(GetEnumValue(pinfo,param.Value),pinfo,value)
  378. else TValue.Make(StrToInt(param.Value),pinfo,value);
  379. end;
  380. end;
  381. end;
  382. param.IsPresent := True;
  383. if not value.IsEmpty then rProp.SetValue(Self,value);
  384. end;
  385. end;
  386. //add help
  387. param := TParam.Create;
  388. param.Name := 'Help';
  389. param.Alias := 'h';
  390. param.ParamType := TValueType.vtBoolean;
  391. param.Help := 'Show this documentation';
  392. fParams.Add(param);
  393. end;
  394. procedure TParameters.Validate;
  395. var
  396. param : TParam;
  397. begin
  398. if help then Exit;
  399. for param in fParams do
  400. begin
  401. if param.IsPresent then
  402. begin
  403. if (not param.IsSwitch) and (param.Value.IsEmpty) then raise EParamValueNotSupported.CreateFmt('Value for parameter "%s" not specified',[param.Name]);
  404. end
  405. else
  406. begin
  407. if param.Required then raise ERequiredParameterNotFound.CreateFmt('Required parameter "%s" not found',[param.Name]);
  408. end;
  409. end;
  410. end;
  411. function TParameters.ValueType(const aProp: TRttiProperty): TValueType;
  412. var
  413. rType : TRttiType;
  414. begin
  415. rType := aProp.PropertyType;
  416. case rType.TypeKind of
  417. tkString, tkWideString, tkChar, tkUnicodeString : Result := TValueType.vtString;
  418. tkInteger, tkInt64 : Result := TValueType.vtInteger;
  419. tkFloat : Result := TValueType.vtFloat;
  420. tkEnumeration :
  421. begin
  422. if TRTTI.GetPropertyValue(Self,aProp.Name).TypeInfo = System.TypeInfo(Boolean) then Result := TValueType.vtBoolean
  423. else Result := TValueType.vtEnumeration;
  424. end;
  425. else raise EParamValueNotSupported.CreateFmt('Parameter "%s": Value not supported',[aProp.Name]);
  426. end;
  427. end;
  428. {$IFDEF CONSOLE}
  429. procedure TParameters.ShowHelp;
  430. var
  431. version : string;
  432. arg : string;
  433. value : string;
  434. usage : string;
  435. commands : string;
  436. param : TParam;
  437. maxlen : Integer;
  438. arglen : Integer;
  439. begin
  440. //show app and version
  441. version := GetAppVersionStr;
  442. if version.IsEmpty then cout(GetAppName,fColorizeHelp.CommandName)
  443. else cout(Format('%s v.%s',[GetAppName,GetAppVersionStr]),fColorizeHelp.CommandName);
  444. usage := '';
  445. maxlen := 0;
  446. commands := '';
  447. //show usage
  448. arglen := 0;
  449. for param in fParams do
  450. begin
  451. if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
  452. if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
  453. else arg := '[' + param.SwitchChar + param.Name + '%s]';
  454. if param.IsSwitch then
  455. begin
  456. arg := Format(arg,['']);
  457. end
  458. else if param.IsCommand then
  459. begin
  460. if param.HepValueName.IsEmpty then value := param.Name
  461. else value := param.HepValueName;
  462. if param.Required then commands := commands + Format('<%s> ',[value])
  463. else commands := commands + Format('[%s] ',[value]);
  464. Continue;
  465. end
  466. else
  467. begin
  468. if param.ValueIsNextParam then value := ' <value>'
  469. else value := param.ValueSeparator + '<value>';
  470. if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
  471. arg := Format(arg,[value]);
  472. end;
  473. //fit usage line
  474. arglen := arglen + arg.Length;
  475. if arglen > 80 then
  476. begin
  477. usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
  478. arglen := arg.Length;
  479. end;
  480. usage := usage + arg + ' ';
  481. end;
  482. maxlen := maxlen + 5;
  483. coutSL('Usage: ',fColorizeHelp.Sections);
  484. coutSL(Format('%s %s%s',[GetAppName,commands,usage]),fColorizeHelp.CommandUsage);
  485. cout('',ccWhite);
  486. cout('',ccWhite);
  487. //show description
  488. cout(Description,fColorizeHelp.CommandDescription);
  489. cout('',ccWhite);
  490. //show arguments
  491. cout('Arguments:',fColorizeHelp.Sections);
  492. cout('',ccWhite);
  493. for param in fParams do
  494. begin
  495. //if param.IsCommand then Continue;
  496. if param.Alias.IsEmpty then
  497. begin
  498. coutSL(Format(' %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]),fColorizeHelp.ArgumentName);
  499. end
  500. else
  501. begin
  502. coutSL(Format(' %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]),fColorizeHelp.ArgumentName);
  503. end;
  504. coutSL(param.Help,fColorizeHelp.ArgumentDescription);
  505. cout('',ccWhite);
  506. end;
  507. cout('',ccWhite);
  508. end;
  509. procedure TParameters.GetColors;
  510. begin
  511. fColorizeHelp.CommandName := ccLightCyan;
  512. fColorizeHelp.CommandDescription := ccDarkGray;
  513. fColorizeHelp.CommandUsage := ccLightGray;
  514. fColorizeHelp.fSections := ccWhite;
  515. fColorizeHelp.ArgumentName := ccWhite;
  516. fColorizeHelp.ArgumentDescription := ccLightGray;
  517. end;
  518. {$ENDIF}
  519. function TParameters.GetHelp : TStringList;
  520. var
  521. line : string;
  522. version : string;
  523. arg : string;
  524. value : string;
  525. usage : string;
  526. commands : string;
  527. param : TParam;
  528. maxlen : Integer;
  529. arglen : Integer;
  530. begin
  531. Result := TStringList.Create;
  532. line := '';
  533. //show app and version
  534. version := GetAppVersionStr;
  535. if version.IsEmpty then Result.Add(GetAppName)
  536. else Result.Add(Format('%s v.%s',[GetAppName,GetAppVersionStr]));
  537. usage := '';
  538. maxlen := 0;
  539. commands := '';
  540. //show usage
  541. arglen := 0;
  542. for param in fParams do
  543. begin
  544. if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
  545. if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
  546. else arg := '[' + param.SwitchChar + param.Name + '%s]';
  547. if param.IsSwitch then
  548. begin
  549. arg := Format(arg,['']);
  550. end
  551. else if param.IsCommand then
  552. begin
  553. if param.HepValueName.IsEmpty then value := param.Name
  554. else value := param.HepValueName;
  555. if param.Required then commands := commands + Format('<%s> ',[value])
  556. else commands := commands + Format('[%s] ',[value]);
  557. Continue;
  558. end
  559. else
  560. begin
  561. if param.ValueIsNextParam then value := ' <value>'
  562. else value := param.ValueSeparator + '<value>';
  563. if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
  564. arg := Format(arg,[value]);
  565. end;
  566. //fit usage line
  567. arglen := arglen + arg.Length;
  568. if arglen > 80 then
  569. begin
  570. usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
  571. arglen := arg.Length;
  572. end;
  573. usage := usage + arg + ' ';
  574. end;
  575. maxlen := maxlen + 5;
  576. Result.Add(Format('Usage: %s %s%s',[GetAppName,commands,usage]));
  577. Result.Add('');
  578. Result.Add('');
  579. //show description
  580. Result.Add(Description);
  581. Result.Add('');
  582. //show arguments
  583. Result.Add('Arguments:');
  584. Result.Add('');
  585. for param in fParams do
  586. begin
  587. //if param.IsCommand then Continue;
  588. line := '';
  589. if param.Alias.IsEmpty then
  590. begin
  591. line := line + Format(' %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]);
  592. end
  593. else
  594. begin
  595. line := line + Format(' %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]);
  596. end;
  597. line := line + param.Help;
  598. Result.Add(line);
  599. Result.Add('');
  600. end;
  601. end;
  602. { CommandDescription }
  603. constructor CommandDescription.Create(const aDescription: string);
  604. begin
  605. fDescription := aDescription;
  606. end;
  607. { ParamName }
  608. constructor ParamName.Create(const aName: string; const aAlias : string = '');
  609. begin
  610. fName := aName;
  611. fAlias := aAlias;
  612. end;
  613. { ParamHelp }
  614. constructor ParamHelp.Create(const aHelp : string; const aValueName : string = '');
  615. begin
  616. fHelp := aHelp;
  617. if not aValueName.IsEmpty then fValueName := aValueName
  618. else fValueName := 'value';
  619. end;
  620. { TParameters.TParam }
  621. constructor TParameters.TParam.Create;
  622. begin
  623. IsPresent := False;
  624. fSwitchChar := '--';
  625. fValueSeparator := '=';
  626. fPrecisePosition := 0;
  627. end;
  628. function TParameters.TParam.IsCommand: Boolean;
  629. begin
  630. Result := fPrecisePosition > 0;
  631. end;
  632. function TParameters.TParam.IsSwitch: Boolean;
  633. begin
  634. Result := fParamType = TValueType.vtBoolean;
  635. end;
  636. function TParameters.TParam.ValueIsSwitch: Boolean;
  637. begin
  638. Result := (fValue.StartsWith('/')) or (fValue.StartsWith('-')) or (fValue.StartsWith(fSwitchChar));
  639. end;
  640. { ParamSwitchChar }
  641. constructor ParamSwitchChar.Create(const aSwitchChar: string);
  642. begin
  643. fSwithChar := aSwitchChar;
  644. end;
  645. { ParamValueSeparator }
  646. constructor ParamValueSeparator.Create(const aValueSeparator: string);
  647. begin
  648. fValueSeparator := aValueSeparator;
  649. end;
  650. { ParamCommand }
  651. constructor ParamCommand.Create(aPosition: Integer);
  652. begin
  653. fPosition := aPosition;
  654. end;
  655. end.