You've already forked lazarus-ccr
cmdlinecfg: the initial files commit
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2802 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
285
components/cmdlinecfg/trunk/cmdlinecfgparser.pas
Normal file
285
components/cmdlinecfg/trunk/cmdlinecfgparser.pas
Normal file
@@ -0,0 +1,285 @@
|
||||
unit cmdlinecfgparser;
|
||||
|
||||
interface
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
uses
|
||||
Classes, SysUtils, cmdlinecfg, cmdlinecfgutils;
|
||||
|
||||
type
|
||||
|
||||
{ TCmdLineOptionParse }
|
||||
|
||||
TOptionParse = class(TObject)
|
||||
key : string;
|
||||
opt : TCmdLineCfgOption;
|
||||
isDelimited : Boolean; // the value comes with a white-space after the key
|
||||
isParameter : Boolean;
|
||||
constructor Create(aopt: TCmdLineCfgOption; const akey: string; AisDelim: Boolean; AisParam: Boolean);
|
||||
end;
|
||||
|
||||
{ TCmdLineArgsParser }
|
||||
|
||||
TCmdLineArgsParser = class(TObject)
|
||||
private
|
||||
fKeyPrefix : TStrings;
|
||||
fCfg : TCmdLineCfg;
|
||||
fisValid : Boolean;
|
||||
fMasters : TStringList;
|
||||
MaxMasterLen : Integer;
|
||||
MinMasterLen : Integer;
|
||||
fOptions : TStringList;
|
||||
MaxKeyLen : Integer;
|
||||
MinKeyLen : Integer;
|
||||
protected
|
||||
procedure SetCfg(ACfg: TCmdLineCfg);
|
||||
procedure PrepareConfig;
|
||||
function FindMasterKey(const arg: string): string;
|
||||
function FindParseOption(const arg: string): TOptionParse;
|
||||
function CreateMasterKeyValues(const ArgValue, MasterKey: string; Vals: TList): Boolean;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
// if an argumant doesn't have a corresponding cmd line option;
|
||||
// .Option field will be set to nil. The next "unkey" option will be set as a value;
|
||||
// KeyPrefix - would be used to find values that are not part of arguments only;
|
||||
// the method will create TCmdLineOptionValue objects and add them to values list
|
||||
// it doesn't check for their existance, just adds them!
|
||||
function Parse(Args: TStrings; Vals: TList {of TCmdLineOptionValue}): Boolean;
|
||||
property CmdLineCfg: TCmdLineCfg read fCfg write SetCfg;
|
||||
property KeyPrefix : TStrings read fKeyPrefix;
|
||||
end;
|
||||
|
||||
// note that KeyPrefix defaults to unix keys = "-". On Windows, many MS commandlines
|
||||
// are using "/" as the key prefix
|
||||
procedure CmdLineMatchArgsToOpts(CmdLineCfg: TCmdLineCfg; Args: TStrings; Vals: TList {of TCmdLineOptionValue}; const KeyPrefix: string = '-'); overload;
|
||||
procedure CmdLineMatchArgsToOpts(CmdLineCfg: TCmdLineCfg; const CmdLine: string; Vals: TList {of TCmdLineOptionValue}; const KeyPrefix: string = '-'); overload;
|
||||
|
||||
implementation
|
||||
|
||||
procedure CmdLineMatchArgsToOpts(CmdLineCfg: TCmdLineCfg; Args: TStrings; Vals: TList;
|
||||
const KeyPrefix: string);
|
||||
var
|
||||
parser : TCmdLineArgsParser;
|
||||
begin
|
||||
parser := TCmdLineArgsParser.Create;
|
||||
try
|
||||
parser.CmdLineCfg:=CmdLineCfg;
|
||||
parser.KeyPrefix.Add(KeyPrefix);
|
||||
parser.Parse(Args, Vals);
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure CmdLineMatchArgsToOpts(CmdLineCfg: TCmdLineCfg; const CmdLine: string;
|
||||
Vals: TList; const KeyPrefix: string);
|
||||
var
|
||||
args : TStringList;
|
||||
begin
|
||||
args:=TstringList.Create;
|
||||
try
|
||||
CmdLineParse(cmdLine, args);
|
||||
CmdLineMatchArgsToOpts(cmdlinecfg, args, vals, KeyPrefix);
|
||||
finally
|
||||
args.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TOptionParse }
|
||||
|
||||
constructor TOptionParse.Create(aopt: TCmdLineCfgOption; const akey: string; AisDelim: Boolean; AisParam: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
opt:=Aopt;
|
||||
key:=akey;
|
||||
isDelimited:=AisDelim;
|
||||
isParameter:=AisParam;
|
||||
end;
|
||||
|
||||
{ TCmdLineArgsParse }
|
||||
|
||||
procedure TCmdLineArgsParser.SetCfg(ACfg: TCmdLineCfg);
|
||||
begin
|
||||
if fCfg<>ACfg then begin
|
||||
fisValid:=false;
|
||||
fCfg:=ACfg;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure MaxMinOptionLen(options: TStrings; var minlen, maxlen: Integer);
|
||||
var
|
||||
i : Integer;
|
||||
j : Integer;
|
||||
ln : Integer;
|
||||
k : string;
|
||||
begin
|
||||
maxlen:=0;
|
||||
minlen:=0;
|
||||
if options.Count=0 then Exit;
|
||||
|
||||
for i:=0 to options.Count-1 do begin
|
||||
ln:=length(options[i]);
|
||||
if ln>maxlen then maxlen:=ln;
|
||||
end;
|
||||
|
||||
j:=0;
|
||||
repeat
|
||||
inc(minlen);
|
||||
k:=Copy(options[0],1,minlen);
|
||||
for i:=0 to options.Count-1 do
|
||||
if Pos(k, options[i])<>1 then begin
|
||||
inc(j);
|
||||
break;
|
||||
end;
|
||||
until (j<>0) or (minlen>maxlen);
|
||||
dec(minlen);
|
||||
end;
|
||||
|
||||
procedure TCmdLineArgsParser.PrepareConfig;
|
||||
var
|
||||
i : integer;
|
||||
ov : TCmdLineCfgOption;
|
||||
k : string;
|
||||
j : integer;
|
||||
y : integer;
|
||||
begin
|
||||
if not Assigned(fCfg) then Exit;
|
||||
fMasters.Clear;
|
||||
fOptions.Clear;
|
||||
fMasters.Duplicates:=dupIgnore;
|
||||
for i:=0 to fCfg.Options.Count-1 do begin
|
||||
ov:=TCmdLineCfgOption(fCfg.Options[i]);
|
||||
if not Assigned(ov) then Continue;
|
||||
k:=Trim(ov.Key);
|
||||
if ov.MasterKey<>'' then fMasters.Add(ov.MasterKey);
|
||||
// preparing keys for values with parameters, like -Cp%test% or -Cp %test%
|
||||
j:=Pos('%', k);
|
||||
y:=Pos(' ', k);
|
||||
if (y>0) and ((y<j) or (j=0)) then k:=Copy(k, 1, y-1)
|
||||
else if j>0 then k:=Copy(k, 1, j-1);
|
||||
fOptions.AddObject(k, TOptionParse.Create(ov, k, y>0, j>0) );
|
||||
end;
|
||||
MaxMinOptionLen(fMasters, MinMasterLen, MaxMasterLen);
|
||||
MaxMinOptionLen(fOptions, MinKeyLen, MaxKeyLen);
|
||||
fOptions.Sort;
|
||||
fisValid:=true;
|
||||
end;
|
||||
|
||||
function TCmdLineArgsParser.FindMasterKey(const arg: string): string;
|
||||
var
|
||||
i : integer;
|
||||
t : string;
|
||||
j : integer;
|
||||
begin
|
||||
for i:=MinMasterLen to MaxMasterLen do begin
|
||||
t:=Copy(arg, 1, i);
|
||||
j:=fMasters.IndexOf(t);
|
||||
if j>=0 then begin
|
||||
Result:=fMasters[j];
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result:='';
|
||||
end;
|
||||
|
||||
function TCmdLineArgsParser.FindParseOption(const arg: string): TOptionParse;
|
||||
var
|
||||
k : string;
|
||||
j : Integer;
|
||||
i : Integer;
|
||||
begin
|
||||
for i:=MinKeyLen to MaxKeyLen do begin
|
||||
k:=Copy(arg, 1, i);
|
||||
j:=fOptions.IndexOf(k);
|
||||
if j>=0 then begin
|
||||
Result:=TOptionParse( fOptions.Objects[j] );
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
Result:=nil;
|
||||
end;
|
||||
|
||||
function TCmdLineArgsParser.CreateMasterKeyValues(const ArgValue, MasterKey: string; Vals: TList): Boolean;
|
||||
var
|
||||
i : Integer;
|
||||
k : string;
|
||||
j : Integer;
|
||||
op : TOptionParse;
|
||||
begin
|
||||
Result:=False;
|
||||
for i:=length(MasterKey)+1 to length(ArgValue) do begin
|
||||
k:=MasterKey + ArgValue[i];
|
||||
j:=fOptions.IndexOf(k);
|
||||
if j>=0 then begin
|
||||
Result:=True;
|
||||
op:=TOptionParse(fOptions.Objects[j]);
|
||||
Vals.Add( TCmdLineOptionValue.Create ( op.opt, '1'))
|
||||
end else begin
|
||||
Vals.Add( TCmdLineOptionValue.Create ( nil, k));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TCmdLineArgsParser.Create;
|
||||
begin
|
||||
fKeyPrefix := TStringList.Create;
|
||||
TStringList(fKeyPrefix).CaseSensitive:=true;
|
||||
|
||||
fMasters := TStringList.Create;
|
||||
TStringList(fMasters).CaseSensitive:=true;
|
||||
|
||||
fOptions := TStringList.Create;
|
||||
TStringList(fOptions).CaseSensitive:=true;
|
||||
TStringList(fOptions).OwnsObjects:=true;
|
||||
end;
|
||||
|
||||
destructor TCmdLineArgsParser.Destroy;
|
||||
begin
|
||||
fMasters.Free;
|
||||
fOptions.Clear;
|
||||
fOptions.Free;
|
||||
fKeyPrefix.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TCmdLineArgsParser.Parse(Args: TStrings; Vals: TList): Boolean;
|
||||
var
|
||||
i : integer;
|
||||
v : string;
|
||||
mk : string;
|
||||
op : TOptionParse;
|
||||
begin
|
||||
Result:=Assigned(fCfg);
|
||||
if not Result then Exit;
|
||||
if not fisValid then PrepareConfig;
|
||||
i:=0;
|
||||
while i<Args.Count do begin
|
||||
v:=Args[i];
|
||||
mk:=FindMasterKey(v);
|
||||
if mk<>'' then begin
|
||||
// todo: test if there's any known value among keys!
|
||||
CreateMasterKeyValues(v, mk, Vals);
|
||||
end else begin
|
||||
op:=FindParseOption(v);
|
||||
if not Assigned(op) then
|
||||
Vals.Add ( TCmdLineOptionValue.Create(nil, v))
|
||||
else begin
|
||||
if op.isParameter then begin
|
||||
if op.isDelimited then begin
|
||||
inc(i);
|
||||
if i<Args.Count then v:=args[i] else v:='';
|
||||
end else
|
||||
v:=Copy(v, length(op.key)+1, length(v));
|
||||
end else
|
||||
v:='1'; // is switch, is enabled!
|
||||
Vals.Add( TCmdLineOptionValue.Create(op.opt, v));
|
||||
end;
|
||||
end;
|
||||
inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
Reference in New Issue
Block a user