fina.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. {
  2. *********************************************************************
  3. Copyright (C) 1997, 1998 Gertjan Schouten
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************
  10. System Utilities For Free Pascal
  11. }
  12. function ChangeFileExt(const FileName, Extension: PathStr): PathStr;
  13. var
  14. i : longint;
  15. EndSep : Set of Char;
  16. begin
  17. i := Length(FileName);
  18. EndSep:=AllowDirectorySeparators+AllowDriveSeparators+[ExtensionSeparator];
  19. while (I > 0) and not(FileName[I] in EndSep) do
  20. Dec(I);
  21. if (I = 0) or (FileName[I] <> ExtensionSeparator) then
  22. I := Length(FileName)+1;
  23. Result := Copy(FileName, 1, I - 1) + Extension;
  24. end;
  25. function ExtractFilePath(const FileName: PathStr): PathStr;
  26. var
  27. i : longint;
  28. EndSep : Set of Char;
  29. begin
  30. i := Length(FileName);
  31. EndSep:=AllowDirectorySeparators+AllowDriveSeparators;
  32. while (i > 0) and not CharInSet(FileName[i],EndSep) do
  33. Dec(i);
  34. If I>0 then
  35. Result := Copy(FileName, 1, i)
  36. else
  37. Result:='';
  38. end;
  39. function ExtractFileDir(const FileName: PathStr): PathStr;
  40. var
  41. i : longint;
  42. EndSep : Set of Char;
  43. begin
  44. I := Length(FileName);
  45. EndSep:=AllowDirectorySeparators+AllowDriveSeparators;
  46. while (I > 0) and not CharInSet(FileName[I],EndSep) do
  47. Dec(I);
  48. if (I > 1) and CharInSet(FileName[I],AllowDirectorySeparators) and
  49. not CharInSet(FileName[I - 1],EndSep) then
  50. Dec(I);
  51. Result := Copy(FileName, 1, I);
  52. end;
  53. function ExtractFileDrive(const FileName: PathStr): PathStr;
  54. var
  55. i,l: longint;
  56. begin
  57. Result := '';
  58. l:=Length(FileName);
  59. if (l<2) then
  60. exit;
  61. {$IF DEFINED(AMIGA) OR DEFINED(MORPHOS)}
  62. i:=Pos(DriveSeparator,FileName);
  63. if (i > 0) then Result:=Copy(FileName,1,i);
  64. {$ELSE}
  65. If CharInSet(FileName[2],AllowDriveSeparators) then
  66. result:=Copy(FileName,1,2)
  67. else if CharInSet(FileName[1],AllowDirectorySeparators) and
  68. CharInSet(FileName[2],AllowDirectorySeparators) then
  69. begin
  70. i := 2;
  71. { skip share }
  72. While (i<l) and Not CharInSet(Filename[i+1],AllowDirectorySeparators) do
  73. inc(i);
  74. inc(i);
  75. While (i<l) and Not CharInSet(Filename[i+1],AllowDirectorySeparators) do
  76. inc(i);
  77. Result:=Copy(FileName,1,i);
  78. end;
  79. {$ENDIF}
  80. end;
  81. function ExtractFileName(const FileName: PathStr): PathStr;
  82. var
  83. i : longint;
  84. EndSep : Set of Char;
  85. begin
  86. I := Length(FileName);
  87. EndSep:=AllowDirectorySeparators+AllowDriveSeparators;
  88. while (I > 0) and not CharInSet(FileName[I],EndSep) do
  89. Dec(I);
  90. Result := Copy(FileName, I + 1, MaxInt);
  91. end;
  92. function ExtractFileExt(const FileName: PathStr): PathStr;
  93. var
  94. i : longint;
  95. EndSep : Set of Char;
  96. begin
  97. I := Length(FileName);
  98. EndSep:=AllowDirectorySeparators+AllowDriveSeparators+[ExtensionSeparator];
  99. while (I > 0) and not CharInSet(FileName[I],EndSep) do
  100. Dec(I);
  101. if (I > 0) and (FileName[I] = ExtensionSeparator) then
  102. Result := Copy(FileName, I, MaxInt)
  103. else
  104. Result := '';
  105. end;
  106. function ExtractShortPathName(Const FileName : PathStr) : PathStr;
  107. {$if defined(MSWINDOWS) and not defined(SYSUTILSUNICODE)}
  108. var
  109. TempFile, TempResult: UnicodeString;
  110. {$endif}
  111. begin
  112. {$ifdef MSWINDOWS}
  113. {$if not defined(SYSUTILSUNICODE)}
  114. TempFile:=FileName;
  115. SetLength(TempResult,Max_Path);
  116. SetLength(TempResult,GetShortPathNameW(PWideChar(TempFile), PWideChar(TempResult),Length(TempResult)));
  117. widestringmanager.Unicode2AnsiMoveProc(PWideChar(TempResult),Result,DefaultRTLFileSystemCodePage,Length(TempResult));
  118. {$else not SYSUTILSUNICODE}
  119. SetLength(Result,Max_Path);
  120. SetLength(Result,GetShortPathNameW(PWideChar(FileName), PWideChar(Result),Length(Result)));
  121. {$endif not SYSUTILSUNICODE}
  122. {$else MSWindows}
  123. Result:=FileName;
  124. {$endif MSWindows}
  125. end;
  126. {$DEFINE FPC_FEXPAND_SYSUTILS}
  127. {$I fexpand.inc}
  128. function ExpandFileName (Const FileName : PathStr): PathStr;
  129. Var S : PathStr;
  130. Begin
  131. S:=FileName;
  132. DoDirSeparators(S);
  133. Result:=Fexpand(S);
  134. end;
  135. {$ifndef HASEXPANDUNCFILENAME}
  136. function ExpandUNCFileName (Const FileName : PathStr): PathStr;
  137. begin
  138. Result:=ExpandFileName (FileName);
  139. //!! Here should follow code to replace the drive: part with UNC...
  140. end;
  141. {$endif HASEXPANDUNCFILENAME}
  142. function ExpandFileNameCase (const FileName: PathStr; out MatchFound: TFilenameCaseMatch): PathStr;
  143. var
  144. {$ifdef SYSUTILSUNICODE}
  145. SR: TUnicodeSearchRec;
  146. {$else SYSUTILSUNICODE}
  147. SR: TRawByteSearchRec;
  148. {$endif SYSUTILSUNICODE}
  149. ItemsFound: byte;
  150. FoundPath: PathStr;
  151. RestPos: SizeUInt;
  152. Root: PathStr;
  153. procedure TryCase (const Base, Rest: PathStr);
  154. var
  155. {$ifdef SYSUTILSUNICODE}
  156. SR: TUnicodeSearchRec;
  157. {$else SYSUTILSUNICODE}
  158. SR: TRawByteSearchRec;
  159. {$endif SYSUTILSUNICODE}
  160. RC: longint;
  161. NextDirPos: SizeUInt;
  162. NextPart: PathStr;
  163. NextRest: PathStr;
  164. SearchBase: PathStr;
  165. begin
  166. NextDirPos := 1;
  167. while (NextDirPos <= Length (Rest)) and
  168. not CharInSet(Rest[NextDirPos],(AllowDirectorySeparators)) do
  169. Inc (NextDirPos);
  170. NextPart := Copy (Rest, 1, Pred (NextDirPos));
  171. {$IFDEF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  172. if (Length (Rest) >= NextDirPos) and
  173. CharInSet(Rest[NextDirPos],AllowDirectorySeparators) then
  174. {$ELSE FPC_FEXPAND_DIRSEP_IS_UPDIR}
  175. while (Length (Rest) >= NextDirPos) and
  176. CharInSet(Rest[NextDirPos],AllowDirectorySeparators) do
  177. {$ENDIF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  178. Inc (NextDirPos);
  179. NextRest := Copy (Rest, NextDirPos, Length (Rest) - Pred (NextDirPos));
  180. if (Base = '') or CharInSet(Base[Length (Base)],AllowDirectorySeparators) then
  181. SearchBase := Base
  182. else
  183. {$ifdef SYSUTILSUNICODE}
  184. SearchBase := Base + DirectorySeparator;
  185. RC := FindFirst (SearchBase + AllFilesMask, faAnyFile, SR);
  186. {$else SYSUTILSUNICODE}
  187. SearchBase := Base + ToSingleByteFileSystemEncodedFileName(DirectorySeparator);
  188. RC := FindFirst (SearchBase + ToSingleByteFileSystemEncodedFileName(AllFilesMask), faAnyFile, SR);
  189. {$endif SYSUTILSUNICODE}
  190. while (RC = 0) and (ItemsFound < 2) do
  191. begin
  192. if UpCase (NextPart) = UpCase (SR.Name) then
  193. begin
  194. if Length (NextPart) = Length (Rest) then
  195. begin
  196. Inc (ItemsFound);
  197. if ItemsFound = 1 then
  198. FoundPath := SearchBase + SR.Name;
  199. end
  200. else if SR.Attr and faDirectory = faDirectory then
  201. {$ifdef SYSUTILSUNICODE}
  202. TryCase (SearchBase + SR.Name + DirectorySeparator, NextRest);
  203. {$else SYSUTILSUNICODE}
  204. TryCase (SearchBase + SR.Name + ToSingleByteFileSystemEncodedFileName(DirectorySeparator), NextRest);
  205. {$endif SYSUTILSUNICODE}
  206. end;
  207. if ItemsFound < 2 then
  208. RC := FindNext (SR);
  209. end;
  210. FindClose (SR);
  211. end;
  212. begin
  213. Result := ExpandFileName (FileName);
  214. if FileName = '' then
  215. MatchFound := mkExactMatch
  216. else
  217. if (FindFirst (FileName, faAnyFile, SR) = 0) or
  218. (* Special check for a root directory or a directory with a trailing slash *)
  219. (* which are not found using FindFirst. *)
  220. DirectoryExists (FileName) then
  221. begin
  222. MatchFound := mkExactMatch;
  223. Result := ExtractFilePath (Result) + SR.Name;
  224. FindClose (SR);
  225. end
  226. else
  227. begin
  228. (* Better close the search handle here before starting the recursive search *)
  229. FindClose (SR);
  230. MatchFound := mkNone;
  231. if FileNameCaseSensitive then
  232. begin
  233. ItemsFound := 0;
  234. FoundPath := '';
  235. RestPos := Length (ExtractFileDrive (FileName)) + 1;
  236. if (Length (FileName) > RestPos) then
  237. begin
  238. {$IFDEF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  239. if (Length (FileName) >= RestPos) and
  240. CharInSet(FileName[RestPos],AllowDirectorySeparators) then
  241. {$ELSE FPC_FEXPAND_DIRSEP_IS_UPDIR}
  242. while (Length (FileName) >= RestPos) and
  243. CharInSet(FileName[RestPos],AllowDirectorySeparators) do
  244. {$ENDIF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  245. Inc (RestPos);
  246. Root := Copy (FileName, 1, Pred (RestPos));
  247. TryCase (Root, Copy (FileName, RestPos, Length (FileName) - Length (Root)));
  248. if ItemsFound > 0 then
  249. begin
  250. Result := ExpandFileName (FoundPath);
  251. if ItemsFound = 1 then
  252. MatchFound := mkSingleMatch
  253. else
  254. MatchFound := mkAmbiguous;
  255. end;
  256. end;
  257. end;
  258. end;
  259. end;
  260. {$if not declared(MaxDirs)}
  261. Const
  262. MaxDirs = 129;
  263. {$endif}
  264. function ExtractRelativepath (Const BaseName,DestName : PathStr): PathStr;
  265. Var Source, Dest : PathStr;
  266. Sc,Dc,I,J
  267. {$ifndef SYSUTILSUNICODE}
  268. ,Len, NewLen
  269. {$endif not SYSUTILSUNICODE}
  270. : Longint;
  271. SD,DD : Array[1..MaxDirs] of PathPChar;
  272. Const OneLevelBack = '..'+DirectorySeparator;
  273. begin
  274. If Uppercase(ExtractFileDrive(BaseName))<>Uppercase(ExtractFileDrive(DestName)) Then
  275. begin
  276. Result:=DestName;
  277. exit;
  278. end;
  279. Source:=ExcludeTrailingPathDelimiter(ExtractFilePath(BaseName));
  280. Dest:=ExcludeTrailingPathDelimiter(ExtractFilePath(DestName));
  281. SC:=GetDirs (Source,SD);
  282. DC:=GetDirs (Dest,DD);
  283. I:=1;
  284. While (I<=DC) and (I<=SC) do
  285. begin
  286. If StrIcomp(DD[i],SD[i])=0 then
  287. Inc(i)
  288. else
  289. Break;
  290. end;
  291. Result:='';
  292. {$ifdef SYSUTILSUNICODE}
  293. For J:=I to SC do Result:=Result+OneLevelBack;
  294. For J:=I to DC do Result:=Result+DD[J]+DirectorySeparator;
  295. {$else SYSUTILSUNICODE}
  296. { prevent conversion to DefaultSystemCodePage due to concatenation of
  297. constant string -- and optimise a little by reducing the numher of
  298. setlength cals }
  299. if SC>=I then
  300. begin
  301. Len:=Length(Result);
  302. SetLength(Result,Len+(SC-I+1)*Length(OneLevelBack));
  303. For J:=0 to SC-I do
  304. move(shortstring(OneLevelBack)[1],Result[Len+1+J*Length(OneLevelBack)],Length(OneLevelBack));
  305. end;
  306. if DC>=I then
  307. begin
  308. Len:=Length(Result);
  309. NewLen:=Len+(DC-I+1)*sizeof(ansichar);
  310. For J:=I to DC do
  311. Inc(NewLen,Length(DD[J]));
  312. SetLength(Result,NewLen);
  313. For J:=I to DC do
  314. begin
  315. NewLen:=Length(DD[J]);
  316. Move(DD[J][0],Result[Len+1],NewLen);
  317. inc(Len,NewLen);
  318. Result[Len+1]:=DirectorySeparator;
  319. Inc(Len);
  320. end;
  321. end;
  322. {$endif SYSUTILSUNICODE}
  323. Result:=Result+ExtractFileName(DestName);
  324. end;
  325. Procedure DoDirSeparators (Var FileName : PathStr); {$ifdef FPC_HAS_CPSTRING}rtlproc;{$endif}
  326. VAr I : longint;
  327. begin
  328. For I:=1 to Length(FileName) do
  329. If CharInSet(FileName[I],AllowDirectorySeparators) then
  330. FileName[i]:=DirectorySeparator;
  331. end;
  332. Function SetDirSeparators (Const FileName : PathStr) : PathStr;
  333. begin
  334. Result:=FileName;
  335. DoDirSeparators (Result);
  336. end;
  337. {
  338. DirName is split in a #0 separated list of directory names,
  339. Dirs is an array of pchars, pointing to these directory names.
  340. The function returns the number of directories found, or -1
  341. if none were found.
  342. }
  343. Function GetDirs (Var DirName : PathStr; Var Dirs : Array of PathPChar) : Longint; {$ifdef FPC_HAS_CPSTRING}rtlproc;{$endif}
  344. Var I : Longint;
  345. begin
  346. I:=1;
  347. Result:=-1;
  348. While I<=Length(DirName) do
  349. begin
  350. If CharInSet(DirName[i],AllowDirectorySeparators) and
  351. { avoid error in case last char=pathdelim }
  352. (length(dirname)>i) then
  353. begin
  354. DirName[i]:=#0;
  355. Inc(Result);
  356. Dirs[Result]:=@DirName[I+1];
  357. end;
  358. Inc(I);
  359. end;
  360. If Result>-1 then inc(Result);
  361. end;
  362. function IncludeTrailingPathDelimiter(Const Path : PathStr) : PathStr;
  363. Var
  364. l : Integer;
  365. begin
  366. Result:=Path;
  367. l:=Length(Result);
  368. If (L=0) or not CharInSet(Result[l],AllowDirectorySeparators) then
  369. {$ifdef SYSUTILSUNICODE}
  370. Result:=Result+DirectorySeparator;
  371. {$else SYSUTILSUNICODE}
  372. begin
  373. SetLength(Result,l+1);
  374. Result[l+1]:=DirectorySeparator;
  375. end;
  376. {$endif SYSUTILSUNICODE}
  377. end;
  378. function IncludeTrailingBackslash(Const Path : PathStr) : PathStr;
  379. begin
  380. Result:=IncludeTrailingPathDelimiter(Path);
  381. end;
  382. function ExcludeTrailingBackslash(Const Path: PathStr): PathStr;
  383. begin
  384. Result:=ExcludeTrailingPathDelimiter(Path);
  385. end;
  386. function ExcludeTrailingPathDelimiter(Const Path: PathStr): PathStr;
  387. Var
  388. L : Integer;
  389. begin
  390. L:=Length(Path);
  391. If (L>0) and CharInSet(Path[L],AllowDirectorySeparators) then
  392. Dec(L);
  393. Result:=Copy(Path,1,L);
  394. end;
  395. function IncludeLeadingPathDelimiter(Const Path : PathStr) : PathStr;
  396. Var
  397. l : Integer;
  398. begin
  399. Result:=Path;
  400. l:=Length(Result);
  401. If (L=0) or not CharInSet(Result[1],AllowDirectorySeparators) then
  402. {$ifdef SYSUTILSUNICODE}
  403. Result:=DirectorySeparator+Result;
  404. {$else SYSUTILSUNICODE}
  405. begin
  406. SetLength(Result,l+1);
  407. Move(Result[1],Result[2],l);
  408. Result[1]:=DirectorySeparator;
  409. end;
  410. {$endif SYSUTILSUNICODE}
  411. end;
  412. function ExcludeLeadingPathDelimiter(Const Path: PathStr): PathStr;
  413. Var
  414. L : Integer;
  415. begin
  416. Result:=Path;
  417. L:=Length(Result);
  418. If (L>0) and CharInSet(Result[1],AllowDirectorySeparators) then
  419. Delete(Result,1,1);
  420. end;
  421. function IsPathDelimiter(Const Path: PathStr; Index: Integer): Boolean;
  422. begin
  423. Result:=(Index>0) and (Index<=Length(Path)) and CharInSet(Path[Index],AllowDirectorySeparators);
  424. end;
  425. function ConcatPaths(const Paths: array of PathStr): PathStr;
  426. var
  427. I: Integer;
  428. begin
  429. if Length(Paths) > 0 then
  430. begin
  431. Result := Paths[0];
  432. for I := 1 to Length(Paths) - 1 do
  433. Result := IncludeTrailingPathDelimiter(Result) + ExcludeLeadingPathDelimiter(Paths[I]);
  434. end else
  435. Result := '';
  436. end;