123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- unit fpmakeParseJSon;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils,
- fpmkunit,
- jsonparser, fpjson;
- function ParseFpmake(AJsonData : TJSONData) : TPackages;
- function ParseFpmakeFile(AFileName: string) : TPackages;
- function ExtStringToOSes(AString: String) : TOSes;
- function ExtOSesToString(AOSes: TOSes) : string;
- function ExtStringToCPUs(AString: String) : TCpus;
- function ExtCPUsToString(ACPUs: TCPUs) : string;
- implementation
- var GSetStrings: TStringList;
- function SetStrings: TstringList;
- begin
- if not assigned(GSetStrings) then
- GSetStrings := TStringList.Create;
- result := GSetStrings;
- end;
- function ExtStringToOSes(AString: String) : TOSes;
- var
- i: dword;
- begin
- try
- result := OSesToString(AString);
- except
- i := SetStrings.Add(AString)+1;
- result:=TOSes(dword(dword(AllOSes)+dword(i)));
- end;
- end;
- function ExtOSesToString(AOSes: TOSes) : string;
- var
- i: dword;
- begin
- if DWord(AOSes) < DWord(AllOSes) then
- result := '[' + OSesToString(AOSes) + ']'
- else
- begin
- i := (dword(AOSes) - dword(AllOSes)) -1;
- if i < SetStrings.Count then
- result := SetStrings[i]
- else
- raise exception.Create('Invalid set of OSes.');
- end;
- end;
- function ExtStringToCPUs(AString: String) : TCpus;
- var
- i: dword;
- begin
- try
- result := StringToCPUS(AString);
- except
- i := SetStrings.Add(AString)+1;
- result:=TCPUS(dword(dword(AllCPUs)+dword(i)));
- end;
- end;
- function ExtCPUsToString(ACPUs: TCPUs) : string;
- var
- i: dword;
- begin
- if DWord(ACPUs) < DWord(AllCPUs) then
- result := '[' + CPUSToString(ACPUs) + ']'
- else
- begin
- i := (dword(ACPUs) - dword(AllCPUs)) -1;
- if i < SetStrings.Count then
- result := SetStrings[i]
- else
- raise exception.Create('Invalid set of CPUs.');
- end;
- end;
- procedure ParseConditionalString(ADependency: TConditionalString; AJsonData: TJSonData; ValueCaption: string);
- var
- AJsonObject: TJSONObject;
- m: Integer;
- begin
- if AJsonData.JSONType = jtString then
- begin
- ADependency.Value := AJsonData.AsString;
- end
- else if AJsonData.JSONType = jtObject then
- begin
- AJsonObject := AJsonData as TJSONObject;
- for m := 0 to AJsonObject.Count-1 do
- begin
- case AJsonObject.Names[m] of
- 'oses' : ADependency.oses := ExtStringToOSes(AJsonObject.Items[m].AsString);
- 'cpus' : ADependency.CPUs := ExtStringToCPUS(AJsonObject.Items[m].AsString);
- else if AJsonObject.Names[m] = ValueCaption then
- ADependency.Value := AJsonObject.Items[m].AsString
- else
- raise Exception.CreateFmt('Unknown conditional property ''%s''.',[AJsonObject.Names[m]]);
- end {case}
- end;
- end
- else
- raise Exception.CreateFmt('Invalid conditional. (%s)',[AJsonData.AsString]);
- end;
- procedure ParseConditionalArray(ACondStrings: TConditionalStrings; AJsonData: TJSonData; ValueCaption: string);
- var
- AJSonArray: TJSONArray;
- n: Integer;
- begin
- if AJsonData.JSONType = jtArray then
- begin
- AJSonArray := AJsonData as TJSONArray;
- for n := 0 to AJSonArray.Count-1 do
- ParseConditionalString(ACondStrings.add(''), AJSonArray.Items[n], ValueCaption);
- end
- else
- ParseConditionalString(ACondStrings.add(''), AJsonData, ValueCaption);
- end;
- procedure ParseDependenciesArray(ACondStrings: TDependencies; AJsonData: TJSonData; ValueCaption: string; aDepType: TDependencyType);
- var
- AJSonArray: TJSONArray;
- n: Integer;
- function GetDep: TDependency;
- begin
- if aDepType=depInclude then
- result := ACondStrings.AddInclude('')
- else if aDepType=depUnit then
- result := ACondStrings.AddUnit('')
- else
- result := ACondStrings.Add('');
- end;
- begin
- if AJsonData.JSONType = jtArray then
- begin
- AJSonArray := AJsonData as TJSONArray;
- for n := 0 to AJSonArray.Count-1 do
- ParseConditionalString(GetDep, AJSonArray.Items[n], ValueCaption);
- end
- else
- ParseConditionalString(GetDep, AJsonData, ValueCaption);
- end;
- procedure ParseDependencies(aDependencies: TDependencies; aJSONData: TJSONData);
- var
- AJsonObject: TJSONObject;
- m: Integer;
- begin
- if aJSONData.JSONType<>jtObject then
- raise exception.create('A target''s dependency has to be an object which encapsulated the different types of dependencies.')
- else
- begin
- AJsonObject := aJSONData as TJSONObject;
- for m := 0 to AJsonObject.Count-1 do
- begin
- case AJsonObject.Names[m] of
- 'includefiles' : ParseDependenciesArray(aDependencies, AJsonObject.items[m],'filename', depInclude);
- 'units' : ParseDependenciesArray(aDependencies, AJsonObject.items[m],'filename', depUnit);
- else
- raise Exception.CreateFmt('Unknown dependency property ''%s''.',[AJsonObject.Names[m]]);
- end {case}
- end;
- end
- end;
- procedure ParseUnitTarget(aTarget: TTarget; aJSONData: TJSONData);
- var
- AJsonObject: TJSONObject;
- m: Integer;
- begin
- if aJSONData.JSONType=jtString then
- aTarget.Name := aJSONData.AsString
- else if aJSONData.JSONType=jtObject then
- begin
- AJsonObject := aJSONData as TJSONObject;
- for m := 0 to AJsonObject.Count-1 do
- begin
- case AJsonObject.Names[m] of
- 'name' : aTarget.name := AJsonObject.items[m].asstring;
- 'resourcestrings' : atarget.ResourceStrings := (AJsonObject.items[m] as TJSONBoolean).AsBoolean;
- 'oses' : aTarget.OSes := ExtStringToOSes(AJsonObject.Items[m].AsString);
- 'cpus' : aTarget.cpus := ExtStringToCPUs(AJsonObject.Items[m].AsString);
- 'dependencies' : ParseDependencies(aTarget.Dependencies, AJsonObject.Items[m]);
- else
- raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
- end {case}
- end;
- end
- else
- raise Exception.CreateFmt('Invalid target ''%s''',[aJSONData.AsString]);
- end;
- procedure ParseUnitTargets(aTargets: TTargets; aJSONData: TJSONData);
- var
- AJsonArray: TJSONArray;
- AJsonObject: TJSONObject;
- AResourceStrings: boolean;
- ACPUs: TCPUS;
- AOSes: TOSes;
- m: Integer;
- LastTargetItem: integer;
- ATarget: ttarget;
- begin
- if aJSONData.JSONType=jtArray then
- begin
- AJsonArray := aJSONData as TJSONArray;
- for m := 0 to AJsonArray.Count-1 do
- ParseUnitTarget(aTargets.AddUnit(''), AJsonArray.Items[m]);
- end
- else if aJSONData.JSONType=jtObject then
- begin
- AJsonObject := aJSONData as TJSONObject;
- AresourceStrings:=false;
- ACpus:=AllCPUs;
- AOses:=AllOSes;
- LastTargetItem:=aTargets.Count;
- for m := 0 to AJsonObject.Count-1 do
- begin
- case AJsonObject.Names[m] of
- 'resourcestrings' : AresourceStrings := (AJsonObject.items[m] as TJSONBoolean).AsBoolean;
- 'cpus' : ACPUs := ExtStringToCPUs(AJsonObject.items[m].AsString);
- 'oses' : AOSes := ExtStringToOSes(AJsonObject.items[m].AsString);
- 'targets' : ParseUnitTargets(aTargets, AJsonObject.items[m])
- else
- raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
- end {case}
- end;
- for m := LastTargetItem to aTargets.Count-1 do
- begin
- aTarget := aTargets.Items[m] as TTarget;
- if AresourceStrings then
- aTarget.ResourceStrings := AresourceStrings;
- if ACPUs<>AllCPUs then
- ATarget.CPUs := ACpus;
- if AOSes<>AllOSes then
- ATarget.OSes := AOses;
- end;
- end
- else
- raise Exception.CreateFmt('Invalid unit target ''%s''',[aJSONData.AsString]);
- end;
- procedure ParseTargets(aTargets: TTargets; aJSONData: TJSONData);
- var
- AJsonObject: TJSONObject;
- m: Integer;
- begin
- if aJSONData.JSONType<>jtObject then
- raise Exception.Create('Invalid targets');
- AJsonObject := aJSONData as TJSONObject;
- for m := 0 to AJsonObject.Count-1 do
- begin
- case AJsonObject.Names[m] of
- 'units' : ParseUnitTargets(aTargets, AJsonObject.items[m]);
- else
- raise Exception.CreateFmt('Unknown targets property ''%s''.',[AJsonObject.Names[m]]);
- end {case}
- end;
- end;
- function ParseFpmakeFile(AFileName: string) : TPackages;
- var
- AJsonData : TJSONData;
- F : TFileStream;
- P: TJSONParser;
- begin
- result := nil;
- // Parse the JSON-file
- F:=TFileStream.Create(AFileName,fmopenRead);
- try
- P:=TJSONParser.Create(F);
- try
- try
- AJsonData := P.Parse;
- except
- on E: Exception do
- begin
- writeln(Format('Error: Syntax of JSON-file %s is incorrect (%s)', [AFileName, e.Message]));
- exit;
- end;
- end;
- finally
- P.Free;
- end;
- finally
- F.Free;
- end;
- try
- result := ParseFpmake(AJsonData);
- except
- on E: Exception do
- begin
- writeln(Format('Error, problem in file %s: %s',[AFileName,e.Message]));
- exit;
- end;
- end;
- end;
- function ParseFpmake(AJsonData : TJSONData) : TPackages;
- Var
- P : TJSONParser;
- MainObject : TJSONObject;
- ItemObject : TJSONObject;
- i: Integer;
- APackages: TPackages;
- n: Integer;
- procedure AddDependencies(APackage: TPackage; AJsonDependencies: TJSONData);
- var
- AJsonDependenciesObj: TJSONObject;
- m,n,o: Integer;
- ADependency: TDependency;
- begin
- if AJsonDependencies.JSONType<>jtObject then
- raise Exception.CreateFmt('Invalid dependencies for package %s',[APackage.Name]);
- AJsonDependenciesObj := AJsonDependencies as TJSONObject;
- for m := 0 to AJsonDependenciesObj.Count-1 do
- begin
- case AJsonDependenciesObj.Names[m] of
- 'packages' : ParseConditionalArray(APackage.Dependencies, AJsonDependenciesObj.items[m],'name');
- else
- raise Exception.CreateFmt('Unknown dependency property ''%s''.',[ItemObject.Names[m]]);
- end {case}
- end;
- end;
- var
- APackage: TPackage;
- begin
- // Convert the JSON-Data to a packages-class
- if AJsonData.JSONType <> jtObject then
- raise Exception.Create('File does not contain any objects.');
- APackages := TPackages.Create(TPackage);
- try
- MainObject := AJsonData as TJSONObject;
- for i := 0 to MainObject.Count-1 do
- begin
- if MainObject.Names[i]='package' then
- begin
- AJsonData := MainObject.Items[i];
- if (AJsonData.JSONType <> jtObject) then
- raise Exception.Create('File does not contain any objects.');
- ItemObject := AJsonData as TJSONObject;
- APackage := APackages.AddPackage('');
- for n := 0 to ItemObject.Count-1 do
- begin
- case ItemObject.Names[n] of
- 'title' : APackage.Name := ItemObject.items[n].AsString;
- 'directory' : APackage.Directory := ItemObject.items[n].AsString;
- 'version' : APackage.version := ItemObject.items[n].AsString;
- 'oses' : APackage.OSes := ExtStringToOSes(ItemObject.items[n].AsString);
- 'cpus' : APackage.CPUs := ExtStringToCPUs(ItemObject.items[n].AsString);
- 'dependencies' : AddDependencies(APackage, ItemObject.items[n]);
- 'sourcepaths' : ParseConditionalArray(APackage.SourcePath, ItemObject.items[n],'path');
- 'targets' : ParseTargets(APackage.Targets, ItemObject.items[n]);
- 'email' : APackage.Email := ItemObject.items[n].AsString;
- 'author' : APackage.Author := ItemObject.items[n].AsString;
- 'license' : APackage.License := ItemObject.items[n].AsString;
- 'homepageurl' : APackage.HomepageURL := ItemObject.items[n].AsString;
- 'description' : APackage.Description := ItemObject.items[n].AsString;
- 'needlibc' : APackage.NeedLibC := (ItemObject.items[n] as TJSONBoolean).AsBoolean;
- else
- raise Exception.CreateFmt('Unknown package property ''%s''.',[ItemObject.Names[n]]);
- end {case}
- end;
- end;
- end;
- Result := APackages;
- except
- APackages.Free;
- raise;
- end;
- end;
- initialization
- GSetStrings := nil;
- finalization
- GSetStrings.Free;
- end.
|