{ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code 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. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * *************************************************************************** } unit ModeMatrixOpts; {$mode objfpc}{$H+} interface uses Classes, SysUtils, contnrs, LazConfigStorage, Laz2_XMLCfg, LazLogger, LazUTF8, FileProcs, KeywordFuncLists, CodeToolsCfgScript, LazarusIDEStrConsts; const BuildMatrixProjectName = '#project'; BuildMatrixIDEName = '#ide'; type TBuildMatrixOptionType = ( bmotCustom, // append fpc parameters in Value bmotOutDir, // override output directory -FU of target bmotIDEMacro // MacroName and Value ); TBuildMatrixOptionTypes = set of TBuildMatrixOptionType; const BuildMatrixOptionTypeNames: array[TBuildMatrixOptionType] of string = ( 'Custom', 'OutDir', 'IDEMacro' ); type TBuildMatrixGroupType = ( bmgtEnvironment, bmgtProject, bmgtSession ); TBuildMatrixGroupTypes = set of TBuildMatrixGroupType; const bmgtAll = [low(TBuildMatrixGroupType)..high(TBuildMatrixGroupType)]; type TStrToBoolEvent = function(const Identifier: string): boolean of object; TBuildMatrixOptions = class; { TBuildMatrixOption } TBuildMatrixOption = class(TPersistent) private FID: string; FList: TBuildMatrixOptions; FMacroName: string; FModes: string; FTargets: string; FTyp: TBuildMatrixOptionType; FValue: string; procedure SetMacroName(AValue: string); procedure SetModes(AValue: string); procedure SetTargets(AValue: string); procedure SetTyp(AValue: TBuildMatrixOptionType); procedure SetValue(AValue: string); public procedure Assign(Source: TPersistent); override; constructor Create(aList: TBuildMatrixOptions); destructor Destroy; override; function FitsTarget(const Target: string): boolean; function FitsMode(const Mode: string): boolean; property List: TBuildMatrixOptions read FList; property ID: string read FID write FID; property Targets: string read FTargets write SetTargets; property Modes: string read FModes write SetModes; // modes separated by line breaks, case insensitive property Typ: TBuildMatrixOptionType read FTyp write SetTyp; property MacroName: string read FMacroName write SetMacroName; property Value: string read FValue write SetValue; function Equals(Obj: TObject): boolean; override; function GetModesSeparatedByComma(const SaveModes: TStrToBoolEvent): string; procedure SetModesFromCommaSeparatedList(aList: string); procedure DisableModes(const DisableModeEvent: TStrToBoolEvent); procedure EnableMode(aMode: string); procedure RenameMode(const OldMode, NewMode: string); procedure LoadFromConfig(Cfg: TConfigStorage); procedure SaveToConfig(Cfg: TConfigStorage; const SaveModes: TStrToBoolEvent); procedure LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string); procedure SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string; const SaveModes: TStrToBoolEvent); function AsString: string; end; { TBuildMatrixOptions } TBuildMatrixOptions = class(TPersistent) private FChangeStep: int64; fSavedChangeStep: int64; fClearing: boolean; fItems: TObjectList; // list of TBuildMatrixOption FOnChanged: TNotifyEvent; FOnChangesd: TNotifyEvent; function GetItems(Index: integer): TBuildMatrixOption; function GetModified: boolean; procedure SetModified(AValue: boolean); public procedure Assign(Source: TPersistent); override; constructor Create; destructor Destroy; override; procedure Clear; function Count: integer; property Items[Index: integer]: TBuildMatrixOption read GetItems; default; function IndexOf(Option: TBuildMatrixOption): integer; function Add(Typ: TBuildMatrixOptionType = bmotCustom; Targets: string = '*'): TBuildMatrixOption; procedure Delete(Index: integer); procedure DisableModes(const IsModeEvent: TStrToBoolEvent); procedure RenameMode(const OldMode, NewMode: string); // equals, modified property ChangeStep: int64 read FChangeStep; procedure IncreaseChangeStep; function Equals(Obj: TObject): boolean; override; property OnChanged: TNotifyEvent read FOnChanged write FOnChangesd; property Modified: boolean read GetModified write SetModified; // load, save procedure LoadFromConfig(Cfg: TConfigStorage); procedure SaveToConfig(Cfg: TConfigStorage; const SaveMode: TStrToBoolEvent); procedure LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string); procedure SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string; const SaveMode: TStrToBoolEvent); function SaveAtOldXMLConfig(Cfg: TXMLConfig; const Path, ModeIdent: string): integer; procedure SaveSessionEnabled(Cfg: TXMLConfig; const Path, ModeIdent: string; var Cnt: integer); // queries procedure AppendCustomOptions(Target, ActiveMode: string; var Options: string); procedure GetOutputDirectory(Target, ActiveMode: string; var OutDir: string); function FindOption(const ID: string): TBuildMatrixOption; function FindMacro(const MacroName, MacroValue: string): TBuildMatrixOption; procedure EnableModeIfOptionFound(ModeID, OptionID: String); end; EMMMacroSyntaxException = class(Exception) end; function BuildMatrixTargetFits(Target, Targets: string): boolean; function BuildMatrixTargetFitsPattern(Target, Pattern: PChar): boolean; function CheckBuildMatrixTargetsSyntax(const Targets: String): String; function BuildMatrixModeFits(Mode, ModesSeparatedByLineBreaks: string): boolean; function Str2BuildMatrixOptionType(const s: string): TBuildMatrixOptionType; function CreateBuildMatrixOptionGUID: string; function SplitMatrixMacro(MacroAssignment: string; out MacroName, MacroValue: string; ExceptionOnError: boolean): boolean; procedure ApplyBuildMatrixMacros(Options: TBuildMatrixOptions; Target, ActiveMode: string; CfgVars: TCTCfgScriptVariables); implementation function BuildMatrixTargetFits(Target, Targets: string): boolean; { case insensitive * = all a = fits a and A a* = fits all starting with a a? = fits all two letter names starting with a Comma and minus: Fits if there is at least one positive match and no negative match a,b = fits a or b -a = if target is a, stop immediately with 'false' -ab,a* = fits all beginning with a except for ab a*,-ab = fits all beginning with a, the -ab is ignored } var p: PChar; Negated: Boolean; begin Result:=false; if (Targets='') or (Target='') then exit; p:=PChar(Targets); repeat if p^='-' then begin Negated:=true; inc(p); end else Negated:=false; if BuildMatrixTargetFitsPattern(PChar(Target),p) then begin if Negated then begin exit(false); end else begin Result:=true; end; end; while not (p^ in [',',#0]) do inc(p); while p^=',' do inc(p); until p^=#0; end; function BuildMatrixTargetFitsPattern(Target, Pattern: PChar): boolean; // Pattern ends at #0 or comma // ? means one arbitrary character // * means any arbitrary characters, even none begin Result:=false; if (Target=nil) or (Target^=#0) or (Pattern=nil) or (Pattern^ in [#0,',']) then exit; repeat case Pattern^ of #0,',': begin // end of pattern reached Result:=Target^=#0; exit; end; '?': begin // one arbitrary character if Target^=#0 then exit; inc(Pattern); inc(Target); end; '*': begin repeat inc(Pattern); until Pattern^<>'*'; if Pattern^ in [#0,','] then exit(true); // behind the * comes a none * => check recursively all combinations while Target^<>#0 do begin if BuildMatrixTargetFitsPattern(Target,Pattern) then exit(true); inc(Target); end; exit; end; 'a'..'z','A'..'Z': begin if UpChars[Pattern^]<>UpChars[Target^] then exit; inc(Pattern); inc(Target) end; else if Pattern^<>Target^ then exit; inc(Pattern); inc(Target); end; until false; end; function CheckBuildMatrixTargetsSyntax(const Targets: String): String; var p: PChar; procedure WarnInvalidChar; begin Result:=Format(lisMMInvalidCharacterAt, [dbgstr(p^), IntToStr(p-PChar( Targets)+1)]); end; begin Result:=''; if Targets='' then exit; p:=PChar(Targets); repeat case p^ of #0: if p-PChar(Targets)=length(Targets) then break else begin WarnInvalidChar; exit; end; #1..#32,#127: begin WarnInvalidChar; exit; end; end; inc(p); until false; end; function BuildMatrixModeFits(Mode, ModesSeparatedByLineBreaks: string): boolean; var p: PChar; m: PChar; begin Result:=false; if Mode='' then exit; if ModesSeparatedByLineBreaks='' then exit; p:=PChar(ModesSeparatedByLineBreaks); while p^<>#0 do begin while p^ in [#1..#31] do inc(p); m:=PChar(Mode); while (UpChars[p^]=UpChars[m^]) and (p^>=' ') do begin inc(p); inc(m); end; if (m^=#0) and (p^ in [#10,#13,#0]) then exit(true); while p^>=' ' do inc(p); end; end; function Str2BuildMatrixOptionType(const s: string): TBuildMatrixOptionType; begin for Result:=low(TBuildMatrixOptionType) to high(TBuildMatrixOptionType) do if SysUtils.CompareText(BuildMatrixOptionTypeNames[Result],s)=0 then exit; Result:=bmotCustom; end; function CreateBuildMatrixOptionGUID: string; var i: Integer; begin SetLength(Result,12); for i:=1 to length(Result) do Result[i]:=chr(ord('0')+random(10)); end; function SplitMatrixMacro(MacroAssignment: string; out MacroName, MacroValue: string; ExceptionOnError: boolean): boolean; procedure E(Msg: string); begin raise EMMMacroSyntaxException.Create(Msg); end; var p: PChar; StartP: PChar; begin Result:=false; MacroName:=''; MacroValue:=''; if MacroAssignment='' then begin if ExceptionOnError then E(lisMMMissingMacroName); exit; end; p:=PChar(MacroAssignment); if not IsIdentStartChar[p^] then begin if ExceptionOnError then E(Format(lisMMExpectedMacroNameButFound, [dbgstr(p^)])); exit; end; StartP:=p; repeat inc(p); until not IsIdentChar[p^]; MacroName:=copy(MacroAssignment,1,p-StartP); if (p^<>':') or (p[1]<>'=') then begin if ExceptionOnError then E(Format(lisMMExpectedAfterMacroNameButFound, [dbgstr(p^)])); exit; end; inc(p,2); StartP:=p; repeat if (p^=#0) and (p-PChar(MacroAssignment)=length(MacroAssignment)) then break; if p^ in [#0..#31,#127] then begin if ExceptionOnError then E(Format(lisMMInvalidCharacterInMacroValue, [dbgstr(p^)])); exit; end; inc(p); until false; MacroValue:=copy(MacroAssignment,StartP-PChar(MacroAssignment)+1,p-StartP); Result:=true; end; procedure ApplyBuildMatrixMacros(Options: TBuildMatrixOptions; Target, ActiveMode: string; CfgVars: TCTCfgScriptVariables); var i: Integer; Option: TBuildMatrixOption; begin if (Options=nil) or (CfgVars=nil) then exit; for i:=0 to Options.Count-1 do begin Option:=Options[i]; if Option.Typ<>bmotIDEMacro then continue; if not Option.FitsMode(ActiveMode) then continue; if not Option.FitsTarget(Target) then continue; //debugln(['ApplyBuildMatrixMacros Option.MacroName="',Option.MacroName,'" Value="',Option.Value,'"']); CfgVars.Values[Option.MacroName]:=Option.Value; end; end; { TBuildMatrixOptions } function TBuildMatrixOptions.GetItems(Index: integer): TBuildMatrixOption; begin Result:=TBuildMatrixOption(fItems[Index]); end; function TBuildMatrixOptions.GetModified: boolean; begin Result:=fSavedChangeStep<>FChangeStep; end; procedure TBuildMatrixOptions.SetModified(AValue: boolean); begin if AValue then IncreaseChangeStep else fSavedChangeStep:=FChangeStep; end; procedure TBuildMatrixOptions.Assign(Source: TPersistent); var aSource: TBuildMatrixOptions; i: Integer; Item: TBuildMatrixOption; begin if Source is TBuildMatrixOptions then begin aSource:=TBuildMatrixOptions(Source); Clear; for i:=0 to aSource.Count-1 do begin Item:=TBuildMatrixOption.Create(Self); Item.Assign(aSource[i]); end; end else inherited Assign(Source); end; constructor TBuildMatrixOptions.Create; begin FChangeStep:=CTInvalidChangeStamp64; fItems:=TObjectList.create(true); end; destructor TBuildMatrixOptions.Destroy; begin Clear; FreeAndNil(fItems); inherited Destroy; end; procedure TBuildMatrixOptions.Clear; begin if fItems.Count=0 then exit; fClearing:=true; fItems.Clear; fClearing:=false; IncreaseChangeStep; end; procedure TBuildMatrixOptions.DisableModes(const IsModeEvent: TStrToBoolEvent); var i: Integer; begin for i:=0 to Count-1 do Items[i].DisableModes(IsModeEvent); end; procedure TBuildMatrixOptions.RenameMode(const OldMode, NewMode: string); var i: Integer; begin for i:=0 to Count-1 do Items[i].RenameMode(OldMode,NewMode); end; function TBuildMatrixOptions.Count: integer; begin Result:=fItems.Count; end; function TBuildMatrixOptions.IndexOf(Option: TBuildMatrixOption): integer; begin Result:=fItems.IndexOf(Option); end; function TBuildMatrixOptions.Add(Typ: TBuildMatrixOptionType; Targets: string ): TBuildMatrixOption; begin Result:=TBuildMatrixOption.Create(Self); Result.Targets:=Targets; Result.Typ:=Typ; end; procedure TBuildMatrixOptions.Delete(Index: integer); begin Items[Index].Free; end; procedure TBuildMatrixOptions.IncreaseChangeStep; begin CTIncreaseChangeStamp64(FChangeStep); if Assigned(OnChanged) then OnChanged(Self); end; function TBuildMatrixOptions.Equals(Obj: TObject): boolean; var Src: TBuildMatrixOptions; i: Integer; begin Result:=false; if Self=Obj then exit; if not (Obj is TBuildMatrixOptions) then exit; Src:=TBuildMatrixOptions(Obj); if Src.Count<>Count then exit; for i:=0 to Count-1 do if not Src[i].Equals(Items[i]) then exit; Result:=true; end; procedure TBuildMatrixOptions.LoadFromConfig(Cfg: TConfigStorage); var Cnt: Integer; i: Integer; Option: TBuildMatrixOption; begin Clear; Cnt:=Cfg.GetValue('Count',0); for i:=1 to Cnt do begin Option:=TBuildMatrixOption.Create(Self); Cfg.AppendBasePath('Item'+IntToStr(i)); Option.LoadFromConfig(Cfg); Cfg.UndoAppendBasePath; end; end; procedure TBuildMatrixOptions.SaveToConfig(Cfg: TConfigStorage; const SaveMode: TStrToBoolEvent); var i: Integer; begin Cfg.SetDeleteValue('Count',Count,0); for i:=0 to Count-1 do begin Cfg.AppendBasePath('Item'+IntToStr(i+1)); Items[i].SaveToConfig(Cfg,SaveMode); Cfg.UndoAppendBasePath; end; end; procedure TBuildMatrixOptions.LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string); var Cnt: Integer; i: Integer; Option: TBuildMatrixOption; begin Clear; Cnt:=Cfg.GetValue(aPath+'Count',0); //debugln(['TBuildMatrixOptions.LoadFromXMLConfig Cnt=',Cnt]); for i:=1 to Cnt do begin Option:=TBuildMatrixOption.Create(Self); Option.LoadFromXMLConfig(Cfg,aPath+'Item'+IntToStr(i)+'/'); end; //debugln(['TBuildMatrixOptions.LoadFromXMLConfig Count=',Count]); end; procedure TBuildMatrixOptions.SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string; const SaveMode: TStrToBoolEvent); var i: Integer; begin //debugln(['TBuildMatrixOptions.SaveToXMLConfig ',aPath]); Cfg.SetDeleteValue(aPath+'Count',Count,0); for i:=0 to Count-1 do Items[i].SaveToXMLConfig(Cfg,aPath+'Item'+IntToStr(i+1)+'/',SaveMode); end; function TBuildMatrixOptions.SaveAtOldXMLConfig(Cfg: TXMLConfig; const Path, ModeIdent: string): integer; var i: Integer; MatrixOption: TBuildMatrixOption; SubPath: String; begin Result:=0; for i:=0 to Count-1 do begin MatrixOption:=Items[i]; if (MatrixOption.Typ=bmotIDEMacro) and MatrixOption.FitsTarget(BuildMatrixProjectName) and MatrixOption.FitsMode(ModeIdent) then begin inc(Result); SubPath:=Path+'Macro'+IntToStr(i+1)+'/'; Cfg.SetDeleteValue(SubPath+'Name',MatrixOption.MacroName,''); Cfg.SetDeleteValue(SubPath+'Value',MatrixOption.Value,''); end; end; end; procedure TBuildMatrixOptions.SaveSessionEnabled(Cfg: TXMLConfig; const Path, ModeIdent: string; var Cnt: integer); var MatrixOption: TBuildMatrixOption; SubPath: String; i: Integer; begin for i:=0 to Count-1 do begin MatrixOption:=Items[i]; //debugln(['SaveSessionEnabled ',MatrixOption.AsString]); if not MatrixOption.FitsMode(ModeIdent) then continue; inc(Cnt); SubPath:=Path+'Item'+IntToStr(Cnt)+'/'; //debugln(['SaveSessionEnabled ModeID="',CurMode.Identifier,'" OptionID="',MatrixOption.ID,'" ',MatrixOption.AsString]); Cfg.SetDeleteValue(SubPath+'Mode',ModeIdent,''); Cfg.SetDeleteValue(SubPath+'Option',MatrixOption.ID,''); end; end; procedure TBuildMatrixOptions.AppendCustomOptions(Target, ActiveMode: string; var Options: string); var i: Integer; Option: TBuildMatrixOption; Value: String; begin for i:=0 to Count-1 do begin Option:=Items[i]; if Option.Typ<>bmotCustom then continue; Value:=Trim(Option.Value); if Value='' then continue; if not Option.FitsTarget(Target) then continue; if not Option.FitsMode(ActiveMode) then continue; if Options<>'' then Options+=' '; Options+=Value; end; end; procedure TBuildMatrixOptions.GetOutputDirectory(Target, ActiveMode: string; var OutDir: string); var i: Integer; Option: TBuildMatrixOption; begin for i:=0 to Count-1 do begin Option:=Items[i]; if Option.Typ<>bmotOutDir then continue; if not Option.FitsTarget(Target) then continue; if not Option.FitsMode(ActiveMode) then continue; OutDir:=Option.Value; end; end; function TBuildMatrixOptions.FindOption(const ID: string): TBuildMatrixOption; var i: Integer; begin for i:=0 to Count-1 do begin Result:=Items[i]; if Result.ID=ID then exit; end; Result:=nil; end; function TBuildMatrixOptions.FindMacro(const MacroName, MacroValue: string): TBuildMatrixOption; var i: Integer; begin i:=Count-1; while i>=0 do begin Result:=Items[i]; if (Result.Typ=bmotIDEMacro) and (Result.Targets='*') and (Result.MacroName=MacroName) and (Result.Value=MacroValue) then exit; dec(i); end; Result:=nil; end; procedure TBuildMatrixOptions.EnableModeIfOptionFound(ModeID, OptionID: String); var Opt: TBuildMatrixOption; begin Opt:=FindOption(OptionID); if Assigned(Opt) then Opt.EnableMode(ModeID); end; { TBuildMatrixOption } procedure TBuildMatrixOption.SetMacroName(AValue: string); begin if FMacroName=AValue then Exit; FMacroName:=AValue; List.IncreaseChangeStep; end; procedure TBuildMatrixOption.SetModes(AValue: string); begin if FModes=AValue then exit; FModes:=AValue; List.IncreaseChangeStep; end; procedure TBuildMatrixOption.SetTargets(AValue: string); begin if FTargets=AValue then Exit; FTargets:=AValue; List.IncreaseChangeStep; end; procedure TBuildMatrixOption.SetTyp(AValue: TBuildMatrixOptionType); begin if FTyp=AValue then Exit; FTyp:=AValue; List.IncreaseChangeStep; end; procedure TBuildMatrixOption.SetValue(AValue: string); begin if FValue=AValue then Exit; FValue:=AValue; List.IncreaseChangeStep; end; procedure TBuildMatrixOption.Assign(Source: TPersistent); var aSource: TBuildMatrixOption; begin if Source is TBuildMatrixOption then begin aSource:=TBuildMatrixOption(Source); ID:=aSource.ID; Targets:=aSource.Targets; Modes:=aSource.Modes; Typ:=aSource.Typ; MacroName:=aSource.MacroName; Value:=aSource.Value; end else inherited Assign(Source); end; constructor TBuildMatrixOption.Create(aList: TBuildMatrixOptions); begin FID:=CreateBuildMatrixOptionGUID; FList:=aList; if List<>nil then List.fItems.Add(Self); end; destructor TBuildMatrixOption.Destroy; begin List.fItems.Remove(Self); FList:=nil; inherited Destroy; end; function TBuildMatrixOption.FitsTarget(const Target: string): boolean; begin Result:=BuildMatrixTargetFits(Target,Targets); end; function TBuildMatrixOption.FitsMode(const Mode: string): boolean; begin Result:=BuildMatrixModeFits(Mode,Modes); end; function TBuildMatrixOption.Equals(Obj: TObject): boolean; var Src: TBuildMatrixOption; begin Result:=false; if Obj=Self then exit; if not (Obj is TBuildMatrixOption) then exit; Src:=TBuildMatrixOption(Obj); if Src.Targets<>Targets then exit; if Src.Modes<>Modes then exit; if Src.Typ<>Typ then exit; if Src.MacroName<>MacroName then exit; if Src.Value<>Value then exit; Result:=true; end; function TBuildMatrixOption.GetModesSeparatedByComma( const SaveModes: TStrToBoolEvent): string; var p, StartP: PChar; l: SizeInt; CurMode: string; i: Integer; begin Result:=''; if Modes='' then exit; p:=PChar(Modes); while p^<>#0 do begin StartP:=p; while not (p^ in [#0,#10,#13]) do inc(p); l:=p-StartP; while p^ in [#10,#13] do inc(p); if l=0 then continue; // skip empty strings SetLength(CurMode,l); System.Move(StartP^,CurMode[1],l); if Assigned(SaveModes) and not SaveModes(CurMode) then continue; // convert a single comma to double comma for i:=length(CurMode) downto 1 do if CurMode[i]=',' then System.Insert(',',CurMode,i); if Result<>'' then Result+=','; Result+=CurMode; end; //debugln(['TBuildMatrixOption.GetModesSeparatedByComma ',dbgstr(Modes),' -> ',dbgstr(Result)]); end; procedure TBuildMatrixOption.SetModesFromCommaSeparatedList(aList: string); var p: Integer; begin //debugln(['TBuildMatrixOption.SetModesFromCommaSeparatedList START aList=',aList]); p:=1; while p<=length(aList) do begin if aList[p]=',' then begin if (p#0 do begin StartP:=p; while not (p^ in [#0,#10,#13]) do inc(p); StartPos:=StartP-PChar(CurModes)+1; CurMode:=copy(CurModes,StartPos,p-StartP); if CompareText(CurMode,OldMode)=0 then begin ReplaceSubstring(CurModes,StartPos,p-StartP,NewMode); p:=Pointer(CurModes)+StartPos-1+length(NewMode); end; while p^ in [#10,#13] do inc(p); end; Modes:=CurModes; end; procedure TBuildMatrixOption.LoadFromConfig(Cfg: TConfigStorage); begin ID:=Cfg.GetValue('ID',''); if ID='' then ID:=CreateBuildMatrixOptionGUID; Targets:=Cfg.GetValue('Targets','*'); SetModesFromCommaSeparatedList(Cfg.GetValue('Modes','')); Typ:=Str2BuildMatrixOptionType(Cfg.GetValue('Type','')); MacroName:=Cfg.GetValue('MacroName',''); Value:=Cfg.GetValue('Value',''); end; procedure TBuildMatrixOption.SaveToConfig(Cfg: TConfigStorage; const SaveModes: TStrToBoolEvent); begin Cfg.SetDeleteValue('ID',ID,''); Cfg.SetDeleteValue('Targets',Targets,'*'); Cfg.SetDeleteValue('Modes',GetModesSeparatedByComma(SaveModes),''); Cfg.SetDeleteValue('Type',BuildMatrixOptionTypeNames[Typ],BuildMatrixOptionTypeNames[bmotCustom]); Cfg.SetDeleteValue('MacroName',MacroName,''); Cfg.SetDeleteValue('Value',Value,''); end; procedure TBuildMatrixOption.LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string); begin ID:=Cfg.GetValue(aPath+'ID',''); if ID='' then ID:=CreateBuildMatrixOptionGUID; Targets:=Cfg.GetValue(aPath+'Targets','*'); SetModesFromCommaSeparatedList(Cfg.GetValue(aPath+'Modes','')); Typ:=Str2BuildMatrixOptionType(Cfg.GetValue(aPath+'Type','')); MacroName:=Cfg.GetValue(aPath+'MacroName',''); Value:=Cfg.GetValue(aPath+'Value',''); end; procedure TBuildMatrixOption.SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string; const SaveModes: TStrToBoolEvent); begin Cfg.SetDeleteValue(aPath+'ID',ID,''); Cfg.SetDeleteValue(aPath+'Targets',Targets,'*'); Cfg.SetDeleteValue(aPath+'Modes',GetModesSeparatedByComma(SaveModes),''); Cfg.SetDeleteValue(aPath+'Type',BuildMatrixOptionTypeNames[Typ],BuildMatrixOptionTypeNames[bmotCustom]); Cfg.SetDeleteValue(aPath+'MacroName',MacroName,''); Cfg.SetDeleteValue(aPath+'Value',Value,''); end; function TBuildMatrixOption.AsString: string; begin Result:='ID="'+ID+'" '+BuildMatrixOptionTypeNames[Typ] +' Value="'+Value+'"' +' Modes="'+dbgstr(Modes)+'"'; end; end.