21
24
function CompareFilenames(const Filename1, Filename2: string): integer;
22
25
function CompareFilenamesIgnoreCase(const Filename1, Filename2: string): integer;
23
26
function CompareFileExt(const Filename, Ext: string;
24
CaseSensitive: boolean): integer;
27
CaseSensitive: boolean): integer; overload;
28
function CompareFileExt(const Filename, Ext: string): integer; overload;
25
30
function CompareFilenameStarts(const Filename1, Filename2: string): integer;
26
31
function CompareFilenames(Filename1: PChar; Len1: integer;
27
32
Filename2: PChar; Len2: integer): integer;
33
function CompareFilenamesP(Filename1, Filename2: PChar;
34
IgnoreCase: boolean = false // false = use default
28
37
function DirPathExists(DirectoryName: string): boolean;
29
38
function DirectoryIsWritable(const DirectoryName: string): boolean;
30
39
function ExtractFileNameOnly(const AFilename: string): string;
41
53
function FilenameIsTrimmed(const TheFilename: string): boolean;
42
54
function FilenameIsTrimmed(StartPos: PChar; NameLen: integer): boolean;
43
55
function TrimFilename(const AFilename: string): string;
56
function ResolveDots(const AFilename: string): string;
57
Procedure ForcePathDelims(Var FileName: string);
58
Function GetForcedPathDelims(Const FileName: string): String;
44
59
function CleanAndExpandFilename(const Filename: string): string; // empty string returns current directory
45
60
function CleanAndExpandDirectory(const Filename: string): string; // empty string returns current directory
46
61
function TrimAndExpandFilename(const Filename: string; const BaseDir: string = ''): string; // empty string returns empty string
47
62
function TrimAndExpandDirectory(const Filename: string; const BaseDir: string = ''): string; // empty string returns empty string
63
function TryCreateRelativePath(const Dest, Source: String; UsePointDirectory: boolean;
64
AlwaysRequireSharedBaseFolder: Boolean; out RelPath: String): Boolean;
48
65
function CreateRelativePath(const Filename, BaseDirectory: string;
49
UsePointDirectory: boolean = false): string;
66
UsePointDirectory: boolean = false; AlwaysRequireSharedBaseFolder: Boolean = True): string;
50
67
function FileIsInPath(const Filename, Path: string): boolean;
51
68
function AppendPathDelim(const Path: string): string;
52
69
function ChompPathDelim(const Path: string): string;
62
79
function FileExistsUTF8(const Filename: string): boolean;
63
80
function FileAgeUTF8(const FileName: string): Longint;
64
81
function DirectoryExistsUTF8(const Directory: string): Boolean;
65
function ExpandFileNameUTF8(const FileName: string; const BaseDir: string = ''): string;
82
function ExpandFileNameUTF8(const FileName: string; {const} BaseDir: string = ''): string;
66
83
function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint;
67
84
function FindNextUTF8(var Rslt: TSearchRec): Longint;
68
procedure FindCloseUTF8(var F: TSearchrec);
85
procedure FindCloseUTF8(var F: TSearchrec); inline;
69
86
function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;
70
87
function FileGetAttrUTF8(const FileName: String): Longint;
71
88
function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;
72
89
function DeleteFileUTF8(const FileName: String): Boolean;
73
90
function RenameFileUTF8(const OldName, NewName: String): Boolean;
74
function FileSearchUTF8(const Name, DirList : String): String;
91
function FileSearchUTF8(const Name, DirList : String; ImplicitCurrentDir : Boolean = True): String;
75
92
function FileIsReadOnlyUTF8(const FileName: String): Boolean;
76
93
function GetCurrentDirUTF8: String;
77
94
function SetCurrentDirUTF8(const NewDir: String): Boolean;
79
96
function RemoveDirUTF8(const Dir: String): Boolean;
80
97
function ForceDirectoriesUTF8(const Dir: string): Boolean;
99
function FileOpenUTF8(Const FileName : string; Mode : Integer) : THandle;
100
function FileCreateUTF8(Const FileName : string) : THandle; overload;
101
function FileCreateUTF8(Const FileName : string; Rights: Cardinal) : THandle; overload;
102
Function FileCreateUtf8(Const FileName : String; ShareMode : Integer; Rights : Cardinal) : THandle; overload;
104
function FileSizeUtf8(const Filename: string): int64;
105
function GetFileDescription(const AFilename: string): string;
108
function GetAppConfigDirUTF8(Global: Boolean; Create: boolean = false): string;
109
function GetAppConfigFileUTF8(Global: Boolean; SubDir: boolean = false;
110
CreateDir: boolean = false): string;
111
function GetTempFileNameUTF8(const Dir, Prefix: String): String;
83
114
function IsUNCPath(const {%H-}Path: String): Boolean;
84
115
function ExtractUNCVolume(const {%H-}Path: String): String;
116
function ExtractFileRoot(FileName: String): String;
120
function GetDarwinSystemFilename(Filename: string): string;
123
procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
124
ReadBackslash: boolean = false);
125
function StrToCmdLineParam(const Param: string): string;
126
function MergeCmdLineParams(ParamList: TStrings): string;
87
129
TInvalidateFileStateCacheEvent = procedure(const Filename: string);
151
function CompareFileExt(const Filename, Ext: string;
152
CaseSensitive: boolean): integer;
200
function CompareFileExt(const Filename, Ext: string; CaseSensitive: boolean): integer;
201
// Ext can contain a point or not
154
204
FileLen, FilePos, ExtLen, ExtPos: integer;
155
FileChar, ExtChar: char;
157
FileLen:=length(Filename);
206
FileLen := length(Filename);
207
ExtLen := length(Ext);
160
209
while (FilePos>=1) and (Filename[FilePos]<>'.') do dec(FilePos);
161
if FilePos<1 then begin
210
if FilePos < 1 then begin
162
211
// no extension in filename
169
if (ExtPos<=ExtLen) and (Ext[1]='.') then inc(ExtPos);
218
if (ExtPos <= ExtLen) and (Ext[1] = '.') then inc(ExtPos);
170
220
// compare extensions
172
if FilePos<=FileLen then begin
173
if ExtPos<=ExtLen then begin
174
FileChar:=Filename[FilePos];
175
ExtChar:=Ext[ExtPos];
176
if not CaseSensitive then begin
177
FileChar:=FPUpChars[FileChar];
178
ExtChar:=FPUpChars[ExtChar];
180
if FileChar=ExtChar then begin
183
end else if FileChar>ExtChar then begin
191
// fileext longer than ext
196
if ExtPos<=ExtLen then begin
197
// fileext shorter than ext
209
function FileIsExecutable(const AFilename: string): boolean;
216
Result:=FileExistsUTF8(AFilename);
218
// first check AFilename is not a directory and then check if executable
219
Result:= (FpStat(AFilename,info{%H-})<>-1) and FPS_ISREG(info.st_mode) and
220
(BaseUnix.FpAccess(AFilename,BaseUnix.X_OK)=0);
224
procedure CheckIfFileIsExecutable(const AFilename: string);
229
// TProcess does not report, if a program can not be executed
230
// to get good error messages consider the OS
231
if not FileExistsUTF8(AFilename) then begin
232
raise Exception.CreateFmt(ctsFileDoesNotExist,[AFilename]);
235
if not(BaseUnix.FpAccess(AFilename,BaseUnix.X_OK)=0) then
237
AText:='"'+AFilename+'"';
240
AText:='read access denied for '+AText;
242
AText:='a directory component in '+AText
243
+' does not exist or is a dangling symlink';
245
AText:='a directory component in '+Atext+' is not a directory';
247
AText:='insufficient memory';
249
AText:=AText+' has a circular symbolic link';
251
AText:=Format(ctsFileIsNotExecutable,[AText]);
253
raise Exception.Create(AText);
257
// ToDo: windows and xxxbsd
221
n := Copy(Filename, FilePos, length(FileName));
222
e := Copy(Ext, ExtPos, length(Ext));
223
if CaseSensitive then
224
Result := CompareStr(n, e)
226
Result := UTF8CompareText(n, e);
230
if Result > 0 then Result := 1;
233
function CompareFileExt(const Filename, Ext: string): integer;
235
Result := CompareFileExt(Filename, Ext, False);
260
238
function ExtractFileNameOnly(const AFilename: string): string;
263
// beware: filename.ext1.ext2
264
Result:=ExtractFilename(AFilename);
265
ExtLen:=length(ExtractFileExt(Result));
266
Result:=copy(Result,1,length(Result)-ExtLen);
269
function FilenameIsAbsolute(const TheFilename: string):boolean;
273
Result:=FilenameIsWinAbsolute(TheFilename);
276
Result:=FilenameIsUnixAbsolute(TheFilename);
280
function FilenameIsWinAbsolute(const TheFilename: string): boolean;
282
Result:=((length(TheFilename)>=2) and (TheFilename[1] in ['A'..'Z','a'..'z'])
283
and (TheFilename[2]=':'))
284
or ((length(TheFilename)>=2)
285
and (TheFilename[1]='\') and (TheFilename[2]='\'));
288
function FilenameIsUnixAbsolute(const TheFilename: string): boolean;
290
Result:=(TheFilename<>'') and (TheFilename[1]='/');
243
StartPos:=length(AFilename)+1;
245
and not (AFilename[StartPos-1] in AllowDirectorySeparators)
246
{$IFDEF Windows}and (AFilename[StartPos-1]<>':'){$ENDIF}
249
ExtPos:=length(AFilename);
250
while (ExtPos>=StartPos) and (AFilename[ExtPos]<>'.') do
252
if (ExtPos<StartPos) then ExtPos:=length(AFilename)+1;
253
Result:=copy(AFilename,StartPos,ExtPos-StartPos);
328
function CompareFilenamesP(Filename1, Filename2: PChar;
329
IgnoreCase: boolean = false): integer;
334
Flags: CFStringCompareFlags;
336
File1, File2: string;
341
if (Filename1=nil) or (Filename1^=#0) then begin
342
if (Filename2=nil) or (Filename2^=#0) then begin
346
// filename1 empty, filename2 not empty
349
end else if (Filename2=nil) or (Filename2^=#0) then begin
350
// filename1 not empty, filename2 empty
354
{$IFDEF CaseInsensitiveFilenames}
355
// this platform is by default case insensitive
359
F1:=CFStringCreateWithCString(nil,Pointer(Filename1),kCFStringEncodingUTF8);
360
F2:=CFStringCreateWithCString(nil,Pointer(Filename2),kCFStringEncodingUTF8);
361
Flags:=kCFCompareNonliteral;
362
if IgnoreCase then Flags+=kCFCompareCaseInsensitive;
363
Result:=CFStringCompare(F1,F2,Flags);
367
if IgnoreCase then begin
368
// compare case insensitive
369
Len1:=StrLen(Filename1);
370
SetLength(File1,Len1);
371
System.Move(Filename1^,File1[1],Len1);
372
Len2:=StrLen(Filename2);
373
SetLength(File2,Len2);
374
System.Move(Filename2^,File2[1],Len2);
375
Result:=UTF8CompareText(File1,File2);
378
while (Filename1^=Filename2^) and (Filename1^<>#0) do begin
382
Result:=ord(Filename1^)-ord(Filename2^);
365
387
function DirPathExists(DirectoryName: string): boolean;
367
389
Result:=DirectoryExistsUTF8(ChompPathDelim(DirectoryName));
517
520
// check trailing spaces
518
521
if StartPos[NameLen-1]=' ' then exit;
519
522
// check ./ at start
520
if (StartPos[0]='.') and (StartPos[1]=PathDelim) then exit;
523
if (StartPos[0]='.') and (StartPos[1] in AllowDirectorySeparators) then exit;
522
525
while i<NameLen do begin
523
if StartPos[i]<>PathDelim then
527
if not (c in AllowDirectorySeparators) then
530
if c<>PathDelim then exit;
527
532
if i=NameLen then break;
529
534
// check for double path delimiter
530
if (StartPos[i]=PathDelim) then exit;
535
if (StartPos[i] in AllowDirectorySeparators) then exit;
532
537
if (StartPos[i]='.') and (i>0) then begin
534
539
// check /./ or /. at end
535
if (StartPos[i]=PathDelim) or (i=NameLen) then exit;
540
if (StartPos[i] in AllowDirectorySeparators) or (i=NameLen) then exit;
536
541
if StartPos[i]='.' then begin
538
543
// check /../ or /.. at end
539
if (StartPos[i]=PathDelim) or (i=NameLen) then exit;
544
if (StartPos[i] in AllowDirectorySeparators) or (i=NameLen) then exit;
547
552
function TrimFilename(const AFilename: string): string;
548
// trim double path delims, heading and trailing spaces
549
// and special dirs . and ..
550
var SrcPos, DestPos, l, DirStart: integer;
553
//Trim leading and trailing spaces
554
//then call ResolveDots to trim double path delims and expand special dirs like .. and .
555
if FilenameIsTrimmed(Result) then exit;
557
l:=length(AFilename);
561
// skip trailing spaces
562
while (l>=1) and (AFilename[l]=' ') do dec(l);
564
// skip heading spaces
565
while (SrcPos<=l) and (AFilename[SrcPos]=' ') do inc(SrcPos);
567
// trim double path delimiters and special dirs . and ..
568
while (SrcPos<=l) do begin
569
c:=AFilename[SrcPos];
570
// check for double path delims
571
if (c=PathDelim) then begin
578
and (Result[DestPos-1]=PathDelim) then begin
579
// skip second PathDelim
586
// check for special dirs . and ..
587
if (c='.') then begin
588
if (SrcPos<l) then begin
589
if (AFilename[SrcPos+1]=PathDelim)
590
and ((DestPos=1) or (AFilename[SrcPos-1]=PathDelim)) then begin
595
end else if (AFilename[SrcPos+1]='.')
596
and (SrcPos+1=l) or (AFilename[SrcPos+2]=PathDelim) then
600
// 2. /.. -> skip .., keep /
602
// 4. C:\.. -> skip .., keep C:\
603
// 5. \\.. -> skip .., keep \\
604
// 6. xxx../.. -> copy
605
// 7. xxxdir/.. -> trim dir and skip ..
606
// 8. xxxdir/.. -> trim dir and skip ..
607
if DestPos=1 then begin
609
end else if (DestPos=2) and (Result[1]=PathDelim) then begin
610
// 2. /.. -> skip .., keep /
614
end else if (DestPos=3) and (Result[2]=':')
615
and (Result[1] in ['a'..'z','A'..'Z']) then begin
617
end else if (DestPos=4) and (Result[2]=':') and (Result[3]=PathDelim)
618
and (Result[1] in ['a'..'z','A'..'Z']) then begin
619
// 4. C:\.. -> skip .., keep C:\
622
end else if (DestPos=3) and (Result[1]=PathDelim)
623
and (Result[2]=PathDelim) then begin
624
// 5. \\.. -> skip .., keep \\
628
end else if (DestPos>1) and (Result[DestPos-1]=PathDelim) then begin
630
and (Result[DestPos-2]='.') and (Result[DestPos-3]='.')
631
and ((DestPos=4) or (Result[DestPos-4]=PathDelim)) then begin
634
// 7. xxxdir/.. -> trim dir and skip ..
636
while (DirStart>1) and (Result[DirStart-1]<>PathDelim) do
639
while MacroPos<DestPos do begin
640
if (Result[MacroPos]='$')
641
and (Result[MacroPos+1] in ['(','a'..'z','A'..'Z']) then begin
642
// 8. directory contains a macro -> keep
647
if MacroPos=DestPos then begin
656
// special dir . at end of filename
657
if DestPos=1 then begin
671
if (SrcPos>l) then break;
672
c:=AFilename[SrcPos];
673
if c=PathDelim then break;
560
Len := Length(AFileName);
561
if (Len = 0) or FilenameIsTrimmed(Result) then exit;
562
if AFilename[1] = #32 then
565
while (Start <= Len) and (AFilename[Start] = #32) do Inc(Start);
566
System.Delete(Result,1,Start-1);
567
Len := Length(AFileName);
677
if DestPos<=length(AFilename) then
678
SetLength(Result,DestPos-1);
569
while (Len > 0) and (AFileName[Len] = #32) do Dec(Len);
570
SetLength(Result, Len);
571
Result := ResolveDots(Result);
574
procedure ForcePathDelims(var FileName: string);
578
for i:=1 to length(FileName) do
580
if Filename[i]='/' then
583
if Filename[i]='\' then
588
function GetForcedPathDelims(const FileName: string): String;
591
ForcePathDelims(Result);
681
594
{------------------------------------------------------------------------------
697
610
function TrimAndExpandFilename(const Filename: string; const BaseDir: string): string;
699
Result:=ChompPathDelim(TrimFilename(SetDirSeparators(Filename)));
612
Result:=ChompPathDelim(TrimFilename(Filename));
700
613
if Result='' then exit;
701
614
Result:=TrimFilename(ExpandFileNameUTF8(Result,BaseDir));
704
617
function TrimAndExpandDirectory(const Filename: string; const BaseDir: string): string;
706
Result:=TrimFilename(SetDirSeparators(Filename));
619
Result:=TrimFilename(Filename);
707
620
if Result='' then exit;
708
621
Result:=TrimFilename(AppendPathDelim(ExpandFileNameUTF8(Result,BaseDir)));
711
function CreateRelativePath(const Filename, BaseDirectory: string;
712
UsePointDirectory: boolean): string;
714
FileNameLength: Integer;
721
FileNameRestLen: Integer;
722
CmpBaseDirectory: String;
728
if (BaseDirectory='') or (Filename='') then exit;
731
// check for different windows file drives
732
if (CompareText(ExtractFileDrive(Filename),
733
ExtractFileDrive(BaseDirectory))<>0)
737
CmpBaseDirectory:=BaseDirectory;
738
CmpFilename:=Filename;
740
CmpBaseDirectory:=GetDarwinSystemFilename(CmpBaseDirectory);
741
CmpFilename:=GetDarwinSystemFilename(CmpFilename);
743
{$IFDEF CaseInsensitiveFilenames}
744
CmpBaseDirectory:=AnsiUpperCaseFileName(CmpBaseDirectory);
745
CmpFilename:=AnsiUpperCaseFileName(CmpFilename);
748
FileNameLength:=length(CmpFilename);
749
while (FileNameLength>0) and (CmpFilename[FileNameLength]=PathDelim) do
751
BaseDirLen:=length(CmpBaseDirectory);
752
while (BaseDirLen>0) and (CmpBaseDirectory[BaseDirLen]=PathDelim) do
754
if BaseDirLen=0 then exit;
756
//WriteLn('CreateRelativePath START ',copy(CmpBaseDirectory,1,BaseDirLen),' ',copy(CmpFilename,1,FileNameLength));
758
// count shared directories
762
while (p<=FileNameLength) and (BaseDirPos<=BaseDirLen)
763
and (CmpFileName[p]=CmpBaseDirectory[BaseDirPos]) do
765
if CmpFilename[p]=PathDelim then
770
until (p>FileNameLength) or (CmpFilename[p]<>PathDelim);
773
until (BaseDirPos>BaseDirLen) or (CmpBaseDirectory[BaseDirPos]<>PathDelim);
780
if ((BaseDirPos>BaseDirLen) or (CmpBaseDirectory[BaseDirPos]=PathDelim))
781
and ((p>FileNameLength) or (CmpFilename[p]=PathDelim)) then
783
// for example File=/a BaseDir=/a/b
786
// for example File=/aa BaseDir=/ab
789
if DirCount=0 then exit;
790
if FilenameIsAbsolute(BaseDirectory) and (DirCount=1) then exit;
792
// calculate needed up directories
793
while (BaseDirPos<=BaseDirLen) do begin
794
if (CmpBaseDirectory[BaseDirPos]=PathDelim) then
799
until (BaseDirPos>BaseDirLen) or (CmpBaseDirectory[BaseDirPos]<>PathDelim);
804
// create relative filename
807
FileNameLength:=length(Filename);
808
while (SamePos<=FileNameLength) do begin
809
if (Filename[SamePos]=PathDelim) then begin
812
until (SamePos>FileNameLength) or (Filename[SamePos]<>PathDelim);
819
FileNameRestLen:=FileNameLength-SamePos+1;
820
//writeln('DirCount=',DirCount,' UpDirCount=',UpDirCount,' FileNameRestLen=',FileNameRestLen,' SamePos=',SamePos);
821
SetLength(Result,3*UpDirCount+FileNameRestLen);
823
for i:=1 to UpDirCount do begin
824
Result[ResultPos]:='.';
825
Result[ResultPos+1]:='.';
826
Result[ResultPos+2]:=PathDelim;
829
if FileNameRestLen>0 then
830
System.Move(Filename[SamePos],Result[ResultPos],FileNameRestLen);
832
if UsePointDirectory and (Result='') and (Filename<>'') then
833
Result:='.'; // Filename is the BaseDirectory
836
626
{------------------------------------------------------------------------------
837
627
function FileIsInPath(const Filename, Path: string): boolean;
1086
function FileExistsUTF8(const Filename: string): boolean;
1088
Result:=SysUtils.FileExists(UTF8ToSys(Filename));
1091
function FileAgeUTF8(const FileName: String): Longint;
1093
Result:=SysUtils.FileAge(UTF8ToSys(Filename));
1096
function DirectoryExistsUTF8(const Directory: string): Boolean;
1098
Result:=SysUtils.DirectoryExists(UTF8ToSys(Directory));
1101
function ExpandFileNameUTF8(const FileName: string; const BaseDir: string): string;
1103
{$DEFINE ExpandTilde}
1106
{$DEFINE UppercaseDrive}
1108
{$IFDEF ExpandTilde}
1114
if Result='' then exit('');
1115
Result:=SetDirSeparators(Result);
1118
// use RTL function, which uses GetCurrentDir
1119
Result:=SysToUTF8(SysUtils.ExpandFileName(UTF8ToSys(Result)));
1121
{$IFDEF ExpandTilde}
1123
if (Result<>'') and (Result[1]='~') then
876
function FileSearchUTF8(const Name, DirList: String; ImplicitCurrentDir : Boolean = True): String;
883
temp:=SetDirSeparators(DirList);
884
// Start with checking the file in the current directory
885
If ImplicitCurrentDir and (Result <> '') and FileExistsUTF8(Result) Then
889
Break; // No more directories to search - fail
890
I:=pos(PathSeparator,Temp);
893
Result:=Copy (Temp,1,i-1);
894
system.Delete(Temp,1,I);
902
Result:=AppendPathDelim(Result)+Name;
903
If (Result <> '') and FileExistsUTF8(Result) Then
909
function FileIsReadOnlyUTF8(const FileName: String): Boolean;
911
Result:=FileGetAttrUTF8(FileName) and faReadOnly > 0;
916
function GetTempFileNameUTF8(const Dir, Prefix: String): String;
921
if Assigned(OnGetTempFile) then
922
Result:=OnGetTempFile(Dir,Prefix)
928
Start:=IncludeTrailingPathDelimiter(Dir);
935
Result:=Format('%s%.5d.tmp',[Start,I]);
937
until not FileExistsUTF8(Result);
941
function ForceDirectoriesUTF8(const Dir: string): Boolean;
946
function DoForceDirectories(Const Dir: string): Boolean;
952
ADir:=ExcludeTrailingPathDelimiter(Dir);
953
if (ADir='') then Exit;
954
if Not DirectoryExistsUTF8(ADir) then
956
APath := ExtractFilePath(ADir);
957
//this can happen on Windows if user specifies Dir like \user\name/test/
958
//and would, if not checked for, cause an infinite recusrsion and a stack overflow
959
if (APath = ADir) then
962
Result:=DoForceDirectories(APath);
964
Result := CreateDirUTF8(ADir);
968
function IsUncDrive(const Drv: String): Boolean;
970
Result := (Length(Drv) > 2) and (Drv[1] in AllowDirectorySeparators) and (Drv[2] in AllowDirectorySeparators);
975
ADrv := ExtractFileDrive(Dir);
976
if (ADrv<>'') and (not DirectoryExistsUTF8(ADrv))
977
{$IFNDEF FORCEDIR_NO_UNC_SUPPORT} and (not IsUncDrive(ADrv)){$ENDIF} then Exit;
1125
{$Hint use GetEnvironmentVariableUTF8}
1126
HomeDir := TrimAndExpandDirectory(GetEnvironmentVariable('HOME'));
1127
Result := HomeDir+copy(Result,2,length(Result));
980
E:=EInOutError.Create(SCannotCreateEmptyDir);
1131
Result := TrimFilename(Result);
1132
{$IFDEF UppercaseDrive}
1133
if (Length(Result)>=2) and (Result[1] in ['a'..'z']) and (Result[2]=':') then
1134
Result[1]:=chr(ord(Result[1])+ord('A')-ord('a'));
1139
if not FilenameIsAbsolute(Result) then
1140
Result := TrimAndExpandDirectory(BaseDir) + Result;
1144
function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec
1147
Result:=SysUtils.FindFirst(UTF8ToSys(Path),Attr,Rslt);
1148
Rslt.Name:=SysToUTF8(Rslt.Name);
1151
function FindNextUTF8(var Rslt: TSearchRec): Longint;
1153
Rslt.Name:=UTF8ToSys(Rslt.Name);
1154
Result:=SysUtils.FindNext(Rslt);
1155
Rslt.Name:=SysToUTF8(Rslt.Name);
1158
procedure FindCloseUTF8(var F: TSearchrec);
1160
SysUtils.FindClose(F);
1163
function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;
1165
Result:=SysUtils.FileSetDate(UTF8ToSys(Filename),Age);
1166
InvalidateFileStateCache(Filename);
1169
function FileGetAttrUTF8(const FileName: String): Longint;
1171
Result:=SysUtils.FileGetAttr(UTF8ToSys(Filename));
1174
function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;
1176
Result:=SysUtils.FileSetAttr(UTF8ToSys(Filename),Attr);
1177
InvalidateFileStateCache(Filename);
1180
function DeleteFileUTF8(const FileName: String): Boolean;
1182
Result:=SysUtils.DeleteFile(UTF8ToSys(Filename));
1184
InvalidateFileStateCache;
1187
function RenameFileUTF8(const OldName, NewName: String): Boolean;
1189
Result:=SysUtils.RenameFile(UTF8ToSys(OldName),UTF8ToSys(NewName));
1191
InvalidateFileStateCache;
1194
function FileSearchUTF8(const Name, DirList: String): String;
1196
Result:=SysToUTF8(SysUtils.FileSearch(UTF8ToSys(Name),UTF8ToSys(DirList)));
1199
function FileIsReadOnlyUTF8(const FileName: String): Boolean;
1201
Result:=SysUtils.FileIsReadOnly(UTF8ToSys(Filename));
1204
function GetCurrentDirUTF8: String;
1206
Result:=SysToUTF8(SysUtils.GetCurrentDir);
1209
function SetCurrentDirUTF8(const NewDir: String): Boolean;
1211
Result:=SysUtils.SetCurrentDir(UTF8ToSys(NewDir));
1214
function CreateDirUTF8(const NewDir: String): Boolean;
1216
Result:=SysUtils.CreateDir(UTF8ToSys(NewDir));
1219
function RemoveDirUTF8(const Dir: String): Boolean;
1221
Result:=SysUtils.RemoveDir(UTF8ToSys(Dir));
1224
function ForceDirectoriesUTF8(const Dir: string): Boolean;
1226
Result:=SysUtils.ForceDirectories(UTF8ToSys(Dir));
984
Result := DoForceDirectories(GetForcedPathDelims(Dir));
1229
988
procedure InvalidateFileStateCache(const Filename: string);
1232
991
OnInvalidateFileStateCache(Filename);
1235
function IsUNCPath(const Path: String): Boolean;
1238
Result := (Length(Path) > 2) and (Path[1] = PathDelim) and (Path[2] = PathDelim);
1244
function ExtractUNCVolume(const Path: String): String;
994
procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
995
ReadBackslash: boolean = false);
996
// split spaces, quotes are parsed as single parameter
997
// if ReadBackslash=true then \" is replaced to " and not treated as quote
1000
TMode = (mNormal,mApostrophe,mQuote);
1249
// the next function reuses Len variable
1250
function NextPathDelim(const Start: Integer): Integer;// inline;
1253
while (Result <= Len) and (Path[Result] <> PathDelim) do
1258
if not IsUNCPath(Path) then
1261
Len := Length(Path);
1262
if Path[I] = '?' then
1007
while p<=length(Params) do
1264
// Long UNC path form like:
1265
// \\?\UNC\ComputerName\SharedFolder\Resource or
1268
if Path[I] <> PathDelim then
1270
if UpperCase(Copy(Path, I + 1, 3)) = 'UNC' then
1010
while (p<=length(Params)) and (Params[p] in [' ',#9,#10,#13]) do inc(p);
1011
if (p>length(Params)) or (Params[p]=#0) then
1013
//writeln('SplitCmdLineParams After Space p=',p,'=[',Params[p],']');
1017
while p<=length(Params) do
1274
I := NextPathDelim(I + 1);
1276
I := NextPathDelim(I + 1);
1025
if ReadBackslash then
1027
// treat next character as normal character
1028
if (p>length(Params)) or (Params[p]=#0) then
1030
if ord(Params[p])<128 then
1035
// next character is already a normal character
1038
// treat backslash as normal character
1068
if Mode=mNormal then break;
1077
//writeln('SplitCmdLineParams Param=#'+Param+'#');
1078
ParamList.Add(Param);
1082
function StrToCmdLineParam(const Param: string): string;
1085
word1 word2 -> 'word1 word2'
1090
#0 character -> cut the rest
1111
if i<length(Result) then
1112
Delete(Result,i+1,length(Result));
1114
AnyQuot: Result:=''''+Result+'''';
1134
System.Insert('"',Result,1);
1135
p:=PChar(Result)+i+1;
1142
// => end ', start "
1143
i:=p-PChar(Result)+1;
1144
System.Insert('''"',Result,i);
1145
p:=PChar(Result)+i+1;
1158
System.Insert('''',Result,1);
1159
p:=PChar(Result)+i+1;
1166
// => end ", start '
1167
i:=p-PChar(Result)+1;
1168
System.Insert('"''',Result,i);
1169
p:=PChar(Result)+i+1;
1181
function MergeCmdLineParams(ParamList: TStrings): string;
1186
if ParamList=nil then exit;
1187
for i:=0 to ParamList.Count-1 do
1281
I := NextPathDelim(I);
1283
I := NextPathDelim(I + 1);
1189
if i>0 then Result+=' ';
1190
Result+=StrToCmdLineParam(ParamList[i]);
1285
Result := Copy(Path, 1, I);
1196
- DriveLetter + : + PathDelim on Windows (if present) or
1197
- UNC Share on Windows if present or
1198
- PathDelim if FileName starts with PathDelim on Unix or Wince or
1199
- Empty string of non eof the above applies
1201
function ExtractFileRoot(FileName: String): String;
1206
Len := Length(FileName);
1209
if IsUncPath(FileName) then
1211
Result := ExtractUNCVolume(FileName);
1212
// is it like \\?\C:\Directory? then also include the "C:\" part
1213
if (Result = '\\?\') and (Length(FileName) > 6) and
1214
(FileName[5] in ['a'..'z','A'..'Z']) and (FileName[6] = ':') and (FileName[7] in AllowDirectorySeparators)
1216
Result := Copy(FileName, 1, 7);
1220
{$if defined(unix) or defined(wince)}
1221
if (FileName[1] = PathDelim) then Result := PathDelim;
1223
if (Len > 2) and (FileName[1] in ['a'..'z','A'..'Z']) and (FileName[2] = ':') and (FileName[3] in AllowDirectorySeparators) then
1224
Result := UpperCase(Copy(FileName,1,3));
1234
FinalizeLazFileUtils;