fina.inc 14 KB

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