2
0

fina.inc 14 KB

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