1 | unit UKConfig;
|
---|
2 |
|
---|
3 | // Kconfig format specification:
|
---|
4 | // https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
|
---|
5 |
|
---|
6 | {$mode Delphi}{$H+}
|
---|
7 |
|
---|
8 | interface
|
---|
9 |
|
---|
10 | uses
|
---|
11 | Classes, SysUtils, Contnrs, FileUtil, ComCtrls;
|
---|
12 |
|
---|
13 | type
|
---|
14 | TValueType = (vtNone, vtBool, vtTristate, vtString, vtInt, vtHex, vtChoice,
|
---|
15 | vtComment);
|
---|
16 |
|
---|
17 | TMenuNode = class;
|
---|
18 | TLoadTreeOption = (toShowSystem);
|
---|
19 | TLoadTreeOptions = set of TLoadTreeOption;
|
---|
20 | TObjectMove = record
|
---|
21 | Source: TObject;
|
---|
22 | NewParent: TObject;
|
---|
23 | end;
|
---|
24 | TObjectMoves = array of TObjectMove;
|
---|
25 |
|
---|
26 | TExpOperator = (eoAnd, eoOr);
|
---|
27 |
|
---|
28 | { TExpression }
|
---|
29 |
|
---|
30 | TExpression = class
|
---|
31 | ExpOperator: TExpOperator;
|
---|
32 | Items: TObjectList; // TList<TExpression>
|
---|
33 | Parent: TExpression;
|
---|
34 | function Show: String; virtual;
|
---|
35 | function CanBeTrue: Boolean; virtual;
|
---|
36 | procedure GetList(List: TStringList); virtual;
|
---|
37 | constructor Create; virtual;
|
---|
38 | destructor Destroy; override;
|
---|
39 | end;
|
---|
40 |
|
---|
41 | TCompareType = (ctNone, ctEqual, ctNotEqual);
|
---|
42 |
|
---|
43 | { TExpressionVar }
|
---|
44 |
|
---|
45 | TExpressionVar = class(TExpression)
|
---|
46 | Name: string;
|
---|
47 | //Node: TMenuNode;
|
---|
48 | Negative: Boolean;
|
---|
49 | Compare: TCompareType;
|
---|
50 | Value: string;
|
---|
51 | function CompareValue: Boolean;
|
---|
52 | function CanBeTrue: Boolean; override;
|
---|
53 | constructor Create; override;
|
---|
54 | procedure GetList(List: TStringList); override;
|
---|
55 | function Show: String; override;
|
---|
56 | end;
|
---|
57 |
|
---|
58 | { TMenuNode }
|
---|
59 |
|
---|
60 | TMenuNode = class
|
---|
61 | private
|
---|
62 | function GetVisible: Boolean;
|
---|
63 | public
|
---|
64 | ID: string;
|
---|
65 | Name: string;
|
---|
66 | DependsOn: TExpression;
|
---|
67 | Selects: TStringList;
|
---|
68 | Description: TStringList;
|
---|
69 | Items: TObjectList; // TList<TMenuNode>
|
---|
70 | Parent: TMenuNode;
|
---|
71 | //NewParent: TMenuNode;
|
---|
72 | DefaultValue: string;
|
---|
73 | ValueType: TValueType;
|
---|
74 | RangeMin: string;
|
---|
75 | RangeMax: string;
|
---|
76 | MenuConfig: Boolean;
|
---|
77 | Optional: Boolean;
|
---|
78 | constructor Create; virtual;
|
---|
79 | destructor Destroy; override;
|
---|
80 | procedure ChangeParent(NewParent: TMenuNode);
|
---|
81 | procedure AddLastToList(List: TObjectList);
|
---|
82 | function GetName: string; virtual;
|
---|
83 | function GetAbsoluteName: string; virtual;
|
---|
84 | procedure LoadTreeNode(Node: TTreeNode; Options: TLoadTreeOptions = []); virtual;
|
---|
85 | procedure LoadStats(List: TStrings); virtual;
|
---|
86 | procedure GetNodes(List: TStrings); virtual;
|
---|
87 | procedure Search(Text: string; List: TObjectList); virtual;
|
---|
88 | procedure SaveToList(List: TStrings); virtual;
|
---|
89 | function PrepareMoveList(Lookup: TStringList; var List: TObjectMoves): Boolean; virtual;
|
---|
90 | function GetCount: Integer; virtual;
|
---|
91 | function GetTopNode: TMenuNode; virtual;
|
---|
92 | function FindNode(ID: string): TMenuNode; virtual;
|
---|
93 | function CanBeVisible: Boolean;
|
---|
94 | property Visible: Boolean read GetVisible;
|
---|
95 | end;
|
---|
96 |
|
---|
97 | TOnLogEvent = procedure (Text: string) of object;
|
---|
98 |
|
---|
99 | { TConfigMenu }
|
---|
100 |
|
---|
101 | TConfigMenu = class
|
---|
102 | private
|
---|
103 | CurrentMenu: TMenuNode;
|
---|
104 | ConditionStack: TStringList;
|
---|
105 | FArch: string;
|
---|
106 | FOnLog: TOnLogEvent;
|
---|
107 | ParseFileName: string;
|
---|
108 | LineNumber: Integer;
|
---|
109 | function GetTopCondition: string;
|
---|
110 | procedure Log(Text: string);
|
---|
111 | function IsWhiteSpace(Character: Char): Boolean;
|
---|
112 | function IsAlpha(Character: Char): Boolean;
|
---|
113 | function IsAlphaNumeric(Character: Char): Boolean;
|
---|
114 | function IsNumeric(Character: Char): Boolean;
|
---|
115 | function IsIdentifier(Name: string): Boolean;
|
---|
116 | function IsSpecialSymbol(Character: Char): Boolean;
|
---|
117 | procedure Expect(var Text: string; Token: string);
|
---|
118 | function GetNextToken(var Text: string): string;
|
---|
119 | procedure ParseExpression(Node: TMenuNode; Line: string);
|
---|
120 | procedure ParseFile(FileName: string);
|
---|
121 | procedure ParseConfig;
|
---|
122 | procedure ParseMakeFile;
|
---|
123 | function GetLog: string;
|
---|
124 | procedure SetArch(AValue: string);
|
---|
125 | public
|
---|
126 | TopNode: TMenuNode;
|
---|
127 | BaseDir: string;
|
---|
128 | Version: string;
|
---|
129 | procedure OptionListNames(List: TStringList);
|
---|
130 | procedure PrepareMoveList(var List: TObjectMoves);
|
---|
131 | procedure CompareStringLists(List1, List2: TStringList; Missing1,
|
---|
132 | Missing2: TStrings);
|
---|
133 | procedure LoadFromDir(Dir: string);
|
---|
134 | property OnLog: TOnLogEvent read FOnLog write FOnLog;
|
---|
135 | constructor Create;
|
---|
136 | destructor Destroy; override;
|
---|
137 | property Arch: string read FArch write SetArch;
|
---|
138 | end;
|
---|
139 |
|
---|
140 | implementation
|
---|
141 |
|
---|
142 | { TExpressionVar }
|
---|
143 |
|
---|
144 | function TExpressionVar.CompareValue: Boolean;
|
---|
145 | begin
|
---|
146 |
|
---|
147 | end;
|
---|
148 |
|
---|
149 | function TExpressionVar.CanBeTrue: Boolean;
|
---|
150 | begin
|
---|
151 | if Compare = ctNone then begin
|
---|
152 |
|
---|
153 | end else
|
---|
154 | if Compare = ctEqual then begin
|
---|
155 | Result := Result and CompareValue;
|
---|
156 | end else
|
---|
157 | if Compare = ctNotEqual then begin
|
---|
158 | Result := Result and not CompareValue;
|
---|
159 | end;
|
---|
160 | // Result := Node.CanBeVisible;
|
---|
161 | end;
|
---|
162 |
|
---|
163 | constructor TExpressionVar.Create;
|
---|
164 | begin
|
---|
165 | inherited;
|
---|
166 | Compare := ctNone;
|
---|
167 | Value := '';
|
---|
168 | Negative := False;
|
---|
169 | Name := '';
|
---|
170 | end;
|
---|
171 |
|
---|
172 | procedure TExpressionVar.GetList(List: TStringList);
|
---|
173 | begin
|
---|
174 | inherited GetList(List);
|
---|
175 | List.Add(Name);
|
---|
176 | end;
|
---|
177 |
|
---|
178 | function TExpressionVar.Show: String;
|
---|
179 | begin
|
---|
180 | Result := Name;
|
---|
181 | if Negative then Result := '!' + Result;
|
---|
182 | if Compare = ctEqual then Result := Result + ' = ' + Value;
|
---|
183 | if Compare = ctNotEqual then Result := Result + ' != ' + Value;
|
---|
184 | end;
|
---|
185 |
|
---|
186 | { TExpression }
|
---|
187 |
|
---|
188 | function TExpression.Show: String;
|
---|
189 | var
|
---|
190 | Operand: string;
|
---|
191 | I: Integer;
|
---|
192 | begin
|
---|
193 | Result := '';
|
---|
194 | if ExpOperator = eoAnd then Operand := '&&';
|
---|
195 | if ExpOperator = eoOr then Operand := '||';
|
---|
196 | for I := 0 to Items.Count - 1 do begin
|
---|
197 | Result := Result + TExpression(Items[I]).Show;
|
---|
198 | if I < (Items.Count - 1) then Result := Result + ' ' + Operand + ' ';
|
---|
199 | end;
|
---|
200 | if Assigned(Parent) then Result := '(' + Result + ')';
|
---|
201 | end;
|
---|
202 |
|
---|
203 | function TExpression.CanBeTrue: Boolean;
|
---|
204 | var
|
---|
205 | I: Integer;
|
---|
206 | begin
|
---|
207 | if ExpOperator = eoAnd then begin
|
---|
208 | Result := True;
|
---|
209 | for I := 0 to Items.Count - 1 do
|
---|
210 | Result := Result and TExpression(Items[I]).CanBeTrue;
|
---|
211 | end else
|
---|
212 | if ExpOperator = eoOr then begin
|
---|
213 | Result := False;
|
---|
214 | for I := 0 to Items.Count - 1 do
|
---|
215 | Result := Result or TExpression(Items[I]).CanBeTrue;
|
---|
216 | end;
|
---|
217 | end;
|
---|
218 |
|
---|
219 | procedure TExpression.GetList(List: TStringList);
|
---|
220 | var
|
---|
221 | I: Integer;
|
---|
222 | begin
|
---|
223 | for I := 0 to Items.Count - 1 do
|
---|
224 | TExpression(Items[I]).GetList(List);
|
---|
225 | end;
|
---|
226 |
|
---|
227 | constructor TExpression.Create;
|
---|
228 | begin
|
---|
229 | Items := TObjectList.Create;
|
---|
230 | Parent := nil;
|
---|
231 | ExpOperator := eoAnd;
|
---|
232 | end;
|
---|
233 |
|
---|
234 | destructor TExpression.Destroy;
|
---|
235 | begin
|
---|
236 | Items.Free;
|
---|
237 | inherited Destroy;
|
---|
238 | end;
|
---|
239 |
|
---|
240 | { TMenuNode }
|
---|
241 |
|
---|
242 | function TMenuNode.GetVisible: Boolean;
|
---|
243 | var
|
---|
244 | I: Integer;
|
---|
245 | begin
|
---|
246 | Result := True;
|
---|
247 | //for I := 0 to Depends.Count - 1 do
|
---|
248 | //if Depends[I]
|
---|
249 | end;
|
---|
250 |
|
---|
251 | constructor TMenuNode.Create;
|
---|
252 | begin
|
---|
253 | Name := '';
|
---|
254 | ID := '';
|
---|
255 | Parent := nil;
|
---|
256 | DependsOn := TExpression.Create;
|
---|
257 | Description := TStringList.Create;
|
---|
258 | Selects := TStringList.Create;
|
---|
259 | Items := TObjectList.Create;
|
---|
260 | MenuConfig := False;
|
---|
261 | end;
|
---|
262 |
|
---|
263 | destructor TMenuNode.Destroy;
|
---|
264 | begin
|
---|
265 | DependsOn.Free;
|
---|
266 | Items.Free;
|
---|
267 | Description.Free;
|
---|
268 | Selects.Free;
|
---|
269 | inherited Destroy;
|
---|
270 | end;
|
---|
271 |
|
---|
272 | procedure TMenuNode.ChangeParent(NewParent: TMenuNode);
|
---|
273 | var
|
---|
274 | LastOwnState: Boolean;
|
---|
275 | begin
|
---|
276 | try
|
---|
277 | LastOwnState := Parent.Items.OwnsObjects;
|
---|
278 | Parent.Items.OwnsObjects := False;
|
---|
279 | Parent.Items.Remove(Self);
|
---|
280 | finally
|
---|
281 | Parent.Items.OwnsObjects := LastOwnState;
|
---|
282 | end;
|
---|
283 | Parent := NewParent;
|
---|
284 | NewParent.Items.Add(Self);
|
---|
285 | end;
|
---|
286 |
|
---|
287 | procedure TMenuNode.AddLastToList(List: TObjectList);
|
---|
288 | begin
|
---|
289 | List.Add(Self);
|
---|
290 | if Items.Count > 0 then begin
|
---|
291 | TMenuNode(Items.Last).AddLastToList(List);
|
---|
292 | end;
|
---|
293 | end;
|
---|
294 |
|
---|
295 | function TMenuNode.GetName: string;
|
---|
296 | begin
|
---|
297 | Result := Name;
|
---|
298 | if Result = '' then Result := ID;
|
---|
299 | end;
|
---|
300 |
|
---|
301 | function TMenuNode.GetAbsoluteName: string;
|
---|
302 | begin
|
---|
303 | if Assigned(Parent) and Assigned(Parent.Parent) then Result := Parent.GetAbsoluteName + ' - ';
|
---|
304 | Result := Result + GetName;
|
---|
305 | end;
|
---|
306 |
|
---|
307 | procedure TMenuNode.LoadTreeNode(Node: TTreeNode; Options: TLoadTreeOptions);
|
---|
308 | var
|
---|
309 | I: Integer;
|
---|
310 | NewNode: TTreeNode;
|
---|
311 | begin
|
---|
312 | for I := 0 to Items.Count - 1 do
|
---|
313 | with TMenuNode(Items[I]) do begin
|
---|
314 | if (Name <> '') or ((Name = '') and (toShowSystem in Options)) then begin
|
---|
315 | NewNode := Node.TreeNodes.AddChild(Node, GetName);
|
---|
316 | NewNode.Data := TMenuNode(Self.Items[I]);
|
---|
317 | LoadTreeNode(NewNode, Options);
|
---|
318 | end else LoadTreeNode(Node, Options);
|
---|
319 | end;
|
---|
320 | end;
|
---|
321 |
|
---|
322 | procedure TMenuNode.LoadStats(List: TStrings);
|
---|
323 | begin
|
---|
324 | with List do begin
|
---|
325 | Clear;
|
---|
326 | Add('ID: ' + ID);
|
---|
327 | Add('Name: ' + Name);
|
---|
328 | Add('Depends on: ' + DependsOn.Show);
|
---|
329 | Add('Selects: ' + Selects.Text);
|
---|
330 | Add('Description: ' + Description.Text);
|
---|
331 | Add('Value type: ' + IntToStr(Integer(ValueType)));
|
---|
332 | Add('Default value: ' + DefaultValue);
|
---|
333 | Add('Path: ' + GetAbsoluteName);
|
---|
334 | end;
|
---|
335 | end;
|
---|
336 |
|
---|
337 | procedure TMenuNode.GetNodes(List: TStrings);
|
---|
338 | var
|
---|
339 | I: Integer;
|
---|
340 | begin
|
---|
341 | if ID <> '' then List.AddObject(ID, Self);
|
---|
342 | for I := 0 to Items.Count - 1 do
|
---|
343 | with TMenuNode(Items[I]) do begin
|
---|
344 | GetNodes(List);
|
---|
345 | end;
|
---|
346 | end;
|
---|
347 |
|
---|
348 | procedure TMenuNode.Search(Text: string; List: TObjectList);
|
---|
349 | var
|
---|
350 | I: Integer;
|
---|
351 | begin
|
---|
352 | if (Pos(Text, ID) > 0) or (Pos(Text, Name) > 0) then List.Add(Self);
|
---|
353 | for I := 0 to Items.Count - 1 do
|
---|
354 | TMenuNode(Items[I]).Search(Text, List);
|
---|
355 | end;
|
---|
356 |
|
---|
357 | procedure TMenuNode.SaveToList(List: TStrings);
|
---|
358 | var
|
---|
359 | I: Integer;
|
---|
360 | begin
|
---|
361 | if ID <> '' then List.AddObject(ID, Self);
|
---|
362 | for I := 0 to Items.Count - 1 do
|
---|
363 | with TMenuNode(Items[I]) do begin
|
---|
364 | SaveToList(List);
|
---|
365 | end;
|
---|
366 | end;
|
---|
367 |
|
---|
368 | function TMenuNode.PrepareMoveList(Lookup: TStringList; var List: TObjectMoves): Boolean;
|
---|
369 | var
|
---|
370 | I: Integer;
|
---|
371 | J: Integer;
|
---|
372 | NewMove: TObjectMove;
|
---|
373 | Index: Integer;
|
---|
374 | LatestNode: TMenuNode;
|
---|
375 | CheckList: TObjectList;
|
---|
376 | DepList: TStringList;
|
---|
377 | begin
|
---|
378 | Result := False;
|
---|
379 | try
|
---|
380 | CheckList := TObjectList.Create;
|
---|
381 | CheckList.OwnsObjects := False;
|
---|
382 | DepList := TStringList.Create;
|
---|
383 | if Assigned(Parent) then begin
|
---|
384 | Index := Parent.Items.IndexOf(Self);
|
---|
385 | if Index = -1 then raise Exception.Create('Node not found in parent');
|
---|
386 | if Index >= 1 then TMenuNode(Parent.Items[Index - 1]).AddLastToList(CheckList);
|
---|
387 | DepList.Clear;
|
---|
388 | DependsOn.GetList(DepList);
|
---|
389 | for I := CheckList.Count - 1 downto 0 do begin
|
---|
390 | for J := 0 to DepList.Count - 1 do
|
---|
391 | if Trim(DepList[J]) <> '' then begin
|
---|
392 | if (DepList[J] = TMenuNode(CheckList[I]).ID) and (TMenuNode(CheckList[I]).ValueType <> vtChoice) then begin
|
---|
393 | ChangeParent(TMenuNode(CheckList[I]));
|
---|
394 | Result := True;
|
---|
395 | Break;
|
---|
396 | end;
|
---|
397 | end;
|
---|
398 | if Result then Break;
|
---|
399 | end;
|
---|
400 | end;
|
---|
401 | finally
|
---|
402 | DepList.Free;
|
---|
403 | CheckList.Free;
|
---|
404 | end;
|
---|
405 |
|
---|
406 | I := 0;
|
---|
407 | while I < Items.Count do
|
---|
408 | with TMenuNode(Items[I]) do begin
|
---|
409 | if not PrepareMoveList(Lookup, List) then Inc(I);
|
---|
410 | end;
|
---|
411 | end;
|
---|
412 |
|
---|
413 | function TMenuNode.GetCount: Integer;
|
---|
414 | var
|
---|
415 | I: Integer;
|
---|
416 | begin
|
---|
417 | Result := 1;
|
---|
418 | for I := 0 to Items.Count - 1 do
|
---|
419 | with TMenuNode(Items[I]) do begin
|
---|
420 | Result := Result + GetCount;
|
---|
421 | end;
|
---|
422 | end;
|
---|
423 |
|
---|
424 | function TMenuNode.GetTopNode: TMenuNode;
|
---|
425 | begin
|
---|
426 | if Assigned(Parent) then Result := Parent.GetTopNode
|
---|
427 | else Result := Self;
|
---|
428 | end;
|
---|
429 |
|
---|
430 | function TMenuNode.FindNode(ID: string): TMenuNode;
|
---|
431 | var
|
---|
432 | I: Integer;
|
---|
433 | begin
|
---|
434 | Result := nil;
|
---|
435 | if Self.ID = ID then Result := Self
|
---|
436 | else begin
|
---|
437 | I := 0;
|
---|
438 | while (I < Items.Count) do begin
|
---|
439 | Result := TMenuNode(Items[I]).FindNode(ID);
|
---|
440 | if Assigned(Result) then Break;
|
---|
441 | Inc(I);
|
---|
442 | end;
|
---|
443 | end;
|
---|
444 | end;
|
---|
445 |
|
---|
446 | function TMenuNode.CanBeVisible: Boolean;
|
---|
447 | begin
|
---|
448 | // TODO
|
---|
449 | // Check if it can be selected manually if manual option
|
---|
450 | // Check if it can be selected automatically by other option
|
---|
451 |
|
---|
452 | end;
|
---|
453 |
|
---|
454 | { TConfigMenu }
|
---|
455 |
|
---|
456 | function TConfigMenu.GetTopCondition: string;
|
---|
457 | begin
|
---|
458 | if ConditionStack.Count > 0 then
|
---|
459 | Result := ConditionStack[ConditionStack.Count - 1]
|
---|
460 | else Result := '';
|
---|
461 | end;
|
---|
462 |
|
---|
463 | procedure TConfigMenu.Log(Text: string);
|
---|
464 | begin
|
---|
465 | if Assigned(FOnLog) then FOnLog(Text);
|
---|
466 | end;
|
---|
467 |
|
---|
468 | function TConfigMenu.IsWhiteSpace(Character: Char): Boolean;
|
---|
469 | begin
|
---|
470 | Result := (Character >= #0) and (Character <= ' ');
|
---|
471 | end;
|
---|
472 |
|
---|
473 | function TConfigMenu.IsAlpha(Character: Char): Boolean;
|
---|
474 | begin
|
---|
475 | Result := ((Character >= 'a') and (Character <= 'z'))
|
---|
476 | or ((Character >= 'A') and (Character <= 'Z'));
|
---|
477 | end;
|
---|
478 |
|
---|
479 | function TConfigMenu.IsAlphaNumeric(Character: Char): Boolean;
|
---|
480 | begin
|
---|
481 | Result := IsAlpha(Character) or IsNumeric(Character);
|
---|
482 | end;
|
---|
483 |
|
---|
484 | function TConfigMenu.IsNumeric(Character: Char): Boolean;
|
---|
485 | begin
|
---|
486 | Result := (Character >= '0') and (Character <= '9');
|
---|
487 | end;
|
---|
488 |
|
---|
489 | function TConfigMenu.IsIdentifier(Name: string): Boolean;
|
---|
490 | var
|
---|
491 | I: Integer;
|
---|
492 | begin
|
---|
493 | Result := True;
|
---|
494 | for I := 1 to Length(Name) do
|
---|
495 | if not (IsAlphaNumeric(Name[I]) or (Name[I] = '_')) then begin
|
---|
496 | Result := False;
|
---|
497 | Break;
|
---|
498 | end;
|
---|
499 | end;
|
---|
500 |
|
---|
501 | function TConfigMenu.IsSpecialSymbol(Character: Char): Boolean;
|
---|
502 | begin
|
---|
503 | Result := (Character = '!') or (Character = '=') or (Character = '(') or
|
---|
504 | (Character = ')') or (Character = '-') or (Character = '|') or (Character = '&');
|
---|
505 | end;
|
---|
506 |
|
---|
507 | procedure TConfigMenu.Expect(var Text: string; Token: string);
|
---|
508 | begin
|
---|
509 | if GetNextToken(Text) <> Token then
|
---|
510 | raise Exception.Create('Expected "' + Token + '"');
|
---|
511 | end;
|
---|
512 |
|
---|
513 | function TConfigMenu.GetNextToken(var Text: string): string;
|
---|
514 | var
|
---|
515 | I: Integer;
|
---|
516 | Terminate: Boolean;
|
---|
517 | State: (stNormal, stWhiteSpace, stString, stSpecialSymbol, stIdent,
|
---|
518 | stString2);
|
---|
519 | begin
|
---|
520 | I := 1;
|
---|
521 | Terminate := False;
|
---|
522 | Result := '';
|
---|
523 | State := stNormal;
|
---|
524 | while (I <= Length(Text)) and not Terminate do begin
|
---|
525 | if State = stWhiteSpace then begin
|
---|
526 | if not IsWhiteSpace(Text[I]) then begin
|
---|
527 | State := stNormal;
|
---|
528 | Terminate := True;
|
---|
529 | end;
|
---|
530 | end else
|
---|
531 | if State = stString then begin
|
---|
532 | if Text[I] = '"' then begin
|
---|
533 | State := stNormal;
|
---|
534 | Terminate := True;
|
---|
535 | Inc(I);
|
---|
536 | end else Result := Result + Text[I];
|
---|
537 | end else
|
---|
538 | if State = stString2 then begin
|
---|
539 | if Text[I] = '''' then begin
|
---|
540 | State := stNormal;
|
---|
541 | Terminate := True;
|
---|
542 | Inc(I);
|
---|
543 | end else Result := Result + Text[I];
|
---|
544 | end else
|
---|
545 | if State = stSpecialSymbol then begin
|
---|
546 | if not IsSpecialSymbol(Text[I]) or (Result = '(') or (Result = ')') or
|
---|
547 | ((Result = '!') and (Text[I] <> '=')) or (Result = '||') or
|
---|
548 | (Result = '&&') then begin
|
---|
549 | State := stNormal;
|
---|
550 | Terminate := True;
|
---|
551 | end else Result := Result + Text[I];
|
---|
552 | end else
|
---|
553 | if State = stIdent then begin
|
---|
554 | if not (IsAlphanumeric(Text[I]) or (Text[I] = '_')) then begin
|
---|
555 | State := stNormal;
|
---|
556 | Terminate := True;
|
---|
557 | end else Result := Result + Text[I];
|
---|
558 | end else begin
|
---|
559 | if IsWhiteSpace(Text[I]) then State := stWhiteSpace
|
---|
560 | else if Text[I] = '"' then State := stString
|
---|
561 | else if Text[I] = '''' then State := stString2
|
---|
562 | else if Text[I] = '#' then begin
|
---|
563 | // Comment
|
---|
564 | Text := '';
|
---|
565 | Terminate := True;
|
---|
566 | end
|
---|
567 | else if IsSpecialSymbol(Text[I]) then begin
|
---|
568 | State := stSpecialSymbol;
|
---|
569 | Result := Result + Text[I];
|
---|
570 | end
|
---|
571 | else if IsAlphaNumeric(Text[I]) then begin
|
---|
572 | State := stIdent;
|
---|
573 | Result := Result + Text[I];
|
---|
574 | end
|
---|
575 | else Result := Result + Text[I];
|
---|
576 | end;
|
---|
577 | if not Terminate then Inc(I);
|
---|
578 | end;
|
---|
579 | Delete(Text, 1, I - 1);
|
---|
580 | end;
|
---|
581 |
|
---|
582 | procedure TConfigMenu.ParseExpression(Node: TMenuNode; Line: string);
|
---|
583 | var
|
---|
584 | Token: string;
|
---|
585 | Exp: TExpression;
|
---|
586 | ExpVar: TExpressionVar;
|
---|
587 | ExpNew: TExpression;
|
---|
588 | Neg: Boolean;
|
---|
589 | Compare: TCompareType;
|
---|
590 | begin
|
---|
591 | Line := Trim(Line);
|
---|
592 | Exp := Node.DependsOn;
|
---|
593 | Neg := False;
|
---|
594 | while Line <> '' do begin
|
---|
595 | Token := GetNextToken(Line);
|
---|
596 | if Token = '||' then begin
|
---|
597 | Exp.ExpOperator := eoOr;
|
---|
598 | end else
|
---|
599 | if Token = '&&' then begin
|
---|
600 | Exp.ExpOperator := eoAnd;
|
---|
601 | end else
|
---|
602 | if Token = '!' then begin
|
---|
603 | Neg := True;
|
---|
604 | Continue;
|
---|
605 | end else
|
---|
606 | if Token = '(' then begin
|
---|
607 | ExpNew := TExpression.Create;
|
---|
608 | ExpNew.Parent := Exp;
|
---|
609 | Exp.Items.Add(ExpNew);
|
---|
610 | Exp := ExpNew;
|
---|
611 | Neg := False;
|
---|
612 | end else
|
---|
613 | if Token = ')' then begin
|
---|
614 | if Assigned(Exp.Parent) then Exp := Exp.Parent
|
---|
615 | else raise Exception.Create('Cannot go to expression parent.' + GetLog);
|
---|
616 | Neg := False;
|
---|
617 | end else
|
---|
618 | if Token = '' then begin
|
---|
619 | // White space
|
---|
620 | end else
|
---|
621 | if Token = '=' then begin
|
---|
622 | ExpVar.Compare := ctEqual;
|
---|
623 | Token := GetNextToken(Line);
|
---|
624 | ExpVar.Value := Token;
|
---|
625 | Continue;
|
---|
626 | end else
|
---|
627 | if Token = '!=' then begin
|
---|
628 | ExpVar.Compare := ctNotEqual;
|
---|
629 | Token := GetNextToken(Line);
|
---|
630 | ExpVar.Value := Token;
|
---|
631 | Continue;
|
---|
632 | end else
|
---|
633 | if IsIdentifier(Token) then begin
|
---|
634 | ExpVar := TExpressionVar.Create;
|
---|
635 | ExpVar.Negative := Neg;
|
---|
636 | ExpVar.Name := Token;
|
---|
637 | ExpVar.Compare := Compare;
|
---|
638 | Exp.Items.Add(ExpVar);
|
---|
639 | Neg := False;
|
---|
640 | end else
|
---|
641 | raise Exception.Create('Unknown token "' + Token + '".' + GetLog);
|
---|
642 | end;
|
---|
643 |
|
---|
644 | {// Just try to load symbol list. Do not parse expression
|
---|
645 | while Trim(Line) <> '' do begin
|
---|
646 | Parameter := GetNextToken(Line);
|
---|
647 | if Copy(Parameter, 1, 1) = '!' then Delete(Parameter, 1, 1);
|
---|
648 | if Copy(Parameter, 1, 1) = '(' then Delete(Parameter, 1, 1);
|
---|
649 | if Copy(Parameter, Length(Parameter), 1) = ')' then Delete(Parameter, Length(Parameter), 1);
|
---|
650 | Parameter := Trim(Parameter);
|
---|
651 | if (Parameter <> '&&') and (Parameter <> '||') then
|
---|
652 | Node.Depends.Add(Parameter);
|
---|
653 | end;
|
---|
654 | }
|
---|
655 |
|
---|
656 | end;
|
---|
657 |
|
---|
658 | function TConfigMenu.GetLog: string;
|
---|
659 | begin
|
---|
660 | Result := ' ' + ParseFileName + ':' + IntToStr(LineNumber);
|
---|
661 | end;
|
---|
662 |
|
---|
663 | procedure TConfigMenu.SetArch(AValue: string);
|
---|
664 | begin
|
---|
665 | if FArch = AValue then Exit;
|
---|
666 | FArch := AValue;
|
---|
667 | LoadFromDir(BaseDir);
|
---|
668 | end;
|
---|
669 |
|
---|
670 | procedure TConfigMenu.ParseFile(FileName: string);
|
---|
671 | var
|
---|
672 | Content: TStringList;
|
---|
673 | I: Integer;
|
---|
674 | J: Integer;
|
---|
675 | Command: string;
|
---|
676 | Parameter: string;
|
---|
677 | Line: string;
|
---|
678 | State: (stNormal, stConfig, stHelp, stHelpStart);
|
---|
679 | NewItem: TMenuNode;
|
---|
680 | NewMenu: TMenuNode;
|
---|
681 | MergedLines: string;
|
---|
682 | HelpIndent: Integer;
|
---|
683 | LineIndent: Integer;
|
---|
684 | NewExp: TExpressionVar;
|
---|
685 | const
|
---|
686 | TabSize = 8;
|
---|
687 | begin
|
---|
688 | ParseFileName := FileName;
|
---|
689 | Log('FILE ' + FileName);
|
---|
690 | try
|
---|
691 | Content := TStringList.Create;
|
---|
692 | Content.LoadFromFile(FileName);
|
---|
693 | State := stNormal;
|
---|
694 | NewItem := nil;
|
---|
695 | MergedLines := '';
|
---|
696 | HelpIndent := 0;
|
---|
697 | for I := 0 to Content.Count - 1 do begin
|
---|
698 | LineNumber := I + 1;
|
---|
699 | Line := MergedLines + Content[I];
|
---|
700 | MergedLines := '';
|
---|
701 | LineIndent := 0;
|
---|
702 | J := 1;
|
---|
703 | while (J <= Length(Line)) and IsWhiteSpace(Line[J]) do begin
|
---|
704 | if Line[J] = #9 then LineIndent := (Trunc(LineIndent / TabSize) + 1) * TabSize
|
---|
705 | else Inc(LineIndent);
|
---|
706 | Inc(J);
|
---|
707 | end;
|
---|
708 | if (State = stHelp) and (Trim(Line) <> '') then begin
|
---|
709 | State := stHelpStart;
|
---|
710 | if LineIndent = 0 then State := stNormal;
|
---|
711 | HelpIndent := LineIndent;
|
---|
712 | if (State = stHelpStart) and (HelpIndent = 0) then
|
---|
713 | raise Exception.Create('Error during help parsing.' + GetLog);
|
---|
714 | end;
|
---|
715 | if (State = stHelpStart) and (Trim(Line) <> '') and (LineIndent < HelpIndent) then
|
---|
716 | State := stNormal;
|
---|
717 |
|
---|
718 | if (Copy(Trim(Line), 1, 1) = '#') or (Copy(Trim(Line), 1, 2) = '\#') then begin
|
---|
719 | // Skip comments
|
---|
720 | Continue;
|
---|
721 | end;
|
---|
722 | if Copy(TrimRight(Line), Length(Line), 1) = '\' then begin
|
---|
723 | // Merge lines
|
---|
724 | Line := TrimRight(Line);
|
---|
725 | Delete(Line, Length(Line), 1);
|
---|
726 | MergedLines := Line;
|
---|
727 | Continue;
|
---|
728 | end;
|
---|
729 | Line := Trim(Line);
|
---|
730 | if Line = '' then begin
|
---|
731 | // Skip empty non help lines
|
---|
732 | Continue;
|
---|
733 | end;
|
---|
734 | Command := GetNextToken(Line);
|
---|
735 | if (State = stHelp) or (State = stHelpStart) then begin
|
---|
736 | NewItem.Description.Add(Trim(Content[I]));
|
---|
737 | end else
|
---|
738 | if (Command = 'bool') or (Command = 'boolean') then begin
|
---|
739 | Expect(Line, '');
|
---|
740 | Parameter := GetNextToken(Line);
|
---|
741 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
742 | NewItem.ValueType := vtBool;
|
---|
743 | NewItem.Name := Parameter;
|
---|
744 | end else
|
---|
745 | if Command = 'def_bool' then begin
|
---|
746 | Expect(Line, '');
|
---|
747 | Parameter := GetNextToken(Line);
|
---|
748 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
749 | NewItem.DefaultValue := Parameter;
|
---|
750 | NewItem.ValueType := vtBool;
|
---|
751 | end else
|
---|
752 | if Command = 'tristate' then begin
|
---|
753 | Expect(Line, '');
|
---|
754 | Parameter := GetNextToken(Line);
|
---|
755 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
756 | NewItem.Name := Parameter;
|
---|
757 | NewItem.ValueType := vtTristate;
|
---|
758 | end else
|
---|
759 | if Command = 'def_tristate' then begin
|
---|
760 | Expect(Line, '');
|
---|
761 | Parameter := GetNextToken(Line);
|
---|
762 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
763 | NewItem.Name := Parameter;
|
---|
764 | end else
|
---|
765 | if Command = 'string' then begin
|
---|
766 | Expect(Line, '');
|
---|
767 | Parameter := GetNextToken(Line);
|
---|
768 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
769 | NewItem.Name := Parameter;
|
---|
770 | NewItem.ValueType := vtString;
|
---|
771 | end else
|
---|
772 | if Command = 'int' then begin
|
---|
773 | Expect(Line, '');
|
---|
774 | Parameter := GetNextToken(Line);
|
---|
775 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
776 | NewItem.Name := Parameter;
|
---|
777 | NewItem.ValueType := vtInt;
|
---|
778 | end else
|
---|
779 | if Command = 'hex' then begin
|
---|
780 | Expect(Line, '');
|
---|
781 | Parameter := GetNextToken(Line);
|
---|
782 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
783 | NewItem.Name := Parameter;
|
---|
784 | NewItem.ValueType := vtHex;
|
---|
785 | end else
|
---|
786 | if Command = 'range' then begin
|
---|
787 | Expect(Line, '');
|
---|
788 | Parameter := GetNextToken(Line);
|
---|
789 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
790 | NewItem.RangeMin := Parameter;
|
---|
791 | Parameter := GetNextToken(Line);
|
---|
792 | NewItem.RangeMax := Parameter;
|
---|
793 | end else
|
---|
794 | if Command = 'prompt' then begin
|
---|
795 | Expect(Line, '');
|
---|
796 | Parameter := GetNextToken(Line);
|
---|
797 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
798 | NewItem.Name := Parameter;
|
---|
799 | end else
|
---|
800 | if Command = 'default' then begin
|
---|
801 | Expect(Line, '');
|
---|
802 | Parameter := GetNextToken(Line);
|
---|
803 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
804 | NewItem.DefaultValue := Parameter;
|
---|
805 | end else
|
---|
806 | if Command = 'depends' then begin
|
---|
807 | Expect(Line, '');
|
---|
808 | Parameter := GetNextToken(Line);
|
---|
809 | if Parameter = 'on' then begin
|
---|
810 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
811 | ParseExpression(NewItem, Line);
|
---|
812 | end;
|
---|
813 | end else
|
---|
814 | if Command = 'select' then begin
|
---|
815 | Expect(Line, '');
|
---|
816 | Parameter := GetNextToken(Line);
|
---|
817 | if not Assigned(NewItem) then raise Exception.Create('Item not defined.' + GetLog);
|
---|
818 | NewItem.Selects.Add(Parameter);
|
---|
819 | end else
|
---|
820 | if Command = '---' then begin
|
---|
821 | Command := GetNextToken(Line);
|
---|
822 | if Command = 'help' then begin
|
---|
823 | Command := GetNextToken(Line);
|
---|
824 | if Command = '---' then begin
|
---|
825 | State := stHelp;
|
---|
826 | HelpIndent := LineIndent;
|
---|
827 | end;
|
---|
828 | end else
|
---|
829 | if Command = '' then begin
|
---|
830 | Command := GetNextToken(Line);
|
---|
831 | if Command = 'help' then begin
|
---|
832 | Expect(Line, '');
|
---|
833 | Command := GetNextToken(Line);
|
---|
834 | if Command = '---' then begin
|
---|
835 | State := stHelp;
|
---|
836 | HelpIndent := LineIndent;
|
---|
837 | end;
|
---|
838 | end;
|
---|
839 | end;
|
---|
840 | end else
|
---|
841 | if (Command = 'help') or (Command = '---help---') then begin
|
---|
842 | State := stHelp;
|
---|
843 | HelpIndent := LineIndent;
|
---|
844 | end else
|
---|
845 | if Command = 'option' then begin
|
---|
846 | Expect(Line, '');
|
---|
847 | Parameter := GetNextToken(Line);
|
---|
848 | end else
|
---|
849 | if (Command = 'config') or (Command = 'menuconfig') then begin
|
---|
850 | Expect(Line, '');
|
---|
851 | Parameter := GetNextToken(Line);
|
---|
852 | State := stConfig;
|
---|
853 | NewItem := TMenuNode.Create;
|
---|
854 | NewItem.Parent := CurrentMenu;
|
---|
855 | NewItem.ID := Parameter;
|
---|
856 | for J := 0 to ConditionStack.Count - 1 do
|
---|
857 | if ConditionStack[J] <> '' then
|
---|
858 | begin
|
---|
859 | NewExp := TExpressionVar.Create;
|
---|
860 | NewExp.Name := ConditionStack[J];
|
---|
861 | NewItem.DependsOn.Items.Add(NewExp);
|
---|
862 | end;
|
---|
863 | CurrentMenu.Items.Add(NewItem);
|
---|
864 | if Command = 'menuconfig' then NewItem.MenuConfig := True;
|
---|
865 | end else
|
---|
866 | if (Command = 'comment') then begin
|
---|
867 | Expect(Line, '');
|
---|
868 | Parameter := GetNextToken(Line);
|
---|
869 | NewItem := TMenuNode.Create;
|
---|
870 | NewItem.Parent := CurrentMenu;
|
---|
871 | NewItem.Name := Parameter;
|
---|
872 | for J := 0 to ConditionStack.Count - 1 do
|
---|
873 | if ConditionStack[J] <> '' then begin
|
---|
874 | NewExp := TExpressionVar.Create;
|
---|
875 | NewExp.Name := ConditionStack[J];
|
---|
876 | NewItem.DependsOn.Items.Add(NewExp);
|
---|
877 | end;
|
---|
878 | NewItem.ValueType := vtComment;
|
---|
879 | CurrentMenu.Items.Add(NewItem);
|
---|
880 | end else
|
---|
881 | if Command = 'source' then begin
|
---|
882 | Expect(Line, '');
|
---|
883 | Parameter := GetNextToken(Line);
|
---|
884 | if Pos('$SRCARCH', Parameter) > 0 then
|
---|
885 | Parameter := StringReplace(Parameter, '$SRCARCH', Arch, [rfReplaceAll]);
|
---|
886 | Parameter := BaseDir + DirectorySeparator + Parameter;
|
---|
887 | if FileExistsUTF8(Parameter) then
|
---|
888 | ParseFile(Parameter)
|
---|
889 | else raise Exception.Create('Source file "' + Parameter + '" not found.' + GetLog);
|
---|
890 | end else
|
---|
891 | if Command = 'choice' then begin
|
---|
892 | Expect(Line, '');
|
---|
893 | Parameter := GetNextToken(Line);
|
---|
894 | NewMenu := TMenuNode.Create;
|
---|
895 | NewMenu.ValueType := vtChoice;
|
---|
896 | NewMenu.Name := Parameter;
|
---|
897 | NewMenu.Parent := CurrentMenu;
|
---|
898 | for J := 0 to ConditionStack.Count - 1 do
|
---|
899 | if ConditionStack[J] <> '' then begin
|
---|
900 | NewExp := TExpressionVar.Create;
|
---|
901 | NewExp.Name := ConditionStack[J];
|
---|
902 | NewMenu.DependsOn.Items.Add(NewExp);
|
---|
903 | end;
|
---|
904 | ConditionStack.AddObject('', nil);
|
---|
905 | NewItem := NewMenu;
|
---|
906 | CurrentMenu.Items.Add(NewMenu);
|
---|
907 | CurrentMenu := NewMenu;
|
---|
908 | end else
|
---|
909 | if command = 'endchoice' then begin
|
---|
910 | if Assigned(CurrentMenu.Parent) then begin
|
---|
911 | ConditionStack.Delete(ConditionStack.Count - 1);
|
---|
912 | CurrentMenu := CurrentMenu.Parent;
|
---|
913 | end else raise Exception.Create('Can''t change menu level up.' + GetLog);
|
---|
914 | end else
|
---|
915 | if Command = 'mainmenu' then begin
|
---|
916 | Expect(Line, '');
|
---|
917 | Parameter := GetNextToken(Line);
|
---|
918 | Parameter := StringReplace(Parameter, '$ARCH', Arch, [rfReplaceAll]);
|
---|
919 | Parameter := StringReplace(Parameter, '$KERNELVERSION', Version, [rfReplaceAll]);
|
---|
920 | TopNode.Name := Parameter;
|
---|
921 | end else
|
---|
922 | if Command = 'menu' then begin
|
---|
923 | Expect(Line, '');
|
---|
924 | Parameter := GetNextToken(Line);
|
---|
925 | Log('MENU ' + Parameter + ' IN ' + CurrentMenu.GetAbsoluteName);
|
---|
926 | NewMenu := TMenuNode.Create;
|
---|
927 | NewMenu.Name := Parameter;
|
---|
928 | NewMenu.Parent := CurrentMenu;
|
---|
929 | for J := 0 to ConditionStack.Count - 1 do
|
---|
930 | if ConditionStack[J] <> '' then begin
|
---|
931 | NewExp := TExpressionVar.Create;
|
---|
932 | NewExp.Name := ConditionStack[J];
|
---|
933 | NewMenu.DependsOn.Items.Add(NewExp);
|
---|
934 | end;
|
---|
935 | ConditionStack.AddObject('', nil);
|
---|
936 | NewItem := NewMenu;
|
---|
937 | CurrentMenu.Items.Add(NewMenu);
|
---|
938 | CurrentMenu := NewMenu;
|
---|
939 | end else
|
---|
940 | if command = 'endmenu' then begin
|
---|
941 | Log('ENDMENU ' + CurrentMenu.GetAbsoluteName);
|
---|
942 | if Assigned(CurrentMenu.Parent) then begin
|
---|
943 | ConditionStack.Delete(ConditionStack.Count - 1);
|
---|
944 | CurrentMenu := CurrentMenu.Parent;
|
---|
945 | end else raise Exception.Create('Can''t change menu level up.' + GetLog);
|
---|
946 | end else
|
---|
947 | if Command = 'if' then begin
|
---|
948 | Expect(Line, '');
|
---|
949 | ConditionStack.AddObject(GetNextToken(Line), NewItem);
|
---|
950 | end else
|
---|
951 | if Command = 'visible' then begin
|
---|
952 | //VisibleCondition := GetNextToken(Line);
|
---|
953 | end else
|
---|
954 | if Command = 'optional' then begin
|
---|
955 | NewItem.Optional := True;
|
---|
956 | end else
|
---|
957 | if Command = 'endif' then begin
|
---|
958 | ConditionStack.Delete(ConditionStack.Count - 1);
|
---|
959 | end else
|
---|
960 | raise Exception.Create('Unknown command "' + Command + '".' + GetLog);
|
---|
961 | end;
|
---|
962 | finally
|
---|
963 | Content.Free;
|
---|
964 | end;
|
---|
965 | end;
|
---|
966 |
|
---|
967 | procedure TConfigMenu.ParseConfig;
|
---|
968 | begin
|
---|
969 | ConditionStack.Clear;
|
---|
970 | TopNode.Free;
|
---|
971 | TopNode := TMenuNode.Create;
|
---|
972 | TopNode.Name := 'Root';
|
---|
973 | CurrentMenu := TopNode;
|
---|
974 | ParseFile(BaseDir + DirectorySeparator + 'Kconfig');
|
---|
975 | end;
|
---|
976 |
|
---|
977 | procedure TConfigMenu.ParseMakeFile;
|
---|
978 | var
|
---|
979 | Content: TStringList;
|
---|
980 | I: Integer;
|
---|
981 | Line: string;
|
---|
982 | Token: string;
|
---|
983 | begin
|
---|
984 | try
|
---|
985 | Content := TStringList.Create;
|
---|
986 | Content.LoadFromFile(BaseDir + DirectorySeparator + 'Makefile');
|
---|
987 | for I := 0 to Content.Count - 1 do begin
|
---|
988 | Line := Trim(Content[I]);
|
---|
989 | Token := GetNextToken(Line);
|
---|
990 | if Token = 'VERSION' then begin
|
---|
991 | Line := Trim(Line);
|
---|
992 | Token := GetNextToken(Line);
|
---|
993 | if Token = '=' then
|
---|
994 | Version := Trim(Line);
|
---|
995 | end else
|
---|
996 | if Token = 'PATCHLEVEL' then begin
|
---|
997 | Line := Trim(Line);
|
---|
998 | Token := GetNextToken(Line);
|
---|
999 | if Token = '=' then
|
---|
1000 | Version := Version + '.' + Trim(Line);
|
---|
1001 | end else
|
---|
1002 | if Token = 'SUBLEVEL' then begin
|
---|
1003 | Line := Trim(Line);
|
---|
1004 | Token := GetNextToken(Line);
|
---|
1005 | if Token = '=' then
|
---|
1006 | Version := Version + '.' + Trim(Line);
|
---|
1007 | end;
|
---|
1008 | end;
|
---|
1009 | finally
|
---|
1010 | Content.Free;
|
---|
1011 | end;
|
---|
1012 | end;
|
---|
1013 |
|
---|
1014 | procedure TConfigMenu.OptionListNames(List: TStringList);
|
---|
1015 | var
|
---|
1016 | I: Integer;
|
---|
1017 | Node: TMenuNode;
|
---|
1018 | begin
|
---|
1019 | for I := 0 to List.Count - 1 do begin
|
---|
1020 | Node := TopNode.FindNode(List[I]);
|
---|
1021 | if Assigned(Node) then
|
---|
1022 | List[I] := '"' + Node.GetAbsoluteName + '";' + List[I];
|
---|
1023 | end;
|
---|
1024 | end;
|
---|
1025 |
|
---|
1026 | procedure TConfigMenu.PrepareMoveList(var List: TObjectMoves);
|
---|
1027 | var
|
---|
1028 | Lookup: TStringList;
|
---|
1029 | begin
|
---|
1030 | try
|
---|
1031 | Lookup := TStringList.Create;
|
---|
1032 | Lookup.OwnsObjects := False;
|
---|
1033 | TopNode.GetNodes(Lookup);
|
---|
1034 | Lookup.Sorted := True;
|
---|
1035 | TopNode.PrepareMoveList(Lookup, List);
|
---|
1036 | finally
|
---|
1037 | Lookup.Free;
|
---|
1038 | end;
|
---|
1039 | end;
|
---|
1040 |
|
---|
1041 | procedure TConfigMenu.CompareStringLists(List1, List2: TStringList;
|
---|
1042 | Missing1, Missing2: TStrings);
|
---|
1043 | var
|
---|
1044 | I: Integer;
|
---|
1045 | J: Integer;
|
---|
1046 | begin
|
---|
1047 | List1.Sort;
|
---|
1048 | List2.Sort;
|
---|
1049 | I := 0;
|
---|
1050 | J := 0;
|
---|
1051 | while (I < List1.Count) and (J < List2.Count) do
|
---|
1052 | begin
|
---|
1053 | if List1[I] < List2[J] then
|
---|
1054 | begin
|
---|
1055 | Missing2.Add(List1[I]);
|
---|
1056 | Inc(I);
|
---|
1057 | end
|
---|
1058 | else if List1[I] > List2[J] then
|
---|
1059 | begin
|
---|
1060 | Missing1.Add(List2[J]);
|
---|
1061 | Inc(J);
|
---|
1062 | end
|
---|
1063 | else
|
---|
1064 | begin
|
---|
1065 | Inc(I);
|
---|
1066 | Inc(J);
|
---|
1067 | end;
|
---|
1068 | end;
|
---|
1069 | for I := I to List1.Count - 1 do
|
---|
1070 | Missing2.Add(List1[I]);
|
---|
1071 | for J := J to List2.Count - 1 do
|
---|
1072 | Missing1.Add(List2[J]);
|
---|
1073 | end;
|
---|
1074 |
|
---|
1075 | procedure TConfigMenu.LoadFromDir(Dir: string);
|
---|
1076 | var
|
---|
1077 | Moves: TObjectMoves;
|
---|
1078 | I: Integer;
|
---|
1079 | begin
|
---|
1080 | BaseDir := Dir;
|
---|
1081 | ParseMakeFile;
|
---|
1082 | ParseConfig;
|
---|
1083 |
|
---|
1084 | SetLength(Moves, 0);
|
---|
1085 | PrepareMoveList(Moves);
|
---|
1086 | for I := 0 to Length(Moves) - 1 do
|
---|
1087 | with Moves[I] do begin
|
---|
1088 | TMenuNode(Source).Parent.Items.OwnsObjects := False;
|
---|
1089 | TMenuNode(Source).Parent.Items.Remove(Source);
|
---|
1090 | TMenuNode(Source).Parent.Items.OwnsObjects := True;
|
---|
1091 | TMenuNode(Source).Parent := TMenuNode(NewParent);
|
---|
1092 | TMenuNode(NewParent).Items.Add(Source);
|
---|
1093 | end;
|
---|
1094 | end;
|
---|
1095 |
|
---|
1096 | constructor TConfigMenu.Create;
|
---|
1097 | begin
|
---|
1098 | ConditionStack := TStringList.Create;
|
---|
1099 | Self.FArch := 'x86';
|
---|
1100 | end;
|
---|
1101 |
|
---|
1102 | destructor TConfigMenu.Destroy;
|
---|
1103 | begin
|
---|
1104 | ConditionStack.Free;
|
---|
1105 | end;
|
---|
1106 |
|
---|
1107 | end.
|
---|
1108 |
|
---|
1109 |
|
---|