fina.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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. begin
  108. {$ifdef MSWINDOWS}
  109. SetLength(Result,Max_Path);
  110. if sizeof(FileName[1])=1 then
  111. SetLength(Result,GetShortPathNameA(PChar(FileName), PChar(Result),Length(Result)))
  112. else
  113. SetLength(Result,GetShortPathNameW(PWideChar(FileName), PWideChar(Result),Length(Result)));
  114. {$else}
  115. Result:=FileName;
  116. {$endif}
  117. end;
  118. {$DEFINE FPC_FEXPAND_SYSUTILS}
  119. {$I fexpand.inc}
  120. function ExpandFileName (Const FileName : PathStr): PathStr;
  121. Var S : PathStr;
  122. Begin
  123. S:=FileName;
  124. DoDirSeparators(S);
  125. Result:=Fexpand(S);
  126. end;
  127. {$ifndef HASEXPANDUNCFILENAME}
  128. function ExpandUNCFileName (Const FileName : PathStr): PathStr;
  129. begin
  130. Result:=ExpandFileName (FileName);
  131. //!! Here should follow code to replace the drive: part with UNC...
  132. end;
  133. {$endif HASEXPANDUNCFILENAME}
  134. function ExpandFileNameCase (const FileName: PathStr; out MatchFound: TFilenameCaseMatch): PathStr;
  135. var
  136. {$ifdef SYSUTILSUNICODE}
  137. SR: TUnicodeSearchRec;
  138. {$else SYSUTILSUNICODE}
  139. SR: TRawByteSearchRec;
  140. {$endif SYSUTILSUNICODE}
  141. ItemsFound: byte;
  142. FoundPath: PathStr;
  143. RestPos: SizeUInt;
  144. Root: PathStr;
  145. procedure TryCase (const Base, Rest: PathStr);
  146. var
  147. {$ifdef SYSUTILSUNICODE}
  148. SR: TUnicodeSearchRec;
  149. {$else SYSUTILSUNICODE}
  150. SR: TRawByteSearchRec;
  151. {$endif SYSUTILSUNICODE}
  152. RC: longint;
  153. NextDirPos: SizeUInt;
  154. NextPart: PathStr;
  155. NextRest: PathStr;
  156. SearchBase: PathStr;
  157. begin
  158. NextDirPos := 1;
  159. while (NextDirPos <= Length (Rest)) and
  160. not CharInSet(Rest[NextDirPos],(AllowDirectorySeparators)) do
  161. Inc (NextDirPos);
  162. NextPart := Copy (Rest, 1, Pred (NextDirPos));
  163. {$IFDEF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  164. if (Length (Rest) >= NextDirPos) and
  165. CharInSet(Rest[NextDirPos],AllowDirectorySeparators) then
  166. {$ELSE FPC_FEXPAND_DIRSEP_IS_UPDIR}
  167. while (Length (Rest) >= NextDirPos) and
  168. CharInSet(Rest[NextDirPos],AllowDirectorySeparators) do
  169. {$ENDIF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  170. Inc (NextDirPos);
  171. NextRest := Copy (Rest, NextDirPos, Length (Rest) - Pred (NextDirPos));
  172. if (Base = '') or CharInSet(Base[Length (Base)],AllowDirectorySeparators) then
  173. SearchBase := Base
  174. else
  175. {$ifdef SYSUTILSUNICODE}
  176. SearchBase := Base + DirectorySeparator;
  177. RC := FindFirst (SearchBase + AllFilesMask, faAnyFile, SR);
  178. {$else SYSUTILSUNICODE}
  179. SearchBase := Base + ToSingleByteFileSystemEncodedFileName(DirectorySeparator);
  180. RC := FindFirst (SearchBase + ToSingleByteFileSystemEncodedFileName(AllFilesMask), faAnyFile, SR);
  181. {$endif SYSUTILSUNICODE}
  182. while (RC = 0) and (ItemsFound < 2) do
  183. begin
  184. if UpCase (NextPart) = UpCase (SR.Name) then
  185. begin
  186. if Length (NextPart) = Length (Rest) then
  187. begin
  188. Inc (ItemsFound);
  189. if ItemsFound = 1 then
  190. FoundPath := SearchBase + SR.Name;
  191. end
  192. else if SR.Attr and faDirectory = faDirectory then
  193. {$ifdef SYSUTILSUNICODE}
  194. TryCase (SearchBase + SR.Name + DirectorySeparator, NextRest);
  195. {$else SYSUTILSUNICODE}
  196. TryCase (SearchBase + SR.Name + ToSingleByteFileSystemEncodedFileName(DirectorySeparator), NextRest);
  197. {$endif SYSUTILSUNICODE}
  198. end;
  199. if ItemsFound < 2 then
  200. RC := FindNext (SR);
  201. end;
  202. FindClose (SR);
  203. end;
  204. begin
  205. Result := ExpandFileName (FileName);
  206. if FileName = '' then
  207. MatchFound := mkExactMatch
  208. else
  209. if (FindFirst (FileName, faAnyFile, SR) = 0) or
  210. (* Special check for a root directory or a directory with a trailing slash *)
  211. (* which are not found using FindFirst. *)
  212. DirectoryExists (FileName) then
  213. begin
  214. MatchFound := mkExactMatch;
  215. Result := ExtractFilePath (Result) + SR.Name;
  216. FindClose (SR);
  217. end
  218. else
  219. begin
  220. (* Better close the search handle here before starting the recursive search *)
  221. FindClose (SR);
  222. MatchFound := mkNone;
  223. if FileNameCaseSensitive then
  224. begin
  225. ItemsFound := 0;
  226. FoundPath := '';
  227. RestPos := Length (ExtractFileDrive (FileName)) + 1;
  228. if (Length (FileName) > RestPos) then
  229. begin
  230. {$IFDEF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  231. if (Length (FileName) >= RestPos) and
  232. CharInSet(FileName[RestPos],AllowDirectorySeparators) then
  233. {$ELSE FPC_FEXPAND_DIRSEP_IS_UPDIR}
  234. while (Length (FileName) >= RestPos) and
  235. CharInSet(FileName[RestPos],AllowDirectorySeparators) do
  236. {$ENDIF FPC_FEXPAND_DIRSEP_IS_UPDIR}
  237. Inc (RestPos);
  238. Root := Copy (FileName, 1, Pred (RestPos));
  239. TryCase (Root, Copy (FileName, RestPos, Length (FileName) - Length (Root)));
  240. if ItemsFound > 0 then
  241. begin
  242. Result := ExpandFileName (FoundPath);
  243. if ItemsFound = 1 then
  244. MatchFound := mkSingleMatch
  245. else
  246. MatchFound := mkAmbiguous;
  247. end;
  248. end;
  249. end;
  250. end;
  251. end;
  252. {$if not declared(MaxDirs)}
  253. Const
  254. MaxDirs = 129;
  255. {$endif}
  256. function ExtractRelativepath (Const BaseName,DestName : PathStr): PathStr;
  257. Var Source, Dest : PathStr;
  258. Sc,Dc,I,J
  259. {$ifndef SYSUTILSUNICODE}
  260. ,Len, NewLen
  261. {$endif not SYSUTILSUNICODE}
  262. : Longint;
  263. SD,DD : Array[1..MaxDirs] of PathPChar;
  264. Const OneLevelBack = '..'+DirectorySeparator;
  265. begin
  266. If Uppercase(ExtractFileDrive(BaseName))<>Uppercase(ExtractFileDrive(DestName)) Then
  267. begin
  268. Result:=DestName;
  269. exit;
  270. end;
  271. Source:=ExcludeTrailingPathDelimiter(ExtractFilePath(BaseName));
  272. Dest:=ExcludeTrailingPathDelimiter(ExtractFilePath(DestName));
  273. SC:=GetDirs (Source,SD);
  274. DC:=GetDirs (Dest,DD);
  275. I:=1;
  276. While (I<=DC) and (I<=SC) do
  277. begin
  278. If StrIcomp(DD[i],SD[i])=0 then
  279. Inc(i)
  280. else
  281. Break;
  282. end;
  283. Result:='';
  284. {$ifdef SYSUTILSUNICODE}
  285. For J:=I to SC do Result:=Result+OneLevelBack;
  286. For J:=I to DC do Result:=Result+DD[J]+DirectorySeparator;
  287. {$else SYSUTILSUNICODE}
  288. { prevent conversion to DefaultSystemCodePage due to concatenation of
  289. constant string -- and optimise a little by reducing the numher of
  290. setlength cals }
  291. if SC>=I then
  292. begin
  293. Len:=Length(Result);
  294. SetLength(Result,Len+(SC-I+1)*Length(OneLevelBack));
  295. For J:=0 to SC-I do
  296. move(shortstring(OneLevelBack)[1],Result[Len+1+J*Length(OneLevelBack)],Length(OneLevelBack));
  297. end;
  298. if DC>=I then
  299. begin
  300. Len:=Length(Result);
  301. NewLen:=Len+(DC-I+1)*sizeof(ansichar);
  302. For J:=I to DC do
  303. Inc(NewLen,Length(DD[J]));
  304. SetLength(Result,NewLen);
  305. For J:=I to DC do
  306. begin
  307. NewLen:=Length(DD[J]);
  308. Move(DD[J][0],Result[Len+1],NewLen);
  309. inc(Len,NewLen);
  310. Result[Len+1]:=DirectorySeparator;
  311. Inc(Len);
  312. end;
  313. end;
  314. {$endif SYSUTILSUNICODE}
  315. Result:=Result+ExtractFileName(DestName);
  316. end;
  317. Procedure DoDirSeparators (Var FileName : PathStr); {$ifdef FPC_HAS_CPSTRING}rtlproc;{$endif}
  318. VAr I : longint;
  319. begin
  320. For I:=1 to Length(FileName) do
  321. If CharInSet(FileName[I],AllowDirectorySeparators) then
  322. FileName[i]:=DirectorySeparator;
  323. end;
  324. Function SetDirSeparators (Const FileName : PathStr) : PathStr;
  325. begin
  326. Result:=FileName;
  327. DoDirSeparators (Result);
  328. end;
  329. {
  330. DirName is split in a #0 separated list of directory names,
  331. Dirs is an array of pchars, pointing to these directory names.
  332. The function returns the number of directories found, or -1
  333. if none were found.
  334. }
  335. Function GetDirs (Var DirName : PathStr; Var Dirs : Array of PathPChar) : Longint; {$ifdef FPC_HAS_CPSTRING}rtlproc;{$endif}
  336. Var I : Longint;
  337. begin
  338. I:=1;
  339. Result:=-1;
  340. While I<=Length(DirName) do
  341. begin
  342. If CharInSet(DirName[i],AllowDirectorySeparators) and
  343. { avoid error in case last char=pathdelim }
  344. (length(dirname)>i) then
  345. begin
  346. DirName[i]:=#0;
  347. Inc(Result);
  348. Dirs[Result]:=@DirName[I+1];
  349. end;
  350. Inc(I);
  351. end;
  352. If Result>-1 then inc(Result);
  353. end;
  354. function IncludeTrailingPathDelimiter(Const Path : PathStr) : PathStr;
  355. Var
  356. l : Integer;
  357. begin
  358. Result:=Path;
  359. l:=Length(Result);
  360. If (L=0) or not CharInSet(Result[l],AllowDirectorySeparators) then
  361. {$ifdef SYSUTILSUNICODE}
  362. Result:=Result+DirectorySeparator;
  363. {$else SYSUTILSUNICODE}
  364. begin
  365. SetLength(Result,l+1);
  366. Result[l+1]:=DirectorySeparator;
  367. end;
  368. {$endif SYSUTILSUNICODE}
  369. end;
  370. function IncludeTrailingBackslash(Const Path : PathStr) : PathStr;
  371. begin
  372. Result:=IncludeTrailingPathDelimiter(Path);
  373. end;
  374. function ExcludeTrailingBackslash(Const Path: PathStr): PathStr;
  375. begin
  376. Result:=ExcludeTrailingPathDelimiter(Path);
  377. end;
  378. function ExcludeTrailingPathDelimiter(Const Path: PathStr): PathStr;
  379. Var
  380. L : Integer;
  381. begin
  382. L:=Length(Path);
  383. If (L>0) and CharInSet(Path[L],AllowDirectorySeparators) then
  384. Dec(L);
  385. Result:=Copy(Path,1,L);
  386. end;
  387. function IncludeLeadingPathDelimiter(Const Path : PathStr) : PathStr;
  388. Var
  389. l : Integer;
  390. begin
  391. Result:=Path;
  392. l:=Length(Result);
  393. If (L=0) or not CharInSet(Result[1],AllowDirectorySeparators) then
  394. {$ifdef SYSUTILSUNICODE}
  395. Result:=DirectorySeparator+Result;
  396. {$else SYSUTILSUNICODE}
  397. begin
  398. SetLength(Result,l+1);
  399. Move(Result[1],Result[2],l);
  400. Result[1]:=DirectorySeparator;
  401. end;
  402. {$endif SYSUTILSUNICODE}
  403. end;
  404. function ExcludeLeadingPathDelimiter(Const Path: PathStr): PathStr;
  405. Var
  406. L : Integer;
  407. begin
  408. Result:=Path;
  409. L:=Length(Result);
  410. If (L>0) and CharInSet(Result[1],AllowDirectorySeparators) then
  411. Delete(Result,1,1);
  412. end;
  413. function IsPathDelimiter(Const Path: PathStr; Index: Integer): Boolean;
  414. begin
  415. Result:=(Index>0) and (Index<=Length(Path)) and CharInSet(Path[Index],AllowDirectorySeparators);
  416. end;
  417. function ConcatPaths(const Paths: array of PathStr): PathStr;
  418. var
  419. I: Integer;
  420. begin
  421. if Length(Paths) > 0 then
  422. begin
  423. Result := Paths[0];
  424. for I := 1 to Length(Paths) - 1 do
  425. Result := IncludeTrailingPathDelimiter(Result) + ExcludeLeadingPathDelimiter(Paths[I]);
  426. end else
  427. Result := '';
  428. end;