unit PackageDependencyIntf; {$mode objfpc}{$H+} interface uses Classes, SysUtils, // LazUtils LazFileUtils; type { TPkgVersion } TPkgVersionValid = ( pvtNone, pvtMajor, pvtMinor, pvtRelease, pvtBuild ); TPkgVersion = class private FMajor: integer; FMinor: integer; FRelease: integer; FBuild: integer; FValid: TPkgVersionValid; FOnChange: TNotifyEvent; function GetAsString: String; procedure SetAsString(const AValue: String); public procedure Clear; function Compare(Version2: TPkgVersion): integer; function CompareMask(ExactVersion: TPkgVersion): integer; procedure Assign(Source: TPkgVersion); //function AsString: string; function AsWord: string; function GetIsNullVersion: Boolean; function ReadString(const s: string): boolean; procedure SetValues(NewMajor, NewMinor, NewRelease, NewBuild: integer; NewValid: TPkgVersionValid = pvtBuild); function VersionBound(v: integer): integer; public property AsString: String read GetAsString write SetAsString; property Major: Integer read FMajor write FMajor; property Minor: Integer read FMinor write FMinor; property Release: Integer read FRelease write FRelease; property Build: Integer read FBuild write FBuild; property IsNullVersion: Boolean read GetIsNullVersion; property Valid: TPkgVersionValid read FValid write FValid; property OnChange: TNotifyEvent read FOnChange write FOnChange; end; { PkgDependency flags } TPkgDependencyFlag = ( pdfMinVersion, // >= MinVersion pdfMaxVersion // <= MaxVersion ); TPkgDependencyFlags = set of TPkgDependencyFlag; { TPkgDependencyBase } TPkgDependencyBase = class private protected FFlags: TPkgDependencyFlags; FMaxVersion: TPkgVersion; FMinVersion: TPkgVersion; FPackageName: string; FRemoved: boolean; //FRequiredPackage: TIDEPackage; procedure SetPackageName(const AValue: string); virtual; abstract; public constructor Create; destructor Destroy; override; procedure Clear; virtual; function IsMakingSense: boolean; function IsCompatible(const Version: TPkgVersion): boolean; overload; function IsCompatible(const PkgName: string; const Version: TPkgVersion): boolean; overload; // API for iterating dependencies. function NextUsedByDependency: TPkgDependencyBase; virtual; abstract; function PrevUsedByDependency: TPkgDependencyBase; virtual; abstract; function NextRequiresDependency: TPkgDependencyBase; virtual; abstract; function PrevRequiresDependency: TPkgDependencyBase; virtual; abstract; // API for adding / removing dependencies. procedure AddRequiresDep(var FirstDependency: TPkgDependencyBase); virtual; abstract; procedure AddUsedByDep(var FirstDependency: TPkgDependencyBase); virtual; abstract; procedure RemoveRequiresDep(var FirstDependency: TPkgDependencyBase); virtual; abstract; procedure RemoveUsedByDep(var FirstDependency: TPkgDependencyBase); virtual; abstract; public property Flags: TPkgDependencyFlags read FFlags write FFlags; property MinVersion: TPkgVersion read FMinVersion write FMinVersion; property MaxVersion: TPkgVersion read FMaxVersion write FMaxVersion; property PackageName: string read FPackageName write SetPackageName; property Removed: boolean read FRemoved write FRemoved; end; function IsValidUnitName(AUnitName: String): Boolean; inline; function IsValidPkgName(APkgName: String): Boolean; inline; function PackageFileNameIsValid(const AFilename: string): boolean; implementation function IsValidUnitName(AUnitName: String): Boolean; begin Result := IsValidIdent(AUnitName, True, True); end; function IsValidPkgName(APkgName: String): Boolean; begin Result := IsValidIdent(APkgName, True, True); end; function PackageFileNameIsValid(const AFilename: string): boolean; var PkgName: String; begin Result:=false; if not FilenameExtIs(AFilename,'lpk',true) then exit; PkgName:=ExtractFileNameOnly(AFilename); if (PkgName='') or (not IsValidPkgName(PkgName)) then exit; Result:=true; end; { TPkgVersion } procedure TPkgVersion.Clear; begin SetValues(0,0,0,0,pvtBuild); end; function TPkgVersion.Compare(Version2: TPkgVersion): integer; begin Result:=FMajor-Version2.FMajor; if Result<>0 then exit; Result:=FMinor-Version2.FMinor; if Result<>0 then exit; Result:=FRelease-Version2.FRelease; if Result<>0 then exit; Result:=FBuild-Version2.FBuild; end; function TPkgVersion.CompareMask(ExactVersion: TPkgVersion): integer; begin if FValid=pvtNone then exit(0); Result:=FMajor-ExactVersion.FMajor; if Result<>0 then exit; if FValid=pvtMajor then exit; Result:=FMinor-ExactVersion.FMinor; if Result<>0 then exit; if FValid=pvtMinor then exit; Result:=FRelease-ExactVersion.FRelease; if Result<>0 then exit; if FValid=pvtRelease then exit; Result:=FBuild-ExactVersion.FBuild; end; procedure TPkgVersion.Assign(Source: TPkgVersion); begin SetValues(Source.FMajor,Source.FMinor,Source.FRelease,Source.FBuild,Source.FValid); end; function TPkgVersion.GetAsString: String; begin Result:=IntToStr(FMajor)+'.'+IntToStr(FMinor); if (FBuild<>0) then Result:=Result+'.'+IntToStr(FRelease)+'.'+IntToStr(FBuild) else if (FRelease<>0) then Result:=Result+'.'+IntToStr(FRelease) end; procedure TPkgVersion.SetAsString(const AValue: String); var Version: String; P, I, V: Integer; begin Clear; if AValue = '' then Exit; I := 0; Version := Trim(AValue) + '.'; repeat Inc(I); P := Pos('.', Version); if P <> 0 then begin V := StrToIntDef(Copy(Version, 1, P-1), 0); case I of 1: FMajor := V; 2: FMinor := V; 3: FRelease := V; 4: FBuild := V; end; Delete(Version, 1, P); end; until (Version = '') or (P = 0) or (I > 4); end; function TPkgVersion.AsWord: string; begin Result:=IntToStr(FMajor)+'_'+IntToStr(FMinor); if (FBuild<>0) then Result:=Result+'_'+IntToStr(FRelease)+'_'+IntToStr(FBuild) else if (FRelease<>0) then Result:=Result+'_'+IntToStr(FRelease) end; function TPkgVersion.GetIsNullVersion: Boolean; begin Result := (FMajor = 0) and (FMinor = 0) and (FRelease = 0) and (FBuild = 0); end; function TPkgVersion.ReadString(const s: string): boolean; var ints: array[1..4] of integer; i: integer; CurPos: Integer; StartPos: Integer; NewValid: TPkgVersionValid; begin Result:=false; CurPos:=1; NewValid:=pvtNone; for i:=1 to 4 do begin ints[i]:=0; if CurPosLow(ints) then begin // read point if s[CurPos]<>'.' then exit; inc(CurPos); end; // read int StartPos:=CurPos; while (CurPos<=length(s)) and (i<=9999) and (s[CurPos] in ['0'..'9']) do begin ints[i]:=ints[i]*10+ord(s[CurPos])-ord('0'); inc(CurPos); end; if (StartPos=CurPos) then exit; NewValid:=succ(NewValid); end; end; if CurPos<=length(s) then exit; SetValues(ints[1],ints[2],ints[3],ints[4],NewValid); Result:=true; end; procedure TPkgVersion.SetValues(NewMajor, NewMinor, NewRelease, NewBuild: integer; NewValid: TPkgVersionValid); begin NewMajor:=VersionBound(NewMajor); NewMinor:=VersionBound(NewMinor); NewRelease:=VersionBound(NewRelease); NewBuild:=VersionBound(NewBuild); if (NewMajor=FMajor) and (NewMinor=FMinor) and (NewRelease=FRelease) and (NewBuild=FBuild) and (NewValid=FValid) then exit; FMajor:=NewMajor; FMinor:=NewMinor; FRelease:=NewRelease; FBuild:=NewBuild; FValid:=NewValid; if Assigned(FOnChange) then FOnChange(Self); end; function TPkgVersion.VersionBound(v: integer): integer; begin if v>9999 then Result:=9999 else if v<0 then Result:=0 else Result:=v; end; { TLazPackageID } constructor TPkgDependencyBase.Create; begin inherited Create; MinVersion:=TPkgVersion.Create; MaxVersion:=TPkgVersion.Create; Clear; end; destructor TPkgDependencyBase.Destroy; begin PackageName:=''; FreeAndNil(fMinVersion); FreeAndNil(fMaxVersion); inherited Destroy; end; procedure TPkgDependencyBase.Clear; begin PackageName:=''; FRemoved:=false; FFlags:=[]; FMaxVersion.Clear; FMinVersion.Clear; end; function TPkgDependencyBase.IsMakingSense: boolean; begin Result:=IsValidPkgName(PackageName); if Result and (pdfMinVersion in FFlags) and (pdfMaxVersion in FFlags) and (MinVersion.Compare(MaxVersion)>0) then Result:=false; end; function TPkgDependencyBase.IsCompatible(const Version: TPkgVersion): boolean; begin if ((pdfMinVersion in FFlags) and (MinVersion.Compare(Version)>0)) or ((pdfMaxVersion in FFlags) and (MaxVersion.Compare(Version)<0)) then Result:=false else Result:=true; end; function TPkgDependencyBase.IsCompatible(const PkgName: string; const Version: TPkgVersion): boolean; begin Result:=(CompareText(PkgName,PackageName)=0) and IsCompatible(Version); end; end.