| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | unit fpmakeParseJSon;{$mode objfpc}{$H+}interfaceuses  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;implementationvar 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;    endend;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.
 |