Quick.Parameters.pas 21 KB

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