[Lazarus] CreateRelativePath document error.

Paul van Helden paul at planetgis.co.za
Tue Feb 9 10:32:26 CET 2010


Hi Juha,

FPC RTL comes with ExtractRelativePath. I still use my own code because 
Delphi's didn't work properly either. It seems FPC's ExtractRelativePath 
is much shorter than mine. If someone can confirm it works well that 
would be great (no time now to test thoroughly).

I use the following code (comes from Delphi but with some changes). The 
second function is to expand a relative path. I don't know how you can 
have one without the other, but then I probably don't know where to look 
for it.

function ExtractRelativePath(const BaseName, DestName: string): string;
var
   BasePath, DestPath: string;
   BaseLead, DestLead: PChar;
   BasePtr, DestPtr: PChar;

   function ExtractFilePathNoDrive(const FileName: string): string;
   begin
     Result := ExtractFilePath(FileName);
     Delete(Result, 1, Length(ExtractFileDrive(FileName)));
   end;

   function Next(var Lead: PChar): PChar;
   begin
     Result := Lead;
     if Result = nil then Exit;
     Lead := AnsiStrScan(Lead, PathDelim);
     if Lead <> nil then
     begin
       Lead^ := #0;
       Inc(Lead);
     end;
   end;

begin
   if SameFilename(ExtractFileDrive(BaseName), 
ExtractFileDrive(DestName)) then
   begin
     BasePath := ExtractFilePathNoDrive(BaseName);
     DestPath := ExtractFilePathNoDrive(DestName);
     BaseLead := PChar(BasePath);
     BasePtr := Next(BaseLead);
     DestLead := Pointer(DestPath);
     DestPtr := Next(DestLead);
     while (BasePtr <> nil) and (DestPtr <> nil) and 
SameFilename(BasePtr, DestPtr) do
     begin
       BasePtr := Next(BaseLead);
       DestPtr := Next(DestLead);
     end;
     Result := '';
     while BaseLead <> nil do
     begin
       Result := Result + '..' + PathDelim;
       Next(BaseLead);
     end;
     if (DestPtr <> nil) and (DestPtr^ <> #0) then
       Result := Result + DestPtr + PathDelim;
     if DestLead <> nil then
       Result := Result + DestLead;     // destlead already has a 
trailing backslash
     Result := Result + ExtractFileName(DestName);
     if Result='' then Result:='.';
   end
   else
     Result := DestName;
end;

function ExpandRelativePath(const BaseName, DestName: String): String;
var
   BasePath, DestPath: string;
   BaseDirs, DestDirs: array[0..129] of PChar;
   BaseDirCount, DestDirCount: Integer;
   I, J: Integer;

   function ExtractFilePathNoDrive(const FileName: string): string;
   begin
     Result := ExtractFilePath(FileName);
     Result := Copy(Result, Length(ExtractFileDrive(FileName)) + 1, 32767);
   end;

   procedure SplitDirs(var Path: string; var Dirs: array of PChar;
     var DirCount: Integer);
   var
     I, J, L: Integer;
   begin
     I := 1;
     J := 0;
     L := Length(Path);
     while (I<=L) and (Path[I] in LeadBytes) do Inc(I);
     if I<=L then
     begin
       if Path[I] = PathDelim then
       begin
         Path[I] := #0;
         Dirs[J] := @Path[I + 1];
         Inc(J);
       end
       else
       begin
         Dirs[J] := @Path[I];
         Inc(J);
       end;
       Inc(I);
     end;
     while I<=L do
     begin
       if Path[I] = PathDelim then
       begin
         Path[I] := #0;
         Dirs[J] := @Path[I + 1];
         Inc(J);
       end;
       Inc(I);
     end;
     DirCount := J - 1;
   end;

begin
   if (DestName='.') or (DestName='') then Result:=ExtractFilePath(BaseName)
   else if ExtractFileDrive(DestName)='' then
   begin
     if DestName[1]=PathDelim then 
Result:=ExtractFileDrive(BaseName)+DestName
     else
     begin
       BasePath := ExtractFilePathNoDrive(BaseName);
       DestPath := ExtractFilePathNoDrive(DestName);
       SplitDirs(BasePath, BaseDirs, BaseDirCount);
       SplitDirs(DestPath, DestDirs, DestDirCount);
       I:=0;
       while (I<DestDirCount) and (StrComp(DestDirs[I], '..')=0) do Inc(I);
       Result := '';
       for J := 0 to BaseDirCount-I-1 do
         Result := Result + BaseDirs[J] + PathDelim;
       for J := I to DestDirCount - 1 do
         Result := Result + DestDirs[J] + PathDelim;
       Result:=Result+ExtractFileName(DestName);
     end;
   end
   else Result := DestName;
end;

Regards,

Paul.




More information about the Lazarus mailing list