197 lines
5.6 KiB
ObjectPascal
197 lines
5.6 KiB
ObjectPascal
|
|
unit FileUtils;
|
||
|
|
|
||
|
|
{$I jvcl.inc}
|
||
|
|
|
||
|
|
interface
|
||
|
|
|
||
|
|
uses
|
||
|
|
Windows;
|
||
|
|
|
||
|
|
{$IFNDEF COMPILER6_UP}
|
||
|
|
{$DEFINE MSWINDOWS}
|
||
|
|
{$ENDIF COMPILER6_UP}
|
||
|
|
|
||
|
|
// returns the relative path between Origin and Destination
|
||
|
|
// This is the string you would have to type after the 'cd'
|
||
|
|
// command is you were located in Origin and willing to change
|
||
|
|
// to Destination
|
||
|
|
// Both Origin and Destination should be absolute path but this
|
||
|
|
// is not verified by the function.
|
||
|
|
// If Origin and Destination are on different partitions,
|
||
|
|
// the function returns Destination
|
||
|
|
function GetRelativePath(const Origin, Destination : string) : string;
|
||
|
|
|
||
|
|
// returns the given path without any relative instructions inside
|
||
|
|
// for instance, if you pass c:\a\b\..\c\.\d, it returns c:\a\c\d
|
||
|
|
// Note that if you pass ..\..\a\b it doesn't remove the heading
|
||
|
|
// relative paths instructions.
|
||
|
|
// If there are more ..\ than paths in front of it, the result
|
||
|
|
// is undefined (most likely an exception will be triggered)
|
||
|
|
function PathNoInsideRelative(const Path : string) : string;
|
||
|
|
|
||
|
|
{$IFDEF COMPILER5}
|
||
|
|
// Sets the date and time of the indicated file
|
||
|
|
// This function with this signature doesn't exists in D5 so
|
||
|
|
// we had to declare it here
|
||
|
|
function FileSetDate(const FileName: string; Age: Integer): Integer;
|
||
|
|
{$ENDIF COMPILER5}
|
||
|
|
|
||
|
|
implementation
|
||
|
|
|
||
|
|
uses
|
||
|
|
Classes,
|
||
|
|
{$IFDEF COMPILER6_UP}
|
||
|
|
StrUtils,
|
||
|
|
{$ENDIF COMPILER6_UP}
|
||
|
|
{$IFDEF NO_JCL}
|
||
|
|
UtilsJcl,
|
||
|
|
{$ELSE}
|
||
|
|
JclStrings, JclFileUtils,
|
||
|
|
{$ENDIF NO_JCL}
|
||
|
|
SysUtils;
|
||
|
|
|
||
|
|
{$IFDEF COMPILER5}
|
||
|
|
function AnsiStartsStr(const SubStr, S: string): Boolean;
|
||
|
|
begin
|
||
|
|
Result := StrLComp(PChar(S), PChar(SubStr), Length(SubStr)) = 0;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function AnsiEndsStr(const SubStr, S: string): Boolean;
|
||
|
|
begin
|
||
|
|
Result := StrLComp(PChar(S) + Length(S) - Length(SubStr), PChar(SubStr), Length(SubStr)) = 0;
|
||
|
|
end;
|
||
|
|
{$ENDIF COMPILER5}
|
||
|
|
|
||
|
|
function StrEnsureNoPrefix(const prefix, str : string) : string;
|
||
|
|
begin
|
||
|
|
if AnsiStartsStr(prefix, str) then
|
||
|
|
Result := Copy(str, Length(prefix)+1, MaxInt)
|
||
|
|
else
|
||
|
|
Result := str;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function StrEnsureNoSuffix(const suffix, str : string) : string;
|
||
|
|
begin
|
||
|
|
if AnsiEndsStr(suffix, str) then
|
||
|
|
Result := Copy(str, 1, Length(str)-Length(suffix))
|
||
|
|
else
|
||
|
|
Result := str;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function GetRelativePath(const Origin, Destination : string) : string;
|
||
|
|
var
|
||
|
|
OrigList : TStringList;
|
||
|
|
DestList : TStringList;
|
||
|
|
DiffIndex : Integer;
|
||
|
|
i : Integer;
|
||
|
|
begin
|
||
|
|
// create a list of paths as separate strings
|
||
|
|
OrigList := TStringList.Create;
|
||
|
|
DestList := TStringList.Create;
|
||
|
|
try
|
||
|
|
// NOTE: DO NOT USE DELIMITER AND DELIMITEDTEXT FROM
|
||
|
|
// TSTRINGS, THEY WILL SPLIT PATHS WITH SPACES !!!!
|
||
|
|
StrToStrings(Origin, DirDelimiter, OrigList);
|
||
|
|
StrToStrings(Destination, DirDelimiter, DestList);
|
||
|
|
{$IFDEF MSWINDOWS}
|
||
|
|
// Let's do some tests when the paths indicate drive letters
|
||
|
|
// This, of course, only happens under a Windows platform
|
||
|
|
|
||
|
|
// If the destination indicates a drive and the drive
|
||
|
|
// letter is different from the one from the one in
|
||
|
|
// origin, then simply return it as the result
|
||
|
|
// Else, if the origin indicates a drive and destination
|
||
|
|
// doesn't, then return the concatenation of origin and
|
||
|
|
// destination, ensuring a DirDelimiter between them.
|
||
|
|
// Else, try to find the relative path between the two.
|
||
|
|
if (DestList[0][2] = ':') and
|
||
|
|
(DestList[0][1] <> OrigList[0][1]) then
|
||
|
|
begin
|
||
|
|
Result := Destination;
|
||
|
|
end
|
||
|
|
else if (OrigList[0][2] = ':') and
|
||
|
|
(DestList[0][2] <> ':') then
|
||
|
|
begin
|
||
|
|
Result := StrEnsureSuffix(DirDelimiter, Origin)+StrEnsureNoPrefix(DirDelimiter, Destination);
|
||
|
|
end
|
||
|
|
else
|
||
|
|
{$ENDIF}
|
||
|
|
begin
|
||
|
|
// find the first directory that is not the same
|
||
|
|
DiffIndex := 0;
|
||
|
|
{$IFDEF MSWINDOWS} // case insensitive
|
||
|
|
while CompareStr(OrigList[DiffIndex], DestList[DiffIndex]) = 0 do
|
||
|
|
{$ELSE} // case sensitive
|
||
|
|
while OrigList[DiffIndex] = DestList[DiffIndex] do
|
||
|
|
{$ENDIF}
|
||
|
|
Inc(DiffIndex);
|
||
|
|
|
||
|
|
Result := StrRepeat('..' + DirDelimiter, OrigList.Count - DiffIndex);
|
||
|
|
if DiffIndex < DestList.Count then
|
||
|
|
begin
|
||
|
|
for i := DiffIndex to DestList.Count - 2 do
|
||
|
|
Result := Result + DestList[i] + DirDelimiter;
|
||
|
|
Result := Result + DestList[DestList.Count-1];
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
finally
|
||
|
|
DestList.Free;
|
||
|
|
OrigList.Free;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function PathNoInsideRelative(const Path : string) : string;
|
||
|
|
var
|
||
|
|
PathList : TStringList;
|
||
|
|
i : Integer;
|
||
|
|
begin
|
||
|
|
PathList := TStringList.Create;
|
||
|
|
try
|
||
|
|
StrToStrings(Path, DirDelimiter, PathList);
|
||
|
|
i := 0;
|
||
|
|
while i < PathList.Count do
|
||
|
|
begin
|
||
|
|
// three cases:
|
||
|
|
// - a single point is found, we simply remove it
|
||
|
|
// - a double point is found, not being the first and not being
|
||
|
|
// preceded by a double point, then we remove it and the
|
||
|
|
// directory before it
|
||
|
|
// - everything else is left in
|
||
|
|
if PathList[i] = '.' then
|
||
|
|
PathList.Delete(i)
|
||
|
|
else if (PathList[i] = '..') and
|
||
|
|
(i>0) and
|
||
|
|
(PathList[i-1] <> '..') then
|
||
|
|
begin
|
||
|
|
Dec(i);
|
||
|
|
PathList.Delete(i);
|
||
|
|
PathList.Delete(i);
|
||
|
|
end
|
||
|
|
else
|
||
|
|
Inc(i);
|
||
|
|
end;
|
||
|
|
Result := StringsToStr(PathList, DirDelimiter);
|
||
|
|
finally
|
||
|
|
PathList.Free;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{$IFDEF COMPILER5}
|
||
|
|
function FileSetDate(const FileName: string; Age: Integer): Integer;
|
||
|
|
var
|
||
|
|
f: THandle;
|
||
|
|
begin
|
||
|
|
f := FileOpen(FileName, fmOpenWrite);
|
||
|
|
if f = THandle(-1) then
|
||
|
|
Result := GetLastError
|
||
|
|
else
|
||
|
|
begin
|
||
|
|
Result := SysUtils.FileSetDate(f, Age);
|
||
|
|
FileClose(f);
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
{$ENDIF COMPILER5}
|
||
|
|
|
||
|
|
|
||
|
|
end.
|