2
0

fina.inc 14 KB

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