mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 03:02:41 +02:00
437 lines
11 KiB
ObjectPascal
437 lines
11 KiB
ObjectPascal
{
|
|
$Id$
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2003 by the Free Pascal development team
|
|
|
|
CustomApplication class.
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
{$mode objfpc}
|
|
{$h+}
|
|
unit CustApp;
|
|
|
|
Interface
|
|
|
|
uses SysUtils,Classes;
|
|
|
|
Type
|
|
TExceptionEvent = Procedure (Sender : TObject; E : Exception) Of Object;
|
|
|
|
TCustomApplication = Class(TComponent)
|
|
Private
|
|
FOnException: TExceptionEvent;
|
|
FTerminated : Boolean;
|
|
FHelpFile,
|
|
FTitle : String;
|
|
FOptionChar : Char;
|
|
FCaseSensitiveOptions : Boolean;
|
|
FStopOnException : Boolean;
|
|
function GetEnvironmentVar(VarName : String): String;
|
|
function GetExeName: string;
|
|
Function GetLocation : String;
|
|
function GetTitle: string;
|
|
Protected
|
|
procedure SetTitle(const AValue: string); Virtual;
|
|
Function GetConsoleApplication : boolean; Virtual;
|
|
Procedure DoRun; Virtual;
|
|
Function GetParams(Index : Integer) : String;virtual;
|
|
function GetParamCount: Integer;Virtual;
|
|
Public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
// Some Delphi methods.
|
|
procedure HandleException(Sender: TObject); virtual;
|
|
procedure Initialize; virtual;
|
|
procedure Run;
|
|
procedure ShowException(E: Exception);virtual;
|
|
procedure Terminate; virtual;
|
|
// Extra methods.
|
|
function FindOptionIndex(Const S : String; Var Longopt : Boolean) : Integer;
|
|
Function GetOptionValue(Const S : String) : String;
|
|
Function GetOptionValue(Const C: Char; Const S : String) : String;
|
|
Function HasOption(Const S : String) : Boolean;
|
|
Function HasOption(Const C : Char; Const S : String) : Boolean;
|
|
Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
|
|
Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings) : String;
|
|
Function CheckOptions(Const ShortOptions : String; Const LongOpts : Array of string) : String;
|
|
Function CheckOptions(Const ShortOptions : String; Const LongOpts : String) : String;
|
|
Procedure GetEnvironmentList(List : TStrings;NamesOnly : Boolean);
|
|
Procedure GetEnvironmentList(List : TStrings);
|
|
// Delphi properties
|
|
property ExeName: string read GetExeName;
|
|
property HelpFile: string read FHelpFile write FHelpFile;
|
|
property Terminated: Boolean read FTerminated;
|
|
property Title: string read FTitle write SetTitle;
|
|
property OnException: TExceptionEvent read FOnException write FOnException;
|
|
// Extra properties
|
|
Property ConsoleApplication : Boolean Read GetConsoleApplication;
|
|
Property Location : String Read GetLocation;
|
|
Property Params [Index : integer] : String Read GetParams;
|
|
Property ParamCount : Integer Read GetParamCount;
|
|
Property EnvironmentVariable[Name : String] : String Read GetEnvironmentVar;
|
|
Property OptionChar : Char Read FoptionChar Write FOptionChar;
|
|
Property CaseSensitiveOptions : Boolean Read FCaseSensitiveOptions Write FCaseSensitiveOptions;
|
|
Property StopOnException : Boolean Read FStopOnException Write FStopOnException;
|
|
end;
|
|
|
|
Implementation
|
|
|
|
{$i custapp.inc}
|
|
|
|
{ TCustomApplication }
|
|
|
|
function TCustomApplication.GetExeName: string;
|
|
begin
|
|
Result:=Paramstr(0);
|
|
end;
|
|
|
|
|
|
function TCustomApplication.GetEnvironmentVar(VarName : String): String;
|
|
begin
|
|
Result:=GetEnvironmentVariable(VarName);
|
|
end;
|
|
|
|
Procedure TCustomApplication.GetEnvironmentList(List : TStrings;NamesOnly : Boolean);
|
|
|
|
begin
|
|
// Routine must be in custapp.inc
|
|
SysGetEnvironmentList(List,NamesOnly);
|
|
end;
|
|
|
|
Procedure TCustomApplication.GetEnvironmentList(List : TStrings);
|
|
|
|
begin
|
|
GetEnvironmentList(List,False);
|
|
end;
|
|
|
|
function TCustomApplication.GetLocation: String;
|
|
begin
|
|
Result:=ExtractFilePath(GetExeName);
|
|
end;
|
|
|
|
function TCustomApplication.GetParamCount: Integer;
|
|
begin
|
|
Result:=System.ParamCount;
|
|
end;
|
|
|
|
function TCustomApplication.GetTitle: string;
|
|
begin
|
|
Result:=FTitle;
|
|
end;
|
|
|
|
function TCustomApplication.GetParams(Index: Integer): String;
|
|
begin
|
|
Result:=ParamStr(Index);
|
|
end;
|
|
|
|
procedure TCustomApplication.SetTitle(const AValue: string);
|
|
begin
|
|
FTitle:=AValue;
|
|
end;
|
|
|
|
function TCustomApplication.GetConsoleApplication: boolean;
|
|
begin
|
|
Result:=IsConsole;
|
|
end;
|
|
|
|
procedure TCustomApplication.DoRun;
|
|
begin
|
|
// Do nothing. Override in descendent classes.
|
|
end;
|
|
|
|
constructor TCustomApplication.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FOptionChar:='-';
|
|
FCaseSensitiveOptions:=True;
|
|
FStopOnException:=False;
|
|
end;
|
|
|
|
destructor TCustomApplication.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TCustomApplication.HandleException(Sender: TObject);
|
|
begin
|
|
If Not (ExceptObject is Exception) then
|
|
SysUtils.showexception(ExceptObject,ExceptAddr)
|
|
else
|
|
begin
|
|
If Not Assigned(FOnexception) then
|
|
ShowException(Exception(ExceptObject))
|
|
else
|
|
FOnException(Sender,Exception(ExceptObject));
|
|
end;
|
|
If FStopOnException then
|
|
FTerminated:=True;
|
|
end;
|
|
|
|
|
|
procedure TCustomApplication.Initialize;
|
|
begin
|
|
FTerminated:=False;
|
|
end;
|
|
|
|
procedure TCustomApplication.Run;
|
|
|
|
begin
|
|
Repeat
|
|
Try
|
|
DoRun;
|
|
except
|
|
HandleException(Self);
|
|
end;
|
|
Until FTerminated;
|
|
end;
|
|
|
|
procedure TCustomApplication.ShowException(E: Exception);
|
|
|
|
begin
|
|
Sysutils.ShowException(E,ExceptAddr)
|
|
end;
|
|
|
|
procedure TCustomApplication.Terminate;
|
|
begin
|
|
FTerminated:=True;
|
|
end;
|
|
|
|
function TCustomApplication.GetOptionValue(Const S: String): String;
|
|
begin
|
|
Result:=GetoptionValue(#255,S);
|
|
end;
|
|
|
|
function TCustomApplication.GetOptionValue(Const C: Char; Const S: String): String;
|
|
|
|
Var
|
|
B : Boolean;
|
|
I,P : integer;
|
|
O : String;
|
|
|
|
begin
|
|
Result:='';
|
|
I:=FindOptionIndex(C,B);
|
|
If (I=-1) then
|
|
I:=FindoptionIndex(S,B);
|
|
If (I<>-1) then
|
|
begin
|
|
If B then
|
|
begin // Long options have form --option=value
|
|
O:=Params[I];
|
|
P:=Pos('=',O);
|
|
If (P=0) then
|
|
P:=Length(O);
|
|
Delete(O,1,P);
|
|
Result:=O;
|
|
end
|
|
else
|
|
begin // short options have form '-o value'
|
|
If (I<ParamCount) then
|
|
Result:=Params[I+1];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomApplication.HasOption(Const S: String): Boolean;
|
|
|
|
Var
|
|
B : Boolean;
|
|
|
|
begin
|
|
Result:=FindOptionIndex(S,B)<>-1;
|
|
end;
|
|
|
|
function TCustomApplication.FindOptionIndex(Const S : String; Var Longopt : Boolean) : Integer;
|
|
|
|
Var
|
|
SO,O : String;
|
|
I,P : Integer;
|
|
|
|
begin
|
|
If Not CaseSensitiveOptions then
|
|
SO:=UpperCase(S)
|
|
else
|
|
SO:=S;
|
|
Result:=-1;
|
|
I:=ParamCount;
|
|
While (Result=-1) and (I>0) do
|
|
begin
|
|
O:=Params[i];
|
|
If (Length(O)>0) and (O[1]=FOptionChar) then
|
|
begin
|
|
Delete(O,1,1);
|
|
LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);
|
|
If LongOpt then
|
|
begin
|
|
Delete(O,1,1);
|
|
P:=Pos('=',O);
|
|
If (P<>0) then
|
|
O:=Copy(O,1,P-1);
|
|
end;
|
|
If Not CaseSensitiveOptions then
|
|
O:=UpperCase(O);
|
|
If (O=SO) then
|
|
Result:=i;
|
|
end;
|
|
Dec(i);
|
|
end;
|
|
end;
|
|
|
|
function TCustomApplication.HasOption(Const C: Char; Const S: String): Boolean;
|
|
|
|
Var
|
|
B : Boolean;
|
|
|
|
begin
|
|
Result:=(FindOptionIndex(C,B)<>-1) or (FindOptionIndex(S,B)<>-1);
|
|
end;
|
|
|
|
|
|
Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const Longopts : TStrings) : String;
|
|
|
|
begin
|
|
Result:=CheckOptions(ShortOptions,LongOpts,Nil,Nil);
|
|
end;
|
|
|
|
ResourceString
|
|
SErrInvalidOption = 'Invalid option at position %d: "%s"';
|
|
SErrNoOptionAllowed = 'Option at position %d does not allow an argument: %s';
|
|
SErrOptionNeeded = 'Option at position %d needs an argument : %s';
|
|
|
|
Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
|
|
|
|
Var
|
|
I,J,L,P : Integer;
|
|
O,OV : String;
|
|
HaveArg : Boolean;
|
|
|
|
begin
|
|
Result:='';
|
|
I:=1;
|
|
While (I<=ParamCount) and (Result='') do
|
|
begin
|
|
O:=Paramstr(I);
|
|
If (Length(O)=0) or (O[1]<>FOptionChar) then
|
|
begin
|
|
If Assigned(NonOpts) then
|
|
NonOpts.Add(O)
|
|
end
|
|
else
|
|
begin
|
|
If (Length(O)<2) then
|
|
Result:=Format(SErrInvalidOption,[i,O])
|
|
else
|
|
begin
|
|
HaveArg:=False;
|
|
OV:='';
|
|
// Long option ?
|
|
If (O[2]=FOptionChar) then
|
|
begin
|
|
Delete(O,1,2);
|
|
J:=Pos('=',O);
|
|
If J<>0 then
|
|
begin
|
|
HaveArg:=true;
|
|
OV:=O;
|
|
Delete(OV,1,J);
|
|
O:=Copy(O,1,J-1);
|
|
end;
|
|
// Switch Option
|
|
If Longopts.IndexOf(O)<>-1 then
|
|
begin
|
|
If HaveArg then
|
|
Result:=Format(SErrNoOptionAllowed,[I,O])
|
|
end
|
|
else
|
|
begin // Required argument
|
|
If LongOpts.IndexOf(O+':')<>-1 then
|
|
begin
|
|
If Not HaveArg then
|
|
Result:=Format(SErrOptionNeeded,[I,O]);
|
|
end
|
|
else
|
|
begin // Optional Argument.
|
|
If LongOpts.IndexOf(O+'::')=-1 then
|
|
Result:=Format(SErrInvalidOption,[I,O]);
|
|
end;
|
|
end;
|
|
end
|
|
else // Short Option.
|
|
begin
|
|
HaveArg:=(I<ParamCount) and (Length(ParamStr(I+1))>0) and (ParamStr(I+1)[i]<>FOptionChar);
|
|
If HaveArg then
|
|
OV:=Paramstr(I+1);
|
|
L:=Length(O);
|
|
For J:=2 to L do
|
|
begin
|
|
P:=Pos(O[J],ShortOptions);
|
|
If P=0 then
|
|
Result:=Format(SErrInvalidOption,[I,O[J]])
|
|
else
|
|
begin
|
|
If (P<Length(ShortOptions)) and (Shortoptions[P+1]=':') then
|
|
begin
|
|
// Required argument
|
|
If ((P+1)<Length(ShortOptions)) and (Shortoptions[P+2]<>':') Then
|
|
If (J<L) or not haveArg then // Must be last in multi-opt !!
|
|
Result:=Format(SErrOptionNeeded,[I,O[J]]);
|
|
O:=O[j]; // O is added to arguments.
|
|
end;
|
|
end;
|
|
end;
|
|
If HaveArg then
|
|
begin
|
|
Inc(I); // Skip argument.
|
|
O:=O[Length(O)]; // O is added to arguments !
|
|
end;
|
|
end;
|
|
If HaveArg and (Result='') then
|
|
If Assigned(Opts) then
|
|
Opts.Add(O+'='+OV);
|
|
end;
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const LongOpts : Array of string) : String;
|
|
|
|
Var
|
|
L : TStringList;
|
|
I : Integer;
|
|
|
|
begin
|
|
L:=TStringList.Create;
|
|
Try
|
|
For I:=0 to High(LongOpts) do
|
|
L.Add(LongOpts[i]);
|
|
Result:=CheckOptions(ShortOptions,L);
|
|
Finally
|
|
L.Free;
|
|
end;
|
|
end;
|
|
|
|
Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const LongOpts : String) : String;
|
|
|
|
Var
|
|
L : TStringList;
|
|
|
|
begin
|
|
L:=TStringList.Create;
|
|
Try
|
|
Result:=CheckOptions(Shortoptions,L);
|
|
Finally
|
|
L.Free;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|