custapp.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team
  4. CustomApplication class.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit CustApp;
  14. Interface
  15. uses SysUtils,Classes,singleinstance;
  16. Type
  17. TStringArray = Array of string;
  18. TExceptionEvent = Procedure (Sender : TObject; E : Exception) Of Object;
  19. TEventLogTypes = Set of TEventType;
  20. { TCustomApplication }
  21. TCustomApplication = Class(TComponent)
  22. Private
  23. FEventLogFilter: TEventLogTypes;
  24. FOnException: TExceptionEvent;
  25. FSingleInstance: TBaseSingleInstance;
  26. FSingleInstanceClass: TBaseSingleInstanceClass; // set before FSingleInstance is created
  27. FSingleInstanceEnabled: Boolean; // set before Initialize is called
  28. FTerminated : Boolean;
  29. FHelpFile,
  30. FTitle : String;
  31. FOptionChar : Char;
  32. FCaseSensitiveOptions : Boolean;
  33. FStopOnException : Boolean;
  34. FExceptionExitCode : Integer;
  35. function GetEnvironmentVar(VarName : String): String;
  36. function GetExeName: string;
  37. Function GetLocation : String;
  38. function GetSingleInstance: TBaseSingleInstance;
  39. procedure SetSingleInstanceClass(
  40. const ASingleInstanceClass: TBaseSingleInstanceClass);
  41. function GetTitle: string;
  42. Protected
  43. function GetOptionAtIndex(AIndex: Integer; IsLong: Boolean): String;
  44. procedure SetTitle(const AValue: string); Virtual;
  45. Function GetConsoleApplication : boolean; Virtual;
  46. Procedure DoRun; Virtual;
  47. Function GetParams(Index : Integer) : String;virtual;
  48. function GetParamCount: Integer;Virtual;
  49. Procedure DoLog(EventType : TEventType; const Msg : String); virtual;
  50. Public
  51. constructor Create(AOwner: TComponent); override;
  52. destructor Destroy; override;
  53. // Some Delphi methods.
  54. procedure HandleException(Sender: TObject); virtual;
  55. procedure Initialize; virtual;
  56. procedure Run;
  57. procedure ShowException(E: Exception);virtual;
  58. procedure Terminate; virtual;
  59. procedure Terminate(AExitCode : Integer) ; virtual;
  60. // Extra methods.
  61. function FindOptionIndex(Const S : String; Var Longopt : Boolean; StartAt : Integer = -1) : Integer;
  62. Function GetOptionValue(Const S : String) : String;
  63. Function GetOptionValue(Const C: Char; Const S : String) : String;
  64. Function GetOptionValues(Const C: Char; Const S : String) : TStringArray;
  65. Function HasOption(Const S : String) : Boolean;
  66. Function HasOption(Const C : Char; Const S : String) : Boolean;
  67. Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; Opts,NonOpts : TStrings; AllErrors : Boolean = False) : String;
  68. Function CheckOptions(Const ShortOptions : String; Const Longopts : Array of string; Opts,NonOpts : TStrings; AllErrors : Boolean = False) : String;
  69. Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; AllErrors : Boolean = False) : String;
  70. Function CheckOptions(Const ShortOptions : String; Const LongOpts : Array of string; AllErrors : Boolean = False) : String;
  71. Function CheckOptions(Const ShortOptions : String; Const LongOpts : String; AllErrors : Boolean = False) : String;
  72. Function GetNonOptions(Const ShortOptions : String; Const Longopts : Array of string) : TStringArray;
  73. Procedure GetNonOptions(Const ShortOptions : String; Const Longopts : Array of string; NonOptions : TStrings);
  74. Procedure GetEnvironmentList(List : TStrings;NamesOnly : Boolean);
  75. Procedure GetEnvironmentList(List : TStrings);
  76. Procedure Log(EventType : TEventType; const Msg : String);
  77. Procedure Log(EventType : TEventType; const Fmt : String; const Args : array of const);
  78. // Delphi properties
  79. property ExeName: string read GetExeName;
  80. property HelpFile: string read FHelpFile write FHelpFile;
  81. property Terminated: Boolean read FTerminated;
  82. property Title: string read FTitle write SetTitle;
  83. property OnException: TExceptionEvent read FOnException write FOnException;
  84. // Extra properties
  85. Property ConsoleApplication : Boolean Read GetConsoleApplication;
  86. Property Location : String Read GetLocation;
  87. Property Params [Index : integer] : String Read GetParams;
  88. Property ParamCount : Integer Read GetParamCount;
  89. Property EnvironmentVariable[envName : String] : String Read GetEnvironmentVar;
  90. Property OptionChar : Char Read FoptionChar Write FOptionChar;
  91. Property CaseSensitiveOptions : Boolean Read FCaseSensitiveOptions Write FCaseSensitiveOptions;
  92. Property StopOnException : Boolean Read FStopOnException Write FStopOnException;
  93. Property ExceptionExitCode : Longint Read FExceptionExitCode Write FExceptionExitCode;
  94. Property EventLogFilter : TEventLogTypes Read FEventLogFilter Write FEventLogFilter;
  95. Property SingleInstance: TBaseSingleInstance read GetSingleInstance;
  96. Property SingleInstanceClass: TBaseSingleInstanceClass read FSingleInstanceClass write SetSingleInstanceClass;
  97. Property SingleInstanceEnabled: Boolean read FSingleInstanceEnabled write FSingleInstanceEnabled;
  98. end;
  99. var CustomApplication : TCustomApplication = nil;
  100. Implementation
  101. {$ifdef darwin}
  102. uses
  103. MacOSAll;
  104. {$endif}
  105. { TCustomApplication }
  106. function TCustomApplication.GetExeName: string;
  107. {$if defined(darwin)}
  108. var
  109. mainBundle: CFBundleRef;
  110. executableUrl: CFURLRef;
  111. executableFSPath: CFStringRef;
  112. utf16len: ptrint;
  113. error: boolean;
  114. begin
  115. error:=false;
  116. { Get main bundle. This even works most of the time for command line
  117. applications
  118. }
  119. mainbundle:=CFBundleGetMainBundle;
  120. if assigned(mainbundle) then
  121. begin
  122. { get the URL pointing to the executable of the bundle }
  123. executableUrl:=CFBundleCopyExecutableURL(mainBundle);
  124. if assigned(executableUrl) then
  125. begin
  126. { convert the url to a POSIX path }
  127. executableFSPath:=CFURLCopyFileSystemPath(executableUrl,kCFURLPOSIXPathStyle);
  128. CFRelease(executableUrl);
  129. { convert to UTF-8 -- this is not really clean since in theory the
  130. ansi-encoding could be different, but
  131. a) all file i/o routines on Darwin expect utf-8-encoded strings
  132. b) there is no easy way to convert the Unix LANG encoding
  133. setting to an equivalent CoreFoundation encoding
  134. }
  135. utf16len:=CFStringGetLength(executableFSPath);
  136. // +1 for extra terminating #0 in the worst case, so the pos below
  137. // will always find the #0
  138. setlength(result,utf16len*3+1);
  139. if CFStringGetCString(executableFSPath,@result[1],length(result),kCFStringEncodingUTF8) then
  140. { truncate to actual length, #0 cannot appear in a file path }
  141. setlength(result,pos(#0,result)-1)
  142. else
  143. error:=true;
  144. CFRelease(executableFSPath);
  145. end
  146. else
  147. error:=true;
  148. end
  149. else
  150. error:=true;
  151. if error then
  152. { can't do better than this }
  153. Result:=Paramstr(0);
  154. end;
  155. {$else darwin}
  156. begin
  157. Result:=Paramstr(0);
  158. end;
  159. {$endif darwin}
  160. Procedure SysGetEnvironmentList(List : TStrings;NamesOnly : Boolean);
  161. var
  162. s : string;
  163. i,l,j,count : longint;
  164. begin
  165. count:=GetEnvironmentVariableCount;
  166. if count>0 then
  167. for j:=1 to count do
  168. begin
  169. s:=GetEnvironmentString(j);
  170. l:=Length(s);
  171. If NamesOnly then
  172. begin
  173. I:=pos('=',s);
  174. If (I>0) then
  175. S:=Copy(S,1,I-1);
  176. end;
  177. List.Add(S);
  178. end;
  179. end;
  180. function TCustomApplication.GetEnvironmentVar(VarName : String): String;
  181. begin
  182. Result:=GetEnvironmentVariable(VarName);
  183. end;
  184. procedure TCustomApplication.GetEnvironmentList(List: TStrings;
  185. NamesOnly: Boolean);
  186. begin
  187. // Routine must be in custapp.inc
  188. SysGetEnvironmentList(List,NamesOnly);
  189. end;
  190. procedure TCustomApplication.GetEnvironmentList(List: TStrings);
  191. begin
  192. GetEnvironmentList(List,False);
  193. end;
  194. function TCustomApplication.GetLocation: String;
  195. begin
  196. Result:=ExtractFilePath(GetExeName);
  197. end;
  198. function TCustomApplication.GetParamCount: Integer;
  199. begin
  200. Result:=System.ParamCount;
  201. end;
  202. function TCustomApplication.GetTitle: string;
  203. begin
  204. Result:=FTitle;
  205. end;
  206. function TCustomApplication.GetParams(Index: Integer): String;
  207. begin
  208. Result:=ParamStr(Index);
  209. end;
  210. function TCustomApplication.GetSingleInstance: TBaseSingleInstance;
  211. begin
  212. if FSingleInstance = nil then
  213. begin
  214. if FSingleInstanceClass=Nil then
  215. Raise ESingleInstance.Create('No single instance provider class set! Include a single-instance class unit such as advsingleinstance');
  216. FSingleInstance := FSingleInstanceClass.Create(Self);
  217. end;
  218. Result := FSingleInstance;
  219. end;
  220. procedure TCustomApplication.SetTitle(const AValue: string);
  221. begin
  222. FTitle:=AValue;
  223. end;
  224. function TCustomApplication.GetConsoleApplication: boolean;
  225. begin
  226. Result:=IsConsole;
  227. end;
  228. procedure TCustomApplication.DoRun;
  229. begin
  230. if Assigned(FSingleInstance) then
  231. if FSingleInstance.IsServer then
  232. FSingleInstance.ServerCheckMessages;
  233. // Override in descendent classes.
  234. end;
  235. procedure TCustomApplication.DoLog(EventType: TEventType; const Msg: String);
  236. begin
  237. // Do nothing, override in descendants
  238. end;
  239. procedure TCustomApplication.Log(EventType: TEventType; const Msg: String);
  240. begin
  241. If (FEventLogFilter=[]) or (EventType in FEventLogFilter) then
  242. DoLog(EventType,Msg);
  243. end;
  244. procedure TCustomApplication.Log(EventType: TEventType; const Fmt: String;
  245. const Args: array of const);
  246. begin
  247. try
  248. Log(EventType, Format(Fmt, Args));
  249. except
  250. On E : Exception do
  251. Log(etError,Format('Error formatting message "%s" with %d arguments: %s',[Fmt,Length(Args),E.Message]));
  252. end
  253. end;
  254. constructor TCustomApplication.Create(AOwner: TComponent);
  255. begin
  256. inherited Create(AOwner);
  257. FOptionChar:='-';
  258. FCaseSensitiveOptions:=True;
  259. FStopOnException:=False;
  260. FSingleInstanceClass := DefaultSingleInstanceClass;
  261. end;
  262. destructor TCustomApplication.Destroy;
  263. begin
  264. inherited Destroy;
  265. end;
  266. procedure TCustomApplication.HandleException(Sender: TObject);
  267. begin
  268. If Not (ExceptObject is Exception) then
  269. SysUtils.showexception(ExceptObject,ExceptAddr)
  270. else
  271. begin
  272. If Not Assigned(FOnexception) then
  273. ShowException(Exception(ExceptObject))
  274. else
  275. FOnException(Sender,Exception(ExceptObject));
  276. end;
  277. If FStopOnException then
  278. Terminate(ExceptionExitCode);
  279. end;
  280. procedure TCustomApplication.Initialize;
  281. begin
  282. FTerminated:=False;
  283. if FSingleInstanceEnabled then
  284. begin
  285. case SingleInstance.Start of
  286. siClient:
  287. begin
  288. SingleInstance.ClientPostParams;
  289. FTerminated:=True;
  290. end;
  291. siNotResponding:
  292. FTerminated:=True;
  293. end;
  294. end;
  295. end;
  296. procedure TCustomApplication.Run;
  297. begin
  298. Repeat
  299. Try
  300. DoRun;
  301. except
  302. HandleException(Self);
  303. end;
  304. Until FTerminated;
  305. end;
  306. procedure TCustomApplication.SetSingleInstanceClass(
  307. const ASingleInstanceClass: TBaseSingleInstanceClass);
  308. begin
  309. Assert((FSingleInstance = nil) and (ASingleInstanceClass <> nil));
  310. FSingleInstanceClass := ASingleInstanceClass;
  311. end;
  312. procedure TCustomApplication.ShowException(E: Exception);
  313. begin
  314. Sysutils.ShowException(E,ExceptAddr)
  315. end;
  316. procedure TCustomApplication.Terminate;
  317. begin
  318. Terminate(ExitCode);
  319. end;
  320. procedure TCustomApplication.Terminate(AExitCode : Integer) ;
  321. begin
  322. FTerminated:=True;
  323. ExitCode:=AExitCode;
  324. end;
  325. function TCustomApplication.GetOptionAtIndex(AIndex : Integer; IsLong: Boolean): String;
  326. Var
  327. P : Integer;
  328. O : String;
  329. begin
  330. Result:='';
  331. If (AIndex=-1) then
  332. Exit;
  333. If IsLong then
  334. begin // Long options have form --option=value
  335. O:=Params[AIndex];
  336. P:=Pos('=',O);
  337. If (P=0) then
  338. P:=Length(O);
  339. Delete(O,1,P);
  340. Result:=O;
  341. end
  342. else
  343. begin // short options have form '-o value'
  344. If (AIndex<ParamCount) then
  345. if (Copy(Params[AIndex+1],1,1)<>OptionChar) then
  346. Result:=Params[AIndex+1];
  347. end;
  348. end;
  349. function TCustomApplication.GetOptionValue(const S: String): String;
  350. begin
  351. Result:=GetoptionValue(#255,S);
  352. end;
  353. function TCustomApplication.GetOptionValue(const C: Char; const S: String
  354. ): String;
  355. Var
  356. B : Boolean;
  357. I : integer;
  358. begin
  359. Result:='';
  360. I:=FindOptionIndex(C,B);
  361. If (I=-1) then
  362. I:=FindOptionIndex(S,B);
  363. If I<>-1 then
  364. Result:=GetOptionAtIndex(I,B);
  365. end;
  366. function TCustomApplication.GetOptionValues(const C: Char; const S: String): TStringArray;
  367. Var
  368. I,Cnt : Integer;
  369. B : Boolean;
  370. begin
  371. SetLength(Result,ParamCount);
  372. Cnt:=0;
  373. I:=-1;
  374. Repeat
  375. I:=FindOptionIndex(C,B,I);
  376. If I<>-1 then
  377. begin
  378. Inc(Cnt);
  379. Dec(I);
  380. end;
  381. Until I=-1;
  382. Repeat
  383. I:=FindOptionIndex(S,B,I);
  384. If I<>-1 then
  385. begin
  386. Inc(Cnt);
  387. Dec(I);
  388. end;
  389. Until I=-1;
  390. SetLength(Result,Cnt);
  391. Cnt:=0;
  392. I:=-1;
  393. Repeat
  394. I:=FindOptionIndex(C,B,I);
  395. If (I<>-1) then
  396. begin
  397. Result[Cnt]:=GetOptionAtIndex(I,False);
  398. Inc(Cnt);
  399. Dec(i);
  400. end;
  401. Until (I=-1);
  402. I:=-1;
  403. Repeat
  404. I:=FindOptionIndex(S,B,I);
  405. If I<>-1 then
  406. begin
  407. Result[Cnt]:=GetOptionAtIndex(I,True);
  408. Inc(Cnt);
  409. Dec(i);
  410. end;
  411. Until (I=-1);
  412. end;
  413. function TCustomApplication.HasOption(const S: String): Boolean;
  414. Var
  415. B : Boolean;
  416. begin
  417. Result:=FindOptionIndex(S,B)<>-1;
  418. end;
  419. function TCustomApplication.FindOptionIndex(const S: String;
  420. var Longopt: Boolean; StartAt : Integer = -1): Integer;
  421. Var
  422. SO,O : String;
  423. I,P : Integer;
  424. begin
  425. If Not CaseSensitiveOptions then
  426. SO:=UpperCase(S)
  427. else
  428. SO:=S;
  429. Result:=-1;
  430. I:=StartAt;
  431. if (I=-1) then
  432. I:=ParamCount;
  433. While (Result=-1) and (I>0) do
  434. begin
  435. O:=Params[i];
  436. // - must be seen as an option value
  437. If (Length(O)>1) and (O[1]=FOptionChar) then
  438. begin
  439. Delete(O,1,1);
  440. LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);
  441. If LongOpt then
  442. begin
  443. Delete(O,1,1);
  444. P:=Pos('=',O);
  445. If (P<>0) then
  446. O:=Copy(O,1,P-1);
  447. end;
  448. If Not CaseSensitiveOptions then
  449. O:=UpperCase(O);
  450. If (O=SO) then
  451. Result:=i;
  452. end;
  453. Dec(i);
  454. end;
  455. end;
  456. function TCustomApplication.HasOption(const C: Char; const S: String): Boolean;
  457. Var
  458. B : Boolean;
  459. begin
  460. Result:=(FindOptionIndex(C,B)<>-1) or (FindOptionIndex(S,B)<>-1);
  461. end;
  462. function TCustomApplication.CheckOptions(const ShortOptions: String;
  463. const Longopts: TStrings; AllErrors: Boolean): String;
  464. begin
  465. Result:=CheckOptions(ShortOptions,LongOpts,Nil,Nil,AllErrors);
  466. end;
  467. ResourceString
  468. SErrInvalidOption = 'Invalid option at position %d: "%s"';
  469. SErrNoOptionAllowed = 'Option at position %d does not allow an argument: %s';
  470. SErrOptionNeeded = 'Option at position %d needs an argument : %s';
  471. function TCustomApplication.CheckOptions(const ShortOptions: String;
  472. const Longopts: TStrings; Opts, NonOpts: TStrings; AllErrors: Boolean
  473. ): String;
  474. Var
  475. I,J,L,P : Integer;
  476. O,OV,SO : String;
  477. UsedArg,HaveArg : Boolean;
  478. Function FindLongOpt(S : String) : boolean;
  479. Var
  480. I : integer;
  481. begin
  482. Result:=Assigned(LongOpts);
  483. if Not Result then
  484. exit;
  485. If CaseSensitiveOptions then
  486. begin
  487. I:=LongOpts.Count-1;
  488. While (I>=0) and (LongOpts[i]<>S) do
  489. Dec(i);
  490. end
  491. else
  492. begin
  493. S:=UpperCase(S);
  494. I:=LongOpts.Count-1;
  495. While (I>=0) and (UpperCase(LongOpts[i])<>S) do
  496. Dec(i);
  497. end;
  498. Result:=(I<>-1);
  499. end;
  500. Procedure AddToResult(Const Msg : string);
  501. begin
  502. If (Result<>'') then
  503. Result:=Result+sLineBreak;
  504. Result:=Result+Msg;
  505. end;
  506. begin
  507. If CaseSensitiveOptions then
  508. SO:=Shortoptions
  509. else
  510. SO:=LowerCase(Shortoptions);
  511. Result:='';
  512. I:=1;
  513. While (I<=ParamCount) and ((Result='') or AllErrors) do
  514. begin
  515. O:=Paramstr(I);
  516. If (Length(O)=0) or (O[1]<>FOptionChar) then
  517. begin
  518. If Assigned(NonOpts) then
  519. NonOpts.Add(O);
  520. end
  521. else
  522. begin
  523. If (Length(O)<2) then
  524. AddToResult(Format(SErrInvalidOption,[i,O]))
  525. else
  526. begin
  527. HaveArg:=False;
  528. OV:='';
  529. // Long option ?
  530. If (O[2]=FOptionChar) then
  531. begin
  532. Delete(O,1,2);
  533. J:=Pos('=',O);
  534. If J<>0 then
  535. begin
  536. HaveArg:=true;
  537. OV:=O;
  538. Delete(OV,1,J);
  539. O:=Copy(O,1,J-1);
  540. end;
  541. // Switch Option
  542. If FindLongopt(O) then
  543. begin
  544. If HaveArg then
  545. AddToResult(Format(SErrNoOptionAllowed,[I,O]));
  546. end
  547. else
  548. begin // Required argument
  549. If FindLongOpt(O+':') then
  550. begin
  551. If Not HaveArg then
  552. AddToResult(Format(SErrOptionNeeded,[I,O]));
  553. end
  554. else
  555. begin // Optional Argument.
  556. If not FindLongOpt(O+'::') then
  557. AddToResult(Format(SErrInvalidOption,[I,O]));
  558. end;
  559. end;
  560. end
  561. else // Short Option.
  562. begin
  563. HaveArg:=(I<ParamCount) and (Length(ParamStr(I+1))>0) and (ParamStr(I+1)[1]<>FOptionChar);
  564. UsedArg:=False;
  565. If Not CaseSensitiveOptions then
  566. O:=LowerCase(O);
  567. L:=Length(O);
  568. J:=2;
  569. While ((Result='') or AllErrors) and (J<=L) do
  570. begin
  571. P:=Pos(O[J],SO);
  572. If (P=0) or (O[j]=':') then
  573. AddToResult(Format(SErrInvalidOption,[I,O[J]]))
  574. else
  575. begin
  576. If (P<Length(SO)) and (SO[P+1]=':') then
  577. begin
  578. // Required argument
  579. If ((P+1)=Length(SO)) or (SO[P+2]<>':') Then
  580. If (J<L) or not haveArg then // Must be last in multi-opt !!
  581. AddToResult(Format(SErrOptionNeeded,[I,O[J]]));
  582. O:=O[j]; // O is added to arguments.
  583. UsedArg:=True;
  584. end;
  585. end;
  586. Inc(J);
  587. end;
  588. HaveArg:=HaveArg and UsedArg;
  589. If HaveArg then
  590. begin
  591. Inc(I); // Skip argument.
  592. OV:=Paramstr(I);
  593. end;
  594. end;
  595. If HaveArg and ((Result='') or AllErrors) then
  596. If Assigned(Opts) then
  597. Opts.Add(O+'='+OV);
  598. end;
  599. end;
  600. Inc(I);
  601. end;
  602. end;
  603. function TCustomApplication.CheckOptions(const ShortOptions: String;
  604. const Longopts: array of string; Opts, NonOpts: TStrings; AllErrors: Boolean
  605. ): String;
  606. Var
  607. L : TStringList;
  608. I : Integer;
  609. begin
  610. L:=TStringList.Create;
  611. Try
  612. For I:=0 to High(LongOpts) do
  613. L.Add(LongOpts[i]);
  614. Result:=CheckOptions(ShortOptions,L,Opts,NonOpts,AllErrors);
  615. Finally
  616. L.Free;
  617. end;
  618. end;
  619. function TCustomApplication.CheckOptions(const ShortOptions: String;
  620. const LongOpts: array of string; AllErrors: Boolean): String;
  621. Var
  622. L : TStringList;
  623. I : Integer;
  624. begin
  625. L:=TStringList.Create;
  626. Try
  627. For I:=0 to High(LongOpts) do
  628. L.Add(LongOpts[i]);
  629. Result:=CheckOptions(ShortOptions,L,AllErrors);
  630. Finally
  631. L.Free;
  632. end;
  633. end;
  634. function TCustomApplication.CheckOptions(const ShortOptions: String;
  635. const LongOpts: String; AllErrors: Boolean): String;
  636. Const
  637. SepChars = ' '#10#13#9;
  638. Var
  639. L : TStringList;
  640. Len,I,J : Integer;
  641. begin
  642. L:=TStringList.Create;
  643. Try
  644. I:=1;
  645. Len:=Length(LongOpts);
  646. While I<=Len do
  647. begin
  648. While Isdelimiter(SepChars,LongOpts,I) do
  649. Inc(I);
  650. J:=I;
  651. While (J<=Len) and Not IsDelimiter(SepChars,LongOpts,J) do
  652. Inc(J);
  653. If (I<=J) then
  654. L.Add(Copy(LongOpts,I,(J-I)));
  655. I:=J+1;
  656. end;
  657. Result:=CheckOptions(Shortoptions,L,AllErrors);
  658. Finally
  659. L.Free;
  660. end;
  661. end;
  662. function TCustomApplication.GetNonOptions(const ShortOptions: String;
  663. const Longopts: array of string): TStringArray;
  664. Var
  665. NO : TStrings;
  666. I : Integer;
  667. begin
  668. No:=TStringList.Create;
  669. try
  670. GetNonOptions(ShortOptions,LongOpts,No);
  671. SetLength(Result,NO.Count);
  672. For I:=0 to NO.Count-1 do
  673. Result[I]:=NO[i];
  674. finally
  675. NO.Free;
  676. end;
  677. end;
  678. procedure TCustomApplication.GetNonOptions(const ShortOptions: String;
  679. const Longopts: array of string; NonOptions: TStrings);
  680. Var
  681. S : String;
  682. begin
  683. S:=CheckOptions(ShortOptions,LongOpts,Nil,NonOptions,true);
  684. if (S<>'') then
  685. Raise EListError.Create(S);
  686. end;
  687. end.