fina.inc 14 KB

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