fexpand.inc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. (* LFNSupport boolean constant, variable or function must be declared for all
  2. the platforms, at least locally in the Dos unit implementation part.
  3. In addition, FEXPAND_UNC, FEXPAND_DRIVES, FEXPAND_GETENV_PCHAR
  4. and FEXPAND_TILDE conditionals might be defined to specify FExpand
  5. behaviour. Only forward slashes are supported if UNIX conditional
  6. is defined, both forward and backslashes otherwise.
  7. *)
  8. (* TODO: GetDir replacement function should appear here to remove
  9. the incorrect setting of IOResult within FExpand.
  10. *)
  11. {
  12. function get_current_drive:byte;assembler;
  13. asm
  14. movb $0x19,%ah
  15. call syscall
  16. end;
  17. }
  18. const
  19. {$IFDEF UNIX}
  20. DirSep = '/';
  21. {$ELSE UNIX}
  22. DirSep = '\';
  23. {$ENDIF UNIX}
  24. {$IFDEF FEXPAND_DRIVES}
  25. PathStart = 3;
  26. {$ELSE FEXPAND_DRIVES}
  27. PathStart = 1;
  28. {$ENDIF FEXPAND_DRIVES}
  29. var S, Pa: PathStr;
  30. I, J: longint;
  31. begin
  32. if FileNameCaseSensitive then
  33. Pa := Path
  34. else
  35. Pa := UpCase (Path);
  36. {$IFNDEF UNIX}
  37. {Allow slash as backslash}
  38. for I := 1 to Length (Pa) do
  39. if Pa [I] = '/' then
  40. Pa [I] := DirSep;
  41. {$ENDIF}
  42. {$IFDEF FEXPAND_TILDE}
  43. {Replace ~/ with $HOME}
  44. if (Length (Pa) > 1) and (Pa [1] ='~') and (Pa [2] = DirSep) then
  45. begin
  46. {$IFDEF FEXPAND_GETENV_PCHAR}
  47. S := StrPas (GetEnv ('HOME'));
  48. {$ELSE FEXPAND_GETENV_PCHAR}
  49. S := GetEnv ('HOME');
  50. {$ENDIF FEXPAND_GETENV_PCHAR}
  51. if (S = '') or (Length (S) = 1) and (S [1] = DirSep) then
  52. Delete (Pa, 1, 1)
  53. else
  54. if S [Length (S)] = DirSep then
  55. Pa := S + Copy (Pa, 3, Length (Pa - 2))
  56. else
  57. Pa := S + Copy (Pa, 2, Pred (Length (Pa)));
  58. end;
  59. {$ENDIF FEXPAND_TILDE}
  60. if (Length (Pa) > 1) and (Pa [1] in ['A'..'Z', 'a'..'z']) and
  61. (Pa [2] = ':') then
  62. begin
  63. {$IFDEF FEXPAND_DRIVES}
  64. { Always uppercase driveletter }
  65. if (Pa [1] in ['a'..'z']) then
  66. Pa [1] := Chr (Ord (Pa [1]) and not ($20));
  67. {We must get the right directory (should be changed to avoid
  68. touching IOResult)}
  69. {$IFOPT I+}
  70. {$DEFINE FEXPAND_WAS_I}
  71. {$I-}
  72. {$ENDIF}
  73. I := IOResult;
  74. GetDir (Ord (Pa [1]) - Ord ('A') + 1, S);
  75. I := IOResult;
  76. {$IFDEF FEXPAND_WAS_I}
  77. {$I+}
  78. {$UNDEF FEXPAND_WAS_I}
  79. {$ENDIF FEXPAND_WAS_I}
  80. case Length (Pa) of
  81. 2: Pa := S;
  82. else
  83. if Pa [3] <> DirSep then
  84. if Pa [1] = S [1] then
  85. begin
  86. { remove ending slash if it already exists }
  87. if S [Length (S)] = DirSep then
  88. Dec (S [0]);
  89. Pa := S + DirSep + Copy (Pa, 3, Length (Pa))
  90. end
  91. else
  92. Pa := Pa [1] + ':' + DirSep + Copy (Pa, 3, Length (Pa))
  93. end;
  94. end
  95. else
  96. {$ELSE FEXPAND_DRIVES}
  97. Delete (Path, 1, 2);
  98. Delete (Pa, 1, 2);
  99. end;
  100. {$ENDIF FEXPAND_DRIVES}
  101. begin
  102. {$IFOPT I+}
  103. {$DEFINE FEXPAND_WAS_I}
  104. {$I-}
  105. {$ENDIF}
  106. I := IOResult;
  107. GetDir (0, S);
  108. I := IOResult;
  109. {$IFDEF FEXPAND_WAS_I}
  110. {$I+}
  111. {$UNDEF FEXPAND_WAS_I}
  112. {$ENDIF FEXPAND_WAS_I}
  113. {$IFDEF FEXPAND_DRIVES}
  114. if (Length (Pa) > 0) and (Pa [1] = DirSep) then
  115. begin
  116. {$IFDEF FEXPAND_UNC}
  117. { Do not touch Network drive names }
  118. if not ((Length (Pa) > 1) and (Pa [2] = Pa [1])
  119. and LFNSupport) then
  120. {$ENDIF FEXPAND_UNC}
  121. Pa := S [1] + ':' + Pa
  122. end
  123. else
  124. {$ENDIF FEXPAND_DRIVES}
  125. (* We already have a slash if root is the curent directory. *)
  126. if Length (S) = PathStart then
  127. Pa := S + Pa
  128. else
  129. (* We need an ending slash if FExpand was called
  130. with an empty string for compatibility. *)
  131. if Length (Pa) = 0 then
  132. Pa := S + DirSep
  133. else
  134. Pa := S + DirSep + Pa;
  135. end;
  136. {First remove all references to '\.\'}
  137. I := Pos (DirSep + '.' + DirSep, Pa);
  138. while I <> 0 do
  139. begin
  140. Delete (Pa, I, 2);
  141. I := Pos (DirSep + '.' + DirSep, Pa);
  142. end;
  143. {Now remove also all references to '\..\' + of course previous dirs..}
  144. I := Pos (DirSep + '..' + DirSep, Pa);
  145. while I <> 0 do
  146. begin
  147. J := Pred (I);
  148. while (J > 0) and (Pa [J] <> DirSep) do
  149. Dec (J);
  150. if (J = 0)
  151. {$IFDEF FEXPAND_UNC}
  152. or (J = 1) and (I = 2)
  153. {$ENDIF FEXPAND_UNC}
  154. then
  155. Delete (Pa, Succ (I), 3)
  156. else
  157. Delete (Pa, Succ (J), I - J + 3);
  158. I := Pos (DirSep + '..' + DirSep, Pa);
  159. end;
  160. {Now remove also any reference to '\..' at the end of line
  161. + of course previous dir..}
  162. I := Pos (DirSep + '..', Pa);
  163. if (I <> 0) and (I = Length (Pa) - 2) then
  164. begin
  165. J := Pred (I);
  166. while (J >= 1) and (Pa [J] <> DirSep) do
  167. Dec (J);
  168. if (J = 0)
  169. {$IFDEF FEXPAND_UNC}
  170. or (J = 1) and (I = 2)
  171. {$ENDIF FEXPAND_UNC}
  172. then
  173. Delete (Pa, Succ (I), 2)
  174. else
  175. Delete (Pa, Succ (J), I - J + 2);
  176. end;
  177. {Now remove also any reference to '\.' at the end of line}
  178. I := Pos (DirSep + '.', Pa);
  179. if (I <> 0) and (I = Pred (Length (Pa))) then
  180. if (I = PathStart)
  181. {$IFDEF FEXPAND_DRIVES}
  182. and (Pa [2] = ':')
  183. {$ENDIF FEXPAND_DRIVES}
  184. {$IFDEF FEXPAND_UNC}
  185. or (I = 2) and (Pa [1] = '\')
  186. {$ENDIF FEXPAND_UNC}
  187. then
  188. Dec (Pa [0])
  189. else
  190. Delete (Pa, I, 2);
  191. {Remove ending \ if not supplied originally, the original string
  192. wasn't empty (to stay compatible) and if not really needed}
  193. if (Length (Pa) > PathStart) and (Pa [Length (Pa)] = DirSep)
  194. and (Length (Path) <> 0) and (Path [Length (Path)] <> DirSep) then
  195. Dec (Pa [0]);
  196. FExpand := Pa;
  197. end;