123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- (* 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;
|