fina.inc 14 KB

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