fina.inc 14 KB

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