2
0

Quick.Parameters.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  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): 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): Boolean;
  281. var
  282. param : TParam;
  283. begin
  284. param := TParam.Create;
  285. param.Name := aParam;
  286. param.Alias := '';
  287. try
  288. Result := ExistParam(param,param.Name);
  289. finally
  290. param.Free;
  291. end;
  292. end;
  293. procedure TParameters.ParseParams;
  294. var
  295. param : TParam;
  296. value : TValue;
  297. valueint : Int64;
  298. valuefloat : Extended;
  299. rType : TRttiType;
  300. rProp : TRttiProperty;
  301. attr : TCustomAttribute;
  302. pinfo : PTypeInfo;
  303. found : Boolean;
  304. begin
  305. fHelp := CheckHelpSwitch;
  306. rType := TRTTI.GetType(Self.ClassInfo);
  307. //get main info
  308. for attr in rType.GetAttributes do
  309. begin
  310. if attr is CommandDescription then Self.Description := CommandDescription(attr).Description;
  311. end;
  312. //get parameters
  313. for rProp in TRTTI.GetProperties(rType,TRttiPropertyOrder.roFirstBase) do
  314. begin
  315. if rProp.Visibility <> TMemberVisibility.mvPublished then continue;
  316. param := TParam.Create;
  317. fParams.Add(param);
  318. param.Name := rProp.Name;
  319. for attr in rProp.GetAttributes do
  320. begin
  321. if attr is ParamHelp then
  322. begin
  323. param.Help := ParamHelp(attr).Help;
  324. param.HepValueName := ParamHelp(attr).ValueName;
  325. end;
  326. if attr is ParamName then
  327. begin
  328. param.Name := ParamName(attr).Name;
  329. param.Alias := ParamName(attr).Alias;
  330. end;
  331. if attr is ParamCommand then param.PrecisePosition := ParamCommand(attr).Position;
  332. if attr is ParamRequired then param.Required := True;
  333. if attr is ParamSwitchChar then param.SwitchChar := ParamSwitchChar(attr).SwitchChar;
  334. if attr is ParamValueSeparator then param.ValueSeparator := ParamValueSeparator(attr).ValueSeparator;
  335. if attr is ParamValueIsNextParam then param.ValueIsNextParam := True;
  336. end;
  337. param.ParamType := ValueType(rProp);
  338. if param.IsCommand then
  339. begin
  340. found := ParamCount >= param.PrecisePosition;
  341. param.SwitchChar := ' ';
  342. if param.ValueIsSwitch then found := False;
  343. end
  344. else found := (ExistParam(param,param.Name)) or (ExistParam(param,param.Alias));
  345. value := nil;
  346. if found then
  347. begin
  348. if param.IsSwitch then
  349. begin
  350. value := True;
  351. end
  352. else
  353. begin
  354. if param.IsCommand then param.Value := ParamStr(param.PrecisePosition)
  355. else param.Value := GetParamValue(param,param.Name);
  356. if (param.Value.IsEmpty) and (not param.Alias.IsEmpty) then param.Value := GetParamValue(param,param.Alias);
  357. if (not param.Value.IsEmpty) and (not fHelp) then
  358. case param.ParamType of
  359. TValueType.vtString :
  360. begin
  361. value := param.Value;
  362. end;
  363. TValueType.vtInteger :
  364. begin
  365. if not TryStrToInt64(param.Value,valueint) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a numeric value',[param.Name]);
  366. value := valueint;
  367. end;
  368. TValueType.vtFloat :
  369. begin
  370. if not TryStrToFloat(param.Value,valuefloat) then raise EParamValueNotSupported.CreateFmt('Parameter "%s" needs a float value',[param.Name]);
  371. value := valuefloat;
  372. end;
  373. TValueType.vtEnumeration :
  374. begin
  375. pinfo := TRTTI.GetPropertyValue(Self,param.Name).TypeInfo;
  376. if not IsInteger(param.Value) then TValue.Make(GetEnumValue(pinfo,param.Value),pinfo,value)
  377. else TValue.Make(StrToInt(param.Value),pinfo,value);
  378. end;
  379. end;
  380. end;
  381. param.IsPresent := True;
  382. if not value.IsEmpty then rProp.SetValue(Self,value);
  383. end;
  384. end;
  385. //add help
  386. param := TParam.Create;
  387. param.Name := 'Help';
  388. param.Alias := 'h';
  389. param.ParamType := TValueType.vtBoolean;
  390. param.Help := 'Show this documentation';
  391. fParams.Add(param);
  392. end;
  393. procedure TParameters.Validate;
  394. var
  395. param : TParam;
  396. begin
  397. if help then Exit;
  398. for param in fParams do
  399. begin
  400. if param.IsPresent then
  401. begin
  402. if (not param.IsSwitch) and (param.Value.IsEmpty) then raise EParamValueNotSupported.CreateFmt('Value for parameter "%s" not specified',[param.Name]);
  403. end
  404. else
  405. begin
  406. if param.Required then raise ERequiredParameterNotFound.CreateFmt('Required parameter "%s" not found',[param.Name]);
  407. end;
  408. end;
  409. end;
  410. function TParameters.ValueType(const aProp: TRttiProperty): TValueType;
  411. var
  412. rType : TRttiType;
  413. begin
  414. rType := aProp.PropertyType;
  415. case rType.TypeKind of
  416. tkString, tkWideString, tkChar, tkUnicodeString : Result := TValueType.vtString;
  417. tkInteger, tkInt64 : Result := TValueType.vtInteger;
  418. tkFloat : Result := TValueType.vtFloat;
  419. tkEnumeration :
  420. begin
  421. if TRTTI.GetPropertyValue(Self,aProp.Name).TypeInfo = System.TypeInfo(Boolean) then Result := TValueType.vtBoolean
  422. else Result := TValueType.vtEnumeration;
  423. end;
  424. else raise EParamValueNotSupported.CreateFmt('Parameter "%s": Value not supported',[aProp.Name]);
  425. end;
  426. end;
  427. {$IFDEF CONSOLE}
  428. procedure TParameters.ShowHelp;
  429. var
  430. version : string;
  431. arg : string;
  432. value : string;
  433. usage : string;
  434. commands : string;
  435. param : TParam;
  436. maxlen : Integer;
  437. arglen : Integer;
  438. begin
  439. //show app and version
  440. version := GetAppVersionStr;
  441. if version.IsEmpty then cout(GetAppName,fColorizeHelp.CommandName)
  442. else cout(Format('%s v.%s',[GetAppName,GetAppVersionStr]),fColorizeHelp.CommandName);
  443. usage := '';
  444. maxlen := 0;
  445. commands := '';
  446. //show usage
  447. arglen := 0;
  448. for param in fParams do
  449. begin
  450. if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
  451. if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
  452. else arg := '[' + param.SwitchChar + param.Name + '%s]';
  453. if param.IsSwitch then
  454. begin
  455. arg := Format(arg,['']);
  456. end
  457. else if param.IsCommand then
  458. begin
  459. if param.HepValueName.IsEmpty then value := param.Name
  460. else value := param.HepValueName;
  461. if param.Required then commands := commands + Format('<%s> ',[value])
  462. else commands := commands + Format('[%s] ',[value]);
  463. Continue;
  464. end
  465. else
  466. begin
  467. if param.ValueIsNextParam then value := ' <value>'
  468. else value := param.ValueSeparator + '<value>';
  469. if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
  470. arg := Format(arg,[value]);
  471. end;
  472. //fit usage line
  473. arglen := arglen + arg.Length;
  474. if arglen > 80 then
  475. begin
  476. usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
  477. arglen := arg.Length;
  478. end;
  479. usage := usage + arg + ' ';
  480. end;
  481. maxlen := maxlen + 5;
  482. coutSL('Usage: ',fColorizeHelp.Sections);
  483. coutSL(Format('%s %s%s',[GetAppName,commands,usage]),fColorizeHelp.CommandUsage);
  484. cout('',ccWhite);
  485. cout('',ccWhite);
  486. //show description
  487. cout(Description,fColorizeHelp.CommandDescription);
  488. cout('',ccWhite);
  489. //show arguments
  490. cout('Arguments:',fColorizeHelp.Sections);
  491. cout('',ccWhite);
  492. for param in fParams do
  493. begin
  494. //if param.IsCommand then Continue;
  495. if param.Alias.IsEmpty then
  496. begin
  497. coutSL(Format(' %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]),fColorizeHelp.ArgumentName);
  498. end
  499. else
  500. begin
  501. coutSL(Format(' %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]),fColorizeHelp.ArgumentName);
  502. end;
  503. coutSL(param.Help,fColorizeHelp.ArgumentDescription);
  504. cout('',ccWhite);
  505. end;
  506. cout('',ccWhite);
  507. end;
  508. procedure TParameters.GetColors;
  509. begin
  510. fColorizeHelp.CommandName := ccLightCyan;
  511. fColorizeHelp.CommandDescription := ccDarkGray;
  512. fColorizeHelp.CommandUsage := ccLightGray;
  513. fColorizeHelp.fSections := ccWhite;
  514. fColorizeHelp.ArgumentName := ccWhite;
  515. fColorizeHelp.ArgumentDescription := ccLightGray;
  516. end;
  517. {$ENDIF}
  518. function TParameters.GetHelp : TStringList;
  519. var
  520. line : string;
  521. version : string;
  522. arg : string;
  523. value : string;
  524. usage : string;
  525. commands : string;
  526. param : TParam;
  527. maxlen : Integer;
  528. arglen : Integer;
  529. begin
  530. Result := TStringList.Create;
  531. line := '';
  532. //show app and version
  533. version := GetAppVersionStr;
  534. if version.IsEmpty then Result.Add(GetAppName)
  535. else Result.Add(Format('%s v.%s',[GetAppName,GetAppVersionStr]));
  536. usage := '';
  537. maxlen := 0;
  538. commands := '';
  539. //show usage
  540. arglen := 0;
  541. for param in fParams do
  542. begin
  543. if (param.Name.Length + param.Alias.Length) > maxlen then maxlen := param.Name.Length + param.Alias.Length;
  544. if param.Required then arg := '<' + param.SwitchChar + param.Name +'%s>'
  545. else arg := '[' + param.SwitchChar + param.Name + '%s]';
  546. if param.IsSwitch then
  547. begin
  548. arg := Format(arg,['']);
  549. end
  550. else if param.IsCommand then
  551. begin
  552. if param.HepValueName.IsEmpty then value := param.Name
  553. else value := param.HepValueName;
  554. if param.Required then commands := commands + Format('<%s> ',[value])
  555. else commands := commands + Format('[%s] ',[value]);
  556. Continue;
  557. end
  558. else
  559. begin
  560. if param.ValueIsNextParam then value := ' <value>'
  561. else value := param.ValueSeparator + '<value>';
  562. if not param.HepValueName.IsEmpty then value := StringReplace(value,'value',param.HepValueName,[rfIgnoreCase,rfReplaceAll]);
  563. arg := Format(arg,[value]);
  564. end;
  565. //fit usage line
  566. arglen := arglen + arg.Length;
  567. if arglen > 80 then
  568. begin
  569. usage := usage + #10 + FillStr(' ',8 + (GetAppName.Length));
  570. arglen := arg.Length;
  571. end;
  572. usage := usage + arg + ' ';
  573. end;
  574. maxlen := maxlen + 5;
  575. Result.Add(Format('Usage: %s %s%s',[GetAppName,commands,usage]));
  576. Result.Add('');
  577. Result.Add('');
  578. //show description
  579. Result.Add(Description);
  580. Result.Add('');
  581. //show arguments
  582. Result.Add('Arguments:');
  583. Result.Add('');
  584. for param in fParams do
  585. begin
  586. //if param.IsCommand then Continue;
  587. line := '';
  588. if param.Alias.IsEmpty then
  589. begin
  590. line := line + Format(' %s%s%s',[param.SwitchChar,param.Name,FillStr(' ',maxlen - param.Name.Length)]);
  591. end
  592. else
  593. begin
  594. line := line + Format(' %s%s, -%s%s',[param.SwitchChar,param.Name,param.Alias,FillStr(' ',maxlen - (param.Name.Length + param.Alias.Length + 3))]);
  595. end;
  596. line := line + param.Help;
  597. Result.Add(line);
  598. Result.Add('');
  599. end;
  600. end;
  601. { CommandDescription }
  602. constructor CommandDescription.Create(const aDescription: string);
  603. begin
  604. fDescription := aDescription;
  605. end;
  606. { ParamName }
  607. constructor ParamName.Create(const aName: string; const aAlias : string = '');
  608. begin
  609. fName := aName;
  610. fAlias := aAlias;
  611. end;
  612. { ParamHelp }
  613. constructor ParamHelp.Create(const aHelp : string; const aValueName : string = '');
  614. begin
  615. fHelp := aHelp;
  616. if not aValueName.IsEmpty then fValueName := aValueName
  617. else fValueName := 'value';
  618. end;
  619. { TParameters.TParam }
  620. constructor TParameters.TParam.Create;
  621. begin
  622. IsPresent := False;
  623. fSwitchChar := '--';
  624. fValueSeparator := '=';
  625. fPrecisePosition := 0;
  626. end;
  627. function TParameters.TParam.IsCommand: Boolean;
  628. begin
  629. Result := fPrecisePosition > 0;
  630. end;
  631. function TParameters.TParam.IsSwitch: Boolean;
  632. begin
  633. Result := fParamType = TValueType.vtBoolean;
  634. end;
  635. function TParameters.TParam.ValueIsSwitch: Boolean;
  636. begin
  637. Result := (fValue.StartsWith('/')) or (fValue.StartsWith('-')) or (fValue.StartsWith(fSwitchChar));
  638. end;
  639. { ParamSwitchChar }
  640. constructor ParamSwitchChar.Create(const aSwitchChar: string);
  641. begin
  642. fSwithChar := aSwitchChar;
  643. end;
  644. { ParamValueSeparator }
  645. constructor ParamValueSeparator.Create(const aValueSeparator: string);
  646. begin
  647. fValueSeparator := aValueSeparator;
  648. end;
  649. { ParamCommand }
  650. constructor ParamCommand.Create(aPosition: Integer);
  651. begin
  652. fPosition := aPosition;
  653. end;
  654. end.