fina.inc 14 KB

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