fpc/rtl/inc/fexpand.inc
2000-11-06 20:36:17 +00:00

201 lines
6.4 KiB
PHP

(* LFNSupport boolean constant, variable or function must be declared for all
the platforms, at least locally in the Dos unit implementation part.
In addition, FEXPAND_UNC, FEXPAND_DRIVES, FEXPAND_GETENV_PCHAR
and FEXPAND_TILDE conditionals might be defined to specify FExpand
behaviour. Only forward slashes are supported if UNIX conditional
is defined, both forward and backslashes otherwise.
*)
(* TODO: GetDir replacement function should appear here to remove
the incorrect setting of IOResult within FExpand.
*)
{
function get_current_drive:byte;assembler;
asm
movb $0x19,%ah
call syscall
end;
}
const
{$IFDEF UNIX}
DirSep = '/';
{$ELSE UNIX}
DirSep = '\';
{$ENDIF UNIX}
{$IFDEF FEXPAND_DRIVES}
PathStart = 3;
{$ELSE FEXPAND_DRIVES}
PathStart = 1;
{$ENDIF FEXPAND_DRIVES}
var S, Pa: PathStr;
I, J: longint;
begin
if FileNameCaseSensitive then
Pa := Path
else
Pa := UpCase (Path);
{$IFNDEF UNIX}
{Allow slash as backslash}
for I := 1 to Length (Pa) do
if Pa [I] = '/' then
Pa [I] := DirSep;
{$ENDIF}
{$IFDEF FEXPAND_TILDE}
{Replace ~/ with $HOME}
if (Length (Pa) > 1) and (Pa [1] ='~') and (Pa [2] = DirSep) then
begin
{$IFDEF FEXPAND_GETENV_PCHAR}
S := StrPas (GetEnv ('HOME'));
{$ELSE FEXPAND_GETENV_PCHAR}
S := GetEnv ('HOME');
{$ENDIF FEXPAND_GETENV_PCHAR}
if (S = '') or (Length (S) = 1) and (S [1] = DirSep) then
Delete (Pa, 1, 1)
else
if S [Length (S)] = DirSep then
Pa := S + Copy (Pa, 3, Length (Pa - 2))
else
Pa := S + Copy (Pa, 2, Pred (Length (Pa)));
end;
{$ENDIF FEXPAND_TILDE}
if (Length (Pa) > 1) and (Pa [1] in ['A'..'Z', 'a'..'z']) and
(Pa [2] = ':') then
begin
{$IFDEF FEXPAND_DRIVES}
{ Always uppercase driveletter }
if (Pa [1] in ['a'..'z']) then
Pa [1] := Chr (Ord (Pa [1]) and not ($20));
{We must get the right directory (should be changed to avoid
touching IOResult)}
{$IFOPT I+}
{$DEFINE FEXPAND_WAS_I}
{$I-}
{$ENDIF}
I := IOResult;
GetDir (Ord (Pa [1]) - Ord ('A') + 1, S);
I := IOResult;
{$IFDEF FEXPAND_WAS_I}
{$I+}
{$UNDEF FEXPAND_WAS_I}
{$ENDIF FEXPAND_WAS_I}
case Length (Pa) of
2: Pa := S;
else
if Pa [3] <> DirSep then
if Pa [1] = S [1] then
begin
{ remove ending slash if it already exists }
if S [Length (S)] = DirSep then
Dec (S [0]);
Pa := S + DirSep + Copy (Pa, 3, Length (Pa))
end
else
Pa := Pa [1] + ':' + DirSep + Copy (Pa, 3, Length (Pa))
end;
end
else
{$ELSE FEXPAND_DRIVES}
Delete (Path, 1, 2);
Delete (Pa, 1, 2);
end;
{$ENDIF FEXPAND_DRIVES}
begin
{$IFOPT I+}
{$DEFINE FEXPAND_WAS_I}
{$I-}
{$ENDIF}
I := IOResult;
GetDir (0, S);
I := IOResult;
{$IFDEF FEXPAND_WAS_I}
{$I+}
{$UNDEF FEXPAND_WAS_I}
{$ENDIF FEXPAND_WAS_I}
{$IFDEF FEXPAND_DRIVES}
if (Length (Pa) > 0) and (Pa [1] = DirSep) then
begin
{$IFDEF FEXPAND_UNC}
{ Do not touch Network drive names }
if not ((Length (Pa) > 1) and (Pa [2] = Pa [1])
and LFNSupport) then
{$ENDIF FEXPAND_UNC}
Pa := S [1] + ':' + Pa
end
else
{$ENDIF FEXPAND_DRIVES}
(* We already have a slash if root is the curent directory. *)
if Length (S) = PathStart then
Pa := S + Pa
else
(* We need an ending slash if FExpand was called
with an empty string for compatibility. *)
if Length (Pa) = 0 then
Pa := S + DirSep
else
Pa := S + DirSep + Pa;
end;
{First remove all references to '\.\'}
I := Pos (DirSep + '.' + DirSep, Pa);
while I <> 0 do
begin
Delete (Pa, I, 2);
I := Pos (DirSep + '.' + DirSep, Pa);
end;
{Now remove also all references to '\..\' + of course previous dirs..}
I := Pos (DirSep + '..' + DirSep, Pa);
while I <> 0 do
begin
J := Pred (I);
while (J > 0) and (Pa [J] <> DirSep) do
Dec (J);
if (J = 0)
{$IFDEF FEXPAND_UNC}
or (J = 1) and (I = 2)
{$ENDIF FEXPAND_UNC}
then
Delete (Pa, Succ (I), 3)
else
Delete (Pa, Succ (J), I - J + 3);
I := Pos (DirSep + '..' + DirSep, Pa);
end;
{Now remove also any reference to '\..' at the end of line
+ of course previous dir..}
I := Pos (DirSep + '..', Pa);
if (I <> 0) and (I = Length (Pa) - 2) then
begin
J := Pred (I);
while (J >= 1) and (Pa [J] <> DirSep) do
Dec (J);
if (J = 0)
{$IFDEF FEXPAND_UNC}
or (J = 1) and (I = 2)
{$ENDIF FEXPAND_UNC}
then
Delete (Pa, Succ (I), 2)
else
Delete (Pa, Succ (J), I - J + 2);
end;
{Now remove also any reference to '\.' at the end of line}
I := Pos (DirSep + '.', Pa);
if (I <> 0) and (I = Pred (Length (Pa))) then
if (I = PathStart)
{$IFDEF FEXPAND_DRIVES}
and (Pa [2] = ':')
{$ENDIF FEXPAND_DRIVES}
{$IFDEF FEXPAND_UNC}
or (I = 2) and (Pa [1] = '\')
{$ENDIF FEXPAND_UNC}
then
Dec (Pa [0])
else
Delete (Pa, I, 2);
{Remove ending \ if not supplied originally, the original string
wasn't empty (to stay compatible) and if not really needed}
if (Length (Pa) > PathStart) and (Pa [Length (Pa)] = DirSep)
and (Length (Path) <> 0) and (Path [Length (Path)] <> DirSep) then
Dec (Pa [0]);
FExpand := Pa;
end;