1 {
2 ***************************************************************************
3 * *
4 * This source is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This code is distributed in the hope that it will be useful, but *
10 * WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * General Public License for more details. *
13 * *
14 * A copy of the GNU General Public License is available on the World *
15 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
16 * obtain it by writing to the Free Software Foundation, *
17 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
18 * *
19 ***************************************************************************
20
21 }
22 unit ModeMatrixOpts;
23
24 {$mode objfpc}{$H+}
25
26 interface
27
28 uses
29 Classes, SysUtils, contnrs,
30 // LazUtils
31 LazConfigStorage, Laz2_XMLCfg, LazLoggerBase, LazUTF8,
32 // Codetools
33 FileProcs, KeywordFuncLists, CodeToolsCfgScript,
34 // IDE
35 LazarusIDEStrConsts;
36
37 const
38 BuildMatrixProjectName = '#project';
39 BuildMatrixIDEName = '#ide';
40 type
41 TBuildMatrixOptionType = (
42 bmotCustom, // append fpc parameters in Value
43 bmotOutDir, // override output directory -FU of target
44 bmotIDEMacro // MacroName and Value
45 );
46 TBuildMatrixOptionTypes = set of TBuildMatrixOptionType;
47
48 const
49 BuildMatrixOptionTypeNames: array[TBuildMatrixOptionType] of string = (
50 'Custom',
51 'OutDir',
52 'IDEMacro'
53 );
54
55 type
56 TBuildMatrixGroupType = (
57 bmgtEnvironment,
58 bmgtProject,
59 bmgtSession
60 );
61 TBuildMatrixGroupTypes = set of TBuildMatrixGroupType;
62 const
63 bmgtAll = [low(TBuildMatrixGroupType)..high(TBuildMatrixGroupType)];
64
65 type
onstnull66 TStrToBoolEvent = function(const Identifier: string): boolean of object;
67
68 TBuildMatrixOptions = class;
69
70 { TBuildMatrixOption }
71
72 TBuildMatrixOption = class(TPersistent)
73 private
74 FID: string;
75 FList: TBuildMatrixOptions;
76 FMacroName: string;
77 FModes: string;
78 FTargets: string;
79 FTyp: TBuildMatrixOptionType;
80 FValue: string;
81 procedure SetMacroName(AValue: string);
82 procedure SetModes(AValue: string);
83 procedure SetTargets(AValue: string);
84 procedure SetTyp(AValue: TBuildMatrixOptionType);
85 procedure SetValue(AValue: string);
86 public
87 procedure Assign(Source: TPersistent); override;
88 constructor Create(aList: TBuildMatrixOptions);
89 destructor Destroy; override;
FitsTargetnull90 function FitsTarget(const Target: string): boolean;
FitsModenull91 function FitsMode(const Mode: string): boolean;
92 property List: TBuildMatrixOptions read FList;
93 property ID: string read FID write FID;
94 property Targets: string read FTargets write SetTargets;
95 property Modes: string read FModes write SetModes; // modes separated by line breaks, case insensitive
96 property Typ: TBuildMatrixOptionType read FTyp write SetTyp;
97 property MacroName: string read FMacroName write SetMacroName;
98 property Value: string read FValue write SetValue;
Equalsnull99 function Equals(Obj: TObject): boolean; override;
GetModesSeparatedByCommanull100 function GetModesSeparatedByComma(const SaveModes: TStrToBoolEvent): string;
101 procedure SetModesFromCommaSeparatedList(aList: string);
102 procedure DisableModes(const DisableModeEvent: TStrToBoolEvent);
103 procedure EnableMode(aMode: string);
104 procedure RenameMode(const OldMode, NewMode: string);
105 procedure LoadFromConfig(Cfg: TConfigStorage);
106 procedure SaveToConfig(Cfg: TConfigStorage; const SaveModes: TStrToBoolEvent);
107 procedure LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string);
108 procedure SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string; const SaveModes: TStrToBoolEvent);
AsStringnull109 function AsString: string;
110 end;
111
112 { TBuildMatrixOptions }
113
114 TBuildMatrixOptions = class(TPersistent)
115 private
116 FChangeStep: int64;
117 fSavedChangeStep: int64;
118 fClearing: boolean;
119 fItems: TObjectList; // list of TBuildMatrixOption
120 FOnChanged: TNotifyEvent;
121 FOnChangesd: TNotifyEvent;
GetItemsnull122 function GetItems(Index: integer): TBuildMatrixOption;
GetModifiednull123 function GetModified: boolean;
124 procedure SetModified(AValue: boolean);
125 public
126 procedure Assign(Source: TPersistent); override;
127 constructor Create;
128 destructor Destroy; override;
129 procedure Clear;
Countnull130 function Count: integer;
131 property Items[Index: integer]: TBuildMatrixOption read GetItems; default;
IndexOfnull132 function IndexOf(Option: TBuildMatrixOption): integer;
Addnull133 function Add(Typ: TBuildMatrixOptionType = bmotCustom; Targets: string = '*'): TBuildMatrixOption;
134 procedure Delete(Index: integer);
135 procedure DisableModes(const IsModeEvent: TStrToBoolEvent);
136 procedure RenameMode(const OldMode, NewMode: string);
137
138 // equals, modified
139 property ChangeStep: int64 read FChangeStep;
140 procedure IncreaseChangeStep;
Equalsnull141 function Equals(Obj: TObject): boolean; override;
142 property OnChanged: TNotifyEvent read FOnChanged write FOnChangesd;
143 property Modified: boolean read GetModified write SetModified;
144
145 // load, save
146 procedure LoadFromConfig(Cfg: TConfigStorage);
147 procedure SaveToConfig(Cfg: TConfigStorage; const SaveMode: TStrToBoolEvent);
148 procedure LoadFromXMLConfig(Cfg: TXMLConfig; const aPath: string);
149 procedure SaveToXMLConfig(Cfg: TXMLConfig; const aPath: string;
150 const SaveMode: TStrToBoolEvent);
SaveAtOldXMLConfignull151 function SaveAtOldXMLConfig(Cfg: TXMLConfig; const Path, ModeIdent: string): integer;
152 procedure SaveSessionEnabled(Cfg: TXMLConfig; const Path, ModeIdent: string; var Cnt: integer);
153
154 // queries
155 procedure AppendCustomOptions(Target, ActiveMode: string; var Options: string);
156 procedure GetOutputDirectory(Target, ActiveMode: string; var OutDir: string);
FindOptionnull157 function FindOption(const ID: string): TBuildMatrixOption;
FindMacronull158 function FindMacro(const MacroName, MacroValue: string): TBuildMatrixOption;
159 procedure EnableModeIfOptionFound(ModeID, OptionID: String);
160 end;
161
162 EMMMacroSyntaxException = class(Exception)
163 end;
164
165
BuildMatrixTargetFitsnull166 function BuildMatrixTargetFits(Target, Targets: string): boolean;
BuildMatrixTargetFitsPatternnull167 function BuildMatrixTargetFitsPattern(Target, Pattern: PChar): boolean;
CheckBuildMatrixTargetsSyntaxnull168 function CheckBuildMatrixTargetsSyntax(const Targets: String): String;
BuildMatrixModeFitsnull169 function BuildMatrixModeFits(Mode, ModesSeparatedByLineBreaks: string): boolean;
Str2BuildMatrixOptionTypenull170 function Str2BuildMatrixOptionType(const s: string): TBuildMatrixOptionType;
CreateBuildMatrixOptionGUIDnull171 function CreateBuildMatrixOptionGUID: string;
172
SplitMatrixMacronull173 function SplitMatrixMacro(MacroAssignment: string;
174 out MacroName, MacroValue: string; ExceptionOnError: boolean): boolean;
175 procedure ApplyBuildMatrixMacros(Options: TBuildMatrixOptions; Target, ActiveMode: string;
176 CfgVars: TCTCfgScriptVariables);
177
178 implementation
179
BuildMatrixTargetFitsnull180 function BuildMatrixTargetFits(Target, Targets: string): boolean;
181 { case insensitive
182 * = all
183 a = fits a and A
184 a* = fits all starting with a
185 a? = fits all two letter names starting with a
186
187 Comma and minus:
188 Fits if there is at least one positive match and no negative match
189 a,b = fits a or b
190 -a = if target is a, stop immediately with 'false'
191 -ab,a* = fits all beginning with a except for ab
192 a*,-ab = fits all beginning with a, the -ab is ignored
193 }
194 var
195 p: PChar;
196 Negated: Boolean;
197 begin
198 Result:=false;
199 if (Targets='') or (Target='') then exit;
200 p:=PChar(Targets);
201 repeat
202 if p^='-' then begin
203 Negated:=true;
204 inc(p);
205 end else
206 Negated:=false;
207 if BuildMatrixTargetFitsPattern(PChar(Target),p) then begin
208 if Negated then begin
209 exit(false);
210 end else begin
211 Result:=true;
212 end;
213 end;
214 while not (p^ in [',',#0]) do
215 inc(p);
216 while p^=',' do
217 inc(p);
218 until p^=#0;
219 end;
220
BuildMatrixTargetFitsPatternnull221 function BuildMatrixTargetFitsPattern(Target, Pattern: PChar): boolean;
222 // Pattern ends at #0 or comma
223 // ? means one arbitrary character
224 // * means any arbitrary characters, even none
225 begin
226 Result:=false;
227 if (Target=nil) or (Target^=#0) or (Pattern=nil) or (Pattern^ in [#0,',']) then
228 exit;
229 repeat
230 case Pattern^ of
231 #0,',':
232 begin
233 // end of pattern reached
234 Result:=Target^=#0;
235 exit;
236 end;
237 '?':
238 begin
239 // one arbitrary character
240 if Target^=#0 then
241 exit;
242 inc(Pattern);
243 inc(Target);
244 end;
245 '*':
246 begin
247 repeat
248 inc(Pattern);
249 until Pattern^<>'*';
250 if Pattern^ in [#0,','] then
251 exit(true);
252 // behind the * comes a none * => check recursively all combinations
253 while Target^<>#0 do begin
254 if BuildMatrixTargetFitsPattern(Target,Pattern) then
255 exit(true);
256 inc(Target);
257 end;
258 exit;
259 end;
260 'a'..'z','A'..'Z':
261 begin
262 if UpChars[Pattern^]<>UpChars[Target^] then
263 exit;
264 inc(Pattern);
265 inc(Target)
266 end;
267 else
268 if Pattern^<>Target^ then
269 exit;
270 inc(Pattern);
271 inc(Target);
272 end;
273 until false;
274 end;
275
CheckBuildMatrixTargetsSyntaxnull276 function CheckBuildMatrixTargetsSyntax(const Targets: String): String;
277 var
278 p: PChar;
279
280 procedure WarnInvalidChar;
281 begin
282 Result:=Format(lisMMInvalidCharacterAt, [dbgstr(p^), IntToStr(p-PChar(
283 Targets)+1)]);
284 end;
285
286 begin
287 Result:='';
288 if Targets='' then exit;
289 p:=PChar(Targets);
290 repeat
291 case p^ of
292 #0:
293 if p-PChar(Targets)=length(Targets) then
294 break
295 else begin
296 WarnInvalidChar;
297 exit;
298 end;
299 #1..#32,#127:
300 begin
301 WarnInvalidChar;
302 exit;
303 end;
304 end;
305 inc(p);
306 until false;
307 end;
308
BuildMatrixModeFitsnull309 function BuildMatrixModeFits(Mode, ModesSeparatedByLineBreaks: string): boolean;
310 var
311 p: PChar;
312 m: PChar;
313 begin
314 Result:=false;
315 if Mode='' then exit;
316 if ModesSeparatedByLineBreaks='' then exit;
317 p:=PChar(ModesSeparatedByLineBreaks);
318 while p^<>#0 do begin
319 while p^ in [#1..#31] do inc(p);
320 m:=PChar(Mode);
321 while (UpChars[p^]=UpChars[m^]) and (p^>=' ') do begin
322 inc(p);
323 inc(m);
324 end;
325 if (m^=#0) and (p^ in [#10,#13,#0]) then
326 exit(true);
327 while p^>=' ' do inc(p);
328 end;
329 end;
330
Str2BuildMatrixOptionTypenull331 function Str2BuildMatrixOptionType(const s: string): TBuildMatrixOptionType;
332 begin
333 for Result:=low(TBuildMatrixOptionType) to high(TBuildMatrixOptionType) do
334 if SysUtils.CompareText(BuildMatrixOptionTypeNames[Result],s)=0 then exit;
335 Result:=bmotCustom;
336 end;
337
CreateBuildMatrixOptionGUIDnull338 function CreateBuildMatrixOptionGUID: string;
339 var
340 i: Integer;
341 begin
342 SetLength(Result,12);
343 for i:=1 to length(Result) do
344 Result[i]:=chr(ord('0')+random(10));
345 end;
346
SplitMatrixMacronull347 function SplitMatrixMacro(MacroAssignment: string; out MacroName,
348 MacroValue: string; ExceptionOnError: boolean): boolean;
349
350 procedure E(Msg: string);
351 begin
352 raise EMMMacroSyntaxException.Create(Msg);
353 end;
354
355 var
356 p: PChar;
357 StartP: PChar;
358 begin
359 Result:=false;
360 MacroName:='';
361 MacroValue:='';
362 if MacroAssignment='' then begin
363 if ExceptionOnError then
364 E(lisMMMissingMacroName);
365 exit;
366 end;
367 p:=PChar(MacroAssignment);
368 if not IsIdentStartChar[p^] then begin
369 if ExceptionOnError then
370 E(Format(lisMMExpectedMacroNameButFound, [dbgstr(p^)]));
371 exit;
372 end;
373 StartP:=p;
374 repeat
375 inc(p);
376 until not IsIdentChar[p^];
377 MacroName:=copy(MacroAssignment,1,p-StartP);
378 if (p^<>':') or (p[1]<>'=') then begin
379 if ExceptionOnError then
380 E(Format(lisMMExpectedAfterMacroNameButFound, [dbgstr(p^)]));
381 exit;
382 end;
383 inc(p,2);
384 StartP:=p;
385 repeat
386 if (p^=#0) and (p-PChar(MacroAssignment)=length(MacroAssignment)) then break;
387 if p^ in [#0..#31,#127] then begin
388 if ExceptionOnError then
389 E(Format(lisMMInvalidCharacterInMacroValue, [dbgstr(p^)]));
390 exit;
391 end;
392 inc(p);
393 until false;
394 MacroValue:=copy(MacroAssignment,StartP-PChar(MacroAssignment)+1,p-StartP);
395 Result:=true;
396 end;
397
398 procedure ApplyBuildMatrixMacros(Options: TBuildMatrixOptions;
399 Target, ActiveMode: string; CfgVars: TCTCfgScriptVariables);
400 var
401 i: Integer;
402 Option: TBuildMatrixOption;
403 begin
404 if (Options=nil) or (CfgVars=nil) then exit;
405 for i:=0 to Options.Count-1 do begin
406 Option:=Options[i];
407 if Option.Typ<>bmotIDEMacro then continue;
408 if not Option.FitsMode(ActiveMode) then continue;
409 if not Option.FitsTarget(Target) then continue;
410 //debugln(['ApplyBuildMatrixMacros Option.MacroName="',Option.MacroName,'" Value="',Option.Value,'"']);
411 CfgVars.Values[Option.MacroName]:=Option.Value;
412 end;
413 end;
414
415 { TBuildMatrixOptions }
416
GetItemsnull417 function TBuildMatrixOptions.GetItems(Index: integer): TBuildMatrixOption;
418 begin
419 Result:=TBuildMatrixOption(fItems[Index]);
420 end;
421
GetModifiednull422 function TBuildMatrixOptions.GetModified: boolean;
423 begin
424 Result:=fSavedChangeStep<>FChangeStep;
425 end;
426
427 procedure TBuildMatrixOptions.SetModified(AValue: boolean);
428 begin
429 if AValue then
430 IncreaseChangeStep
431 else
432 fSavedChangeStep:=FChangeStep;
433 end;
434
435 procedure TBuildMatrixOptions.Assign(Source: TPersistent);
436 var
437 aSource: TBuildMatrixOptions;
438 i: Integer;
439 Item: TBuildMatrixOption;
440 begin
441 if Source is TBuildMatrixOptions then
442 begin
443 aSource:=TBuildMatrixOptions(Source);
444 Clear;
445 for i:=0 to aSource.Count-1 do begin
446 Item:=TBuildMatrixOption.Create(Self);
447 Item.Assign(aSource[i]);
448 end;
449 end else
450 inherited Assign(Source);
451 end;
452
453 constructor TBuildMatrixOptions.Create;
454 begin
455 FChangeStep:=CTInvalidChangeStamp64;
456 fItems:=TObjectList.create(true);
457 end;
458
459 destructor TBuildMatrixOptions.Destroy;
460 begin
461 Clear;
462 FreeAndNil(fItems);
463 inherited Destroy;
464 end;
465
466 procedure TBuildMatrixOptions.Clear;
467 begin
468 if fItems.Count=0 then exit;
469 fClearing:=true;
470 fItems.Clear;
471 fClearing:=false;
472 IncreaseChangeStep;
473 end;
474
475 procedure TBuildMatrixOptions.DisableModes(const IsModeEvent: TStrToBoolEvent);
476 var
477 i: Integer;
478 begin
479 for i:=0 to Count-1 do
480 Items[i].DisableModes(IsModeEvent);
481 end;
482
483 procedure TBuildMatrixOptions.RenameMode(const OldMode, NewMode: string);
484 var
485 i: Integer;
486 begin
487 for i:=0 to Count-1 do
488 Items[i].RenameMode(OldMode,NewMode);
489 end;
490
TBuildMatrixOptions.Countnull491 function TBuildMatrixOptions.Count: integer;
492 begin
493 Result:=fItems.Count;
494 end;
495
TBuildMatrixOptions.IndexOfnull496 function TBuildMatrixOptions.IndexOf(Option: TBuildMatrixOption): integer;
497 begin
498 Result:=fItems.IndexOf(Option);
499 end;
500
Addnull501 function TBuildMatrixOptions.Add(Typ: TBuildMatrixOptionType; Targets: string
502 ): TBuildMatrixOption;
503 begin
504 Result:=TBuildMatrixOption.Create(Self);
505 Result.Targets:=Targets;
506 Result.Typ:=Typ;
507 end;
508
509 procedure TBuildMatrixOptions.Delete(Index: integer);
510 begin
511 Items[Index].Free;
512 end;
513
514 procedure TBuildMatrixOptions.IncreaseChangeStep;
515 begin
516 CTIncreaseChangeStamp64(FChangeStep);
517 if Assigned(OnChanged) then
518 OnChanged(Self);
519 end;
520
Equalsnull521 function TBuildMatrixOptions.Equals(Obj: TObject): boolean;
522 var
523 Src: TBuildMatrixOptions;
524 i: Integer;
525 begin
526 Result:=false;
527 if Self=Obj then exit;
528 if not (Obj is TBuildMatrixOptions) then exit;
529 Src:=TBuildMatrixOptions(Obj);
530 if Src.Count<>Count then exit;
531 for i:=0 to Count-1 do
532 if not Src[i].Equals(Items[i]) then exit;
533 Result:=true;
534 end;
535
536 procedure TBuildMatrixOptions.LoadFromConfig(Cfg: TConfigStorage);
537 var
538 Cnt: Integer;
539 i: Integer;
540 Option: TBuildMatrixOption;
541 begin
542 Clear;
543 Cnt:=Cfg.GetValue('Count',0);
544 for i:=1 to Cnt do begin
545 Option:=TBuildMatrixOption.Create(Self);
546 Cfg.AppendBasePath('Item'+IntToStr(i));
547 Option.LoadFromConfig(Cfg);
548 Cfg.UndoAppendBasePath;
549 end;
550 end;
551
552 procedure TBuildMatrixOptions.SaveToConfig(Cfg: TConfigStorage;
553 const SaveMode: TStrToBoolEvent);
554 var
555 i: Integer;
556 begin
557 Cfg.SetDeleteValue('Count',Count,0);
558 for i:=0 to Count-1 do begin
559 Cfg.AppendBasePath('Item'+IntToStr(i+1));
560 Items[i].SaveToConfig(Cfg,SaveMode);
561 Cfg.UndoAppendBasePath;
562 end;
563 end;
564
565 procedure TBuildMatrixOptions.LoadFromXMLConfig(Cfg: TXMLConfig;
566 const aPath: string);
567 var
568 Cnt: Integer;
569 i: Integer;
570 Option: TBuildMatrixOption;
571 begin
572 Clear;
573 Cnt:=Cfg.GetValue(aPath+'Count',0);
574 //debugln(['TBuildMatrixOptions.LoadFromXMLConfig Cnt=',Cnt]);
575 for i:=1 to Cnt do begin
576 Option:=TBuildMatrixOption.Create(Self);
577 Option.LoadFromXMLConfig(Cfg,aPath+'Item'+IntToStr(i)+'/');
578 end;
579 //debugln(['TBuildMatrixOptions.LoadFromXMLConfig Count=',Count]);
580 end;
581
582 procedure TBuildMatrixOptions.SaveToXMLConfig(Cfg: TXMLConfig;
583 const aPath: string; const SaveMode: TStrToBoolEvent);
584 var
585 i: Integer;
586 begin
587 //debugln(['TBuildMatrixOptions.SaveToXMLConfig ',aPath]);
588 Cfg.SetDeleteValue(aPath+'Count',Count,0);
589 for i:=0 to Count-1 do
590 Items[i].SaveToXMLConfig(Cfg,aPath+'Item'+IntToStr(i+1)+'/',SaveMode);
591 end;
592
SaveAtOldXMLConfignull593 function TBuildMatrixOptions.SaveAtOldXMLConfig(Cfg: TXMLConfig;
594 const Path, ModeIdent: string): integer;
595 var
596 i: Integer;
597 MatrixOption: TBuildMatrixOption;
598 SubPath: String;
599 begin
600 Result:=0;
601 for i:=0 to Count-1 do
602 begin
603 MatrixOption:=Items[i];
604 if (MatrixOption.Typ=bmotIDEMacro)
605 and MatrixOption.FitsTarget(BuildMatrixProjectName)
606 and MatrixOption.FitsMode(ModeIdent) then
607 begin
608 inc(Result);
609 SubPath:=Path+'Macro'+IntToStr(i+1)+'/';
610 Cfg.SetDeleteValue(SubPath+'Name',MatrixOption.MacroName,'');
611 Cfg.SetDeleteValue(SubPath+'Value',MatrixOption.Value,'');
612 end;
613 end;
614 end;
615
616 procedure TBuildMatrixOptions.SaveSessionEnabled(Cfg: TXMLConfig;
617 const Path, ModeIdent: string; var Cnt: integer);
618 var
619 MatrixOption: TBuildMatrixOption;
620 SubPath: String;
621 i: Integer;
622 begin
623 for i:=0 to Count-1 do begin
624 MatrixOption:=Items[i];
625 //debugln(['SaveSessionEnabled ',MatrixOption.AsString]);
626 if not MatrixOption.FitsMode(ModeIdent) then continue;
627 inc(Cnt);
628 SubPath:=Path+'Item'+IntToStr(Cnt)+'/';
629 //debugln(['SaveSessionEnabled ModeID="',CurMode.Identifier,'" OptionID="',MatrixOption.ID,'" ',MatrixOption.AsString]);
630 Cfg.SetDeleteValue(SubPath+'Mode',ModeIdent,'');
631 Cfg.SetDeleteValue(SubPath+'Option',MatrixOption.ID,'');
632 end;
633 end;
634
635 procedure TBuildMatrixOptions.AppendCustomOptions(Target, ActiveMode: string;
636 var Options: string);
637 var
638 i: Integer;
639 Option: TBuildMatrixOption;
640 Value: String;
641 begin
642 for i:=0 to Count-1 do begin
643 Option:=Items[i];
644 if Option.Typ<>bmotCustom then continue;
645 Value:=Trim(Option.Value);
646 if Value='' then continue;
647 if not Option.FitsTarget(Target) then continue;
648 if not Option.FitsMode(ActiveMode) then continue;
649 if Options<>'' then Options+=' ';
650 Options+=Value;
651 end;
652 end;
653
654 procedure TBuildMatrixOptions.GetOutputDirectory(Target, ActiveMode: string;
655 var OutDir: string);
656 var
657 i: Integer;
658 Option: TBuildMatrixOption;
659 begin
660 for i:=0 to Count-1 do begin
661 Option:=Items[i];
662 if Option.Typ<>bmotOutDir then continue;
663 if not Option.FitsTarget(Target) then continue;
664 if not Option.FitsMode(ActiveMode) then continue;
665 OutDir:=Option.Value;
666 end;
667 end;
668
TBuildMatrixOptions.FindOptionnull669 function TBuildMatrixOptions.FindOption(const ID: string): TBuildMatrixOption;
670 var
671 i: Integer;
672 begin
673 for i:=0 to Count-1 do begin
674 Result:=Items[i];
675 if Result.ID=ID then exit;
676 end;
677 Result:=nil;
678 end;
679
TBuildMatrixOptions.FindMacronull680 function TBuildMatrixOptions.FindMacro(const MacroName, MacroValue: string): TBuildMatrixOption;
681 var
682 i: Integer;
683 begin
684 i:=Count-1;
685 while i>=0 do
686 begin
687 Result:=Items[i];
688 if (Result.Typ=bmotIDEMacro)
689 and (Result.Targets='*')
690 and (Result.MacroName=MacroName)
691 and (Result.Value=MacroValue)
692 then
693 exit;
694 dec(i);
695 end;
696 Result:=nil;
697 end;
698
699 procedure TBuildMatrixOptions.EnableModeIfOptionFound(ModeID, OptionID: String);
700 var
701 Opt: TBuildMatrixOption;
702 begin
703 Opt:=FindOption(OptionID);
704 if Assigned(Opt) then
705 Opt.EnableMode(ModeID);
706 end;
707
708 { TBuildMatrixOption }
709
710 procedure TBuildMatrixOption.SetMacroName(AValue: string);
711 begin
712 if FMacroName=AValue then Exit;
713 FMacroName:=AValue;
714 List.IncreaseChangeStep;
715 end;
716
717 procedure TBuildMatrixOption.SetModes(AValue: string);
718 begin
719 if FModes=AValue then exit;
720 FModes:=AValue;
721 List.IncreaseChangeStep;
722 end;
723
724 procedure TBuildMatrixOption.SetTargets(AValue: string);
725 begin
726 if FTargets=AValue then Exit;
727 FTargets:=AValue;
728 List.IncreaseChangeStep;
729 end;
730
731 procedure TBuildMatrixOption.SetTyp(AValue: TBuildMatrixOptionType);
732 begin
733 if FTyp=AValue then Exit;
734 FTyp:=AValue;
735 List.IncreaseChangeStep;
736 end;
737
738 procedure TBuildMatrixOption.SetValue(AValue: string);
739 begin
740 if FValue=AValue then Exit;
741 FValue:=AValue;
742 List.IncreaseChangeStep;
743 end;
744
745 procedure TBuildMatrixOption.Assign(Source: TPersistent);
746 var
747 aSource: TBuildMatrixOption;
748 begin
749 if Source is TBuildMatrixOption then
750 begin
751 aSource:=TBuildMatrixOption(Source);
752 ID:=aSource.ID;
753 Targets:=aSource.Targets;
754 Modes:=aSource.Modes;
755 Typ:=aSource.Typ;
756 MacroName:=aSource.MacroName;
757 Value:=aSource.Value;
758 end else
759 inherited Assign(Source);
760 end;
761
762 constructor TBuildMatrixOption.Create(aList: TBuildMatrixOptions);
763 begin
764 FID:=CreateBuildMatrixOptionGUID;
765 FList:=aList;
766 if List<>nil then
767 List.fItems.Add(Self);
768 end;
769
770 destructor TBuildMatrixOption.Destroy;
771 begin
772 List.fItems.Remove(Self);
773 FList:=nil;
774 inherited Destroy;
775 end;
776
FitsTargetnull777 function TBuildMatrixOption.FitsTarget(const Target: string): boolean;
778 begin
779 Result:=BuildMatrixTargetFits(Target,Targets);
780 end;
781
TBuildMatrixOption.FitsModenull782 function TBuildMatrixOption.FitsMode(const Mode: string): boolean;
783 begin
784 Result:=BuildMatrixModeFits(Mode,Modes);
785 end;
786
TBuildMatrixOption.Equalsnull787 function TBuildMatrixOption.Equals(Obj: TObject): boolean;
788 var
789 Src: TBuildMatrixOption;
790 begin
791 Result:=false;
792 if Obj=Self then exit;
793 if not (Obj is TBuildMatrixOption) then exit;
794 Src:=TBuildMatrixOption(Obj);
795 if Src.Targets<>Targets then exit;
796 if Src.Modes<>Modes then exit;
797 if Src.Typ<>Typ then exit;
798 if Src.MacroName<>MacroName then exit;
799 if Src.Value<>Value then exit;
800 Result:=true;
801 end;
802
GetModesSeparatedByCommanull803 function TBuildMatrixOption.GetModesSeparatedByComma(
804 const SaveModes: TStrToBoolEvent): string;
805 var
806 p, StartP: PChar;
807 l: SizeInt;
808 CurMode: string;
809 i: Integer;
810 begin
811 Result:='';
812 if Modes='' then exit;
813 p:=PChar(Modes);
814 while p^<>#0 do begin
815 StartP:=p;
816 while not (p^ in [#0,#10,#13]) do inc(p);
817 l:=p-StartP;
818 while p^ in [#10,#13] do inc(p);
819 if l=0 then continue; // skip empty strings
820 SetLength(CurMode,l);
821 System.Move(StartP^,CurMode[1],l);
822 if Assigned(SaveModes) and not SaveModes(CurMode) then continue;
823 // convert a single comma to double comma
824 for i:=length(CurMode) downto 1 do
825 if CurMode[i]=',' then
826 System.Insert(',',CurMode,i);
827 if Result<>'' then
828 Result+=',';
829 Result+=CurMode;
830 end;
831 //debugln(['TBuildMatrixOption.GetModesSeparatedByComma ',dbgstr(Modes),' -> ',dbgstr(Result)]);
832 end;
833
834 procedure TBuildMatrixOption.SetModesFromCommaSeparatedList(aList: string);
835 var
836 p: Integer;
837 begin
838 //debugln(['TBuildMatrixOption.SetModesFromCommaSeparatedList START aList=',aList]);
839 p:=1;
840 while p<=length(aList) do begin
841 if aList[p]=',' then begin
842 if (p<length(aList)) and (aList[p+1]=',') then begin
843 // double comma is normal character = single comma
844 system.Delete(aList,p,1);
845 inc(p);
846 end else begin
847 // single comma is separator
848 ReplaceSubstring(aList,p,1,LineEnding);
849 inc(p,length(LineEnding));
850 end;
851 end else begin
852 inc(p);
853 end;
854 end;
855 Modes:=aList;
856 //debugln(['TBuildMatrixOption.SetModesFromCommaSeparatedList END Modes=',dbgstr(Modes)]);
857 end;
858
859 procedure TBuildMatrixOption.DisableModes(const DisableModeEvent: TStrToBoolEvent);
860 var
861 CurModes: String;
862 p: PChar;
863 StartP: PChar;
864 CurMode: String;
865 StartPos: integer;
866 begin
867 CurModes:=Modes;
868 p:=PChar(CurModes);
869 while p^<>#0 do begin
870 StartP:=p;
871 while not (p^ in [#0,#10,#13]) do inc(p);
872 StartPos:=StartP-PChar(CurModes)+1;
873 CurMode:=copy(CurModes,StartPos,p-StartP);
874 while p^ in [#10,#13] do inc(p);
875 if DisableModeEvent(CurMode) then begin
876 System.Delete(CurModes,StartPos,p-StartP);
877 p:=Pointer(CurModes)+StartPos-1;
878 end;
879 end;
880 Modes:=CurModes;
881 end;
882
883 procedure TBuildMatrixOption.EnableMode(aMode: string);
884 begin
885 if FitsMode(aMode) then exit;
886 if Modes<>'' then
887 aMode:=LineEnding+aMode;
888 Modes:=Modes+aMode;
889 end;
890
891 procedure TBuildMatrixOption.RenameMode(const OldMode, NewMode: string);
892 var
893 CurModes: String;
894 p: PChar;
895 StartP: PChar;
896 StartPos: SizeInt;
897 CurMode: String;
898 begin
899 CurModes:=Modes;
900 p:=PChar(CurModes);
901 while p^<>#0 do begin
902 StartP:=p;
903 while not (p^ in [#0,#10,#13]) do inc(p);
904 StartPos:=StartP-PChar(CurModes)+1;
905 CurMode:=copy(CurModes,StartPos,p-StartP);
906 if CompareText(CurMode,OldMode)=0 then begin
907 ReplaceSubstring(CurModes,StartPos,p-StartP,NewMode);
908 p:=Pointer(CurModes)+StartPos-1+length(NewMode);
909 end;
910 while p^ in [#10,#13] do inc(p);
911 end;
912 Modes:=CurModes;
913 end;
914
915 procedure TBuildMatrixOption.LoadFromConfig(Cfg: TConfigStorage);
916 begin
917 ID:=Cfg.GetValue('ID','');
918 if ID='' then ID:=CreateBuildMatrixOptionGUID;
919 Targets:=Cfg.GetValue('Targets','*');
920 SetModesFromCommaSeparatedList(Cfg.GetValue('Modes',''));
921 Typ:=Str2BuildMatrixOptionType(Cfg.GetValue('Type',''));
922 MacroName:=Cfg.GetValue('MacroName','');
923 Value:=Cfg.GetValue('Value','');
924 end;
925
926 procedure TBuildMatrixOption.SaveToConfig(Cfg: TConfigStorage;
927 const SaveModes: TStrToBoolEvent);
928 begin
929 Cfg.SetDeleteValue('ID',ID,'');
930 Cfg.SetDeleteValue('Targets',Targets,'*');
931 Cfg.SetDeleteValue('Modes',GetModesSeparatedByComma(SaveModes),'');
932 Cfg.SetDeleteValue('Type',BuildMatrixOptionTypeNames[Typ],BuildMatrixOptionTypeNames[bmotCustom]);
933 Cfg.SetDeleteValue('MacroName',MacroName,'');
934 Cfg.SetDeleteValue('Value',Value,'');
935 end;
936
937 procedure TBuildMatrixOption.LoadFromXMLConfig(Cfg: TXMLConfig;
938 const aPath: string);
939 begin
940 ID:=Cfg.GetValue(aPath+'ID','');
941 if ID='' then ID:=CreateBuildMatrixOptionGUID;
942 Targets:=Cfg.GetValue(aPath+'Targets','*');
943 SetModesFromCommaSeparatedList(Cfg.GetValue(aPath+'Modes',''));
944 Typ:=Str2BuildMatrixOptionType(Cfg.GetValue(aPath+'Type',''));
945 MacroName:=Cfg.GetValue(aPath+'MacroName','');
946 Value:=Cfg.GetValue(aPath+'Value','');
947 end;
948
949 procedure TBuildMatrixOption.SaveToXMLConfig(Cfg: TXMLConfig;
950 const aPath: string; const SaveModes: TStrToBoolEvent);
951 begin
952 Cfg.SetDeleteValue(aPath+'ID',ID,'');
953 Cfg.SetDeleteValue(aPath+'Targets',Targets,'*');
954 Cfg.SetDeleteValue(aPath+'Modes',GetModesSeparatedByComma(SaveModes),'');
955 Cfg.SetDeleteValue(aPath+'Type',BuildMatrixOptionTypeNames[Typ],BuildMatrixOptionTypeNames[bmotCustom]);
956 Cfg.SetDeleteValue(aPath+'MacroName',MacroName,'');
957 Cfg.SetDeleteValue(aPath+'Value',Value,'');
958 end;
959
AsStringnull960 function TBuildMatrixOption.AsString: string;
961 begin
962 Result:='ID="'+ID+'" '+BuildMatrixOptionTypeNames[Typ]
963 +' Value="'+Value+'"'
964 +' Modes="'+dbgstr(Modes)+'"';
965 end;
966
967 end.
968
969