mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-25 17:59:06 +02:00
629 lines
15 KiB
ObjectPascal
629 lines
15 KiB
ObjectPascal
{
|
|
$Id$
|
|
This file is part of the Free Pascal Integrated Development Environment
|
|
Copyright (c) 1998 by Berczi Gabor
|
|
|
|
Utilility routines used by the IDE
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
unit FPUtils;
|
|
|
|
interface
|
|
|
|
uses Objects;
|
|
|
|
const
|
|
{$ifdef Unix}
|
|
dirsep = '/';
|
|
listsep = [';',':'];
|
|
exeext = '';
|
|
pasext = '.pas';
|
|
ppext = '.pp';
|
|
{$else}
|
|
dirsep = '\';
|
|
listsep = [';'];
|
|
exeext = '.exe';
|
|
pasext = '.pas';
|
|
ppext = '.pp';
|
|
{$endif}
|
|
|
|
function SmartPath(Path: string): string;
|
|
Function FixPath(s:string;allowdot:boolean):string;
|
|
function FixFileName(const s:string):string;
|
|
function MakeExeName(const fn:string):string;
|
|
function Center(const S: string; Len: byte): string;
|
|
function FitStr(const S: string; Len: byte): string;
|
|
function KillTilde(S: string): string;
|
|
function LowercaseStr(const S: string): string;
|
|
{function DirOf(const S: string): string;
|
|
function ExtOf(const S: string): string;
|
|
function NameOf(const S: string): string;
|
|
function NameAndExtOf(const S: string): string;}
|
|
function StrToExtended(S: string): Extended;
|
|
function Power(const A,B: double): double;
|
|
function MatchesMask(What, Mask: string): boolean;
|
|
function MatchesMaskList(What, MaskList: string): boolean;
|
|
function MatchesFileList(What, FileList: string): boolean;
|
|
function EatIO: integer;
|
|
function RenameFile(const OldFileName,NewFileName: string): boolean;
|
|
function LocateFile(FileList: string): string;
|
|
function LocatePasFile(const FileName:string):string;
|
|
function LocateExeFile(var FileName:string): boolean;
|
|
function EraseFile(FileName: string): boolean;
|
|
function GetStr(const P: PString): string;
|
|
procedure ReplaceStr(var S: string; const What,NewS: string);
|
|
procedure ReplaceStrI(var S: string; What: string; const NewS: string);
|
|
|
|
const ListSeparator : char = ';';
|
|
|
|
implementation
|
|
|
|
uses Dos,
|
|
WUtils,
|
|
FPVars,FPSwitch;
|
|
|
|
function IntToStr(L: longint): string;
|
|
var S: string;
|
|
begin
|
|
Str(L,S);
|
|
IntToStr:=S;
|
|
end;
|
|
|
|
function IntToStrZ(L: longint; MinLen: byte): string;
|
|
var S: string;
|
|
begin
|
|
S:=IntToStr(L);
|
|
if length(S)<MinLen then S:=CharStr('0',MinLen-length(S))+S;
|
|
IntToStrZ:=S;
|
|
end;
|
|
|
|
function IntToStrL(L: longint; MinLen: byte): string;
|
|
var S: string;
|
|
begin
|
|
S:=IntToStr(L);
|
|
if length(S)<MinLen then S:=CharStr(' ',MinLen-length(S))+S;
|
|
IntToStrL:=S;
|
|
end;
|
|
|
|
function SmartPath(Path: string): string;
|
|
var S: string;
|
|
begin
|
|
GetDir(0,S);
|
|
if copy(S,length(S),1)<>DirSep then S:=S+DirSep;
|
|
{$ifdef FSCaseInsensitive}
|
|
if (LowerCaseStr(copy(Path,1,length(S)))=LowerCaseStr(S)) {and (Pos('\',copy(Path,length(S)+1,High(S)))=0)} then
|
|
{$else}
|
|
if (copy(Path,1,length(S))=S) {and (Pos('\',copy(Path,length(S)+1,High(S)))=0)} then
|
|
{$endif}
|
|
system.Delete(Path,1,length(S));
|
|
SmartPath:=Path;
|
|
end;
|
|
|
|
|
|
Function FixPath(s:string;allowdot:boolean):string;
|
|
var
|
|
i : longint;
|
|
begin
|
|
for i:=1 to length(s) do
|
|
if s[i] in ['/','\'] then
|
|
s[i]:=DirSep;
|
|
if (length(s)>0) and (s[length(s)]<>DirSep) and
|
|
(s[length(s)]<>':') then
|
|
s:=s+DirSep;
|
|
if (not allowdot) and (s='.'+DirSep) then
|
|
s:='';
|
|
FixPath:=s;
|
|
end;
|
|
|
|
|
|
function FixFileName(const s:string):string;
|
|
var
|
|
i : longint;
|
|
{$ifdef Unix}
|
|
NoPath : boolean;
|
|
{$endif}
|
|
begin
|
|
{$ifdef Unix}NoPath:=true;{$endif}
|
|
for i:=length(s) downto 1 do
|
|
begin
|
|
case s[i] of
|
|
{$ifdef Unix}
|
|
'/','\' : begin
|
|
FixFileName[i]:='/';
|
|
NoPath:=false; {Skip lowercasing path: 'X11'<>'x11' }
|
|
end;
|
|
'A'..'Z' : if NoPath then
|
|
FixFileName[i]:=char(byte(s[i])+ord('a')-ord('A'))
|
|
else
|
|
FixFileName[i]:=s[i];
|
|
{$else}
|
|
'/' : FixFileName[i]:='\';
|
|
'A'..'Z' : FixFileName[i]:=char(byte(s[i])+32);
|
|
{$endif}
|
|
else
|
|
FixFileName[i]:=s[i];
|
|
end;
|
|
end;
|
|
FixFileName[0]:=s[0];
|
|
end;
|
|
|
|
|
|
function MakeExeName(const fn:string):string;
|
|
var
|
|
d : DirStr;
|
|
n : NameStr;
|
|
e : ExtStr;
|
|
begin
|
|
FSplit(fn,d,n,e);
|
|
MakeExeName:=d+n+ExeExt;
|
|
end;
|
|
|
|
|
|
function Center(const S: string; Len: byte): string;
|
|
begin
|
|
Center:=LExpand(S+CharStr(' ',Max(0,(Len-length(S)) div 2)),Len);
|
|
end;
|
|
|
|
function FitStr(const S: string; Len: byte): string;
|
|
begin
|
|
FitStr:=RExpand(copy(S,1,Len),Len);
|
|
end;
|
|
|
|
|
|
function KillTilde(S: string): string;
|
|
var P: longint;
|
|
begin
|
|
repeat
|
|
P:=Pos('~',S);
|
|
if P>0 then
|
|
Delete(S,P,1);
|
|
until P=0;
|
|
KillTilde:=S;
|
|
end;
|
|
|
|
function LowerCaseStr(const S: string): string;
|
|
var
|
|
I: Longint;
|
|
begin
|
|
for I:=1 to length(S) do
|
|
if S[I] in ['A'..'Z'] then
|
|
LowerCaseStr[I]:=chr(ord(S[I])+32)
|
|
else
|
|
LowerCaseStr[I]:=S[I];
|
|
LowercaseStr[0]:=S[0];
|
|
end;
|
|
|
|
{function DirOf(const S: string): string;
|
|
var D: DirStr; E: ExtStr; N: NameStr;
|
|
begin
|
|
FSplit(S,D,N,E);
|
|
if (D<>'') and (D[Length(D)]<>DirSep) then
|
|
DirOf:=D+DirSep
|
|
else
|
|
DirOf:=D;
|
|
end;
|
|
|
|
|
|
function ExtOf(const S: string): string;
|
|
var D: DirStr; E: ExtStr; N: NameStr;
|
|
begin
|
|
FSplit(S,D,N,E);
|
|
ExtOf:=E;
|
|
end;
|
|
|
|
|
|
function NameOf(const S: string): string;
|
|
var D: DirStr; E: ExtStr; N: NameStr;
|
|
begin
|
|
FSplit(S,D,N,E);
|
|
NameOf:=N;
|
|
end;
|
|
|
|
function NameAndExtOf(const S: string): string;
|
|
var D: DirStr; E: ExtStr; N: NameStr;
|
|
begin
|
|
FSplit(S,D,N,E);
|
|
NameAndExtOf:=N+E;
|
|
end; }
|
|
|
|
function StrToExtended(S: string): Extended;
|
|
var R : Extended;
|
|
C : integer;
|
|
begin
|
|
Val(S,R,C);
|
|
StrToExtended:=R;
|
|
end;
|
|
|
|
function Power(const A,B: double): double;
|
|
begin
|
|
if A=0 then Power:=0
|
|
else Power:=exp(B*ln(A));
|
|
end;
|
|
|
|
function MatchesMask(What, Mask: string): boolean;
|
|
|
|
function upper(const s : string) : string;
|
|
var
|
|
i : Sw_integer;
|
|
begin
|
|
for i:=1 to length(s) do
|
|
if s[i] in ['a'..'z'] then
|
|
upper[i]:=char(byte(s[i])-32)
|
|
else
|
|
upper[i]:=s[i];
|
|
upper[0]:=s[0];
|
|
end;
|
|
|
|
Function CmpStr(const hstr1,hstr2:string):boolean;
|
|
var
|
|
found : boolean;
|
|
i1,i2 : Sw_integer;
|
|
begin
|
|
i1:=0;
|
|
i2:=0;
|
|
found:=true;
|
|
while found and (i1<length(hstr1)) and (i2<=length(hstr2)) do
|
|
begin
|
|
if found then
|
|
inc(i2);
|
|
inc(i1);
|
|
case hstr1[i1] of
|
|
'?' :
|
|
found:=true;
|
|
'*' :
|
|
begin
|
|
found:=true;
|
|
if (i1=length(hstr1)) then
|
|
i2:=length(hstr2)
|
|
else
|
|
if (i1<length(hstr1)) and (hstr1[i1+1]<>hstr2[i2]) then
|
|
begin
|
|
if i2<length(hstr2) then
|
|
dec(i1)
|
|
end
|
|
else
|
|
if i2>1 then
|
|
dec(i2);
|
|
end;
|
|
else
|
|
found:=(hstr1[i1]=hstr2[i2]) or (hstr2[i2]='?');
|
|
end;
|
|
end;
|
|
if found then
|
|
found:=(i1>=length(hstr1)) and (i2>=length(hstr2));
|
|
CmpStr:=found;
|
|
end;
|
|
|
|
var
|
|
D1,D2 : DirStr;
|
|
N1,N2 : NameStr;
|
|
E1,E2 : Extstr;
|
|
begin
|
|
{$ifdef Unix}
|
|
FSplit(What,D1,N1,E1);
|
|
FSplit(Mask,D2,N2,E2);
|
|
{$else}
|
|
FSplit(Upper(What),D1,N1,E1);
|
|
FSplit(Upper(Mask),D2,N2,E2);
|
|
{$endif}
|
|
MatchesMask:=CmpStr(N2,N1) and CmpStr(E2,E1);
|
|
end;
|
|
|
|
function MatchesMaskList(What, MaskList: string): boolean;
|
|
var P: integer;
|
|
Match: boolean;
|
|
begin
|
|
Match:=false;
|
|
if What<>'' then
|
|
repeat
|
|
P:=Pos(ListSeparator, MaskList);
|
|
if P=0 then
|
|
P:=length(MaskList)+1;
|
|
Match:=MatchesMask(What,copy(MaskList,1,P-1));
|
|
Delete(MaskList,1,P);
|
|
until Match or (MaskList='');
|
|
MatchesMaskList:=Match;
|
|
end;
|
|
|
|
function MatchesFileList(What, FileList: string): boolean;
|
|
var P: integer;
|
|
Match: boolean;
|
|
WD,FD : record D: DirStr; N: NameStr; E: ExtStr; end;
|
|
F: string;
|
|
begin
|
|
Match:=false;
|
|
FSplit(What,WD.D,WD.N,WD.E);
|
|
if What<>'' then
|
|
repeat
|
|
P:=Pos(ListSeparator, FileList);
|
|
if P=0 then P:=length(FileList)+1;
|
|
F:=copy(FileList,1,P-1);
|
|
FSplit(F,FD.D,FD.N,FD.E);
|
|
Match:=MatchesMask(WD.D+WD.N,FD.D+FD.N) and
|
|
MatchesMask(WD.E,FD.E);
|
|
Delete(FileList,1,P);
|
|
until Match or (FileList='');
|
|
MatchesFileList:=Match;
|
|
end;
|
|
|
|
function EatIO: integer;
|
|
begin
|
|
EatIO:=IOResult;
|
|
end;
|
|
|
|
function RenameFile(const OldFileName,NewFileName: string): boolean;
|
|
var f: file;
|
|
begin
|
|
Assign(f,OldFileName);
|
|
Rename(f,NewFileName);
|
|
RenameFile:=(EatIO=0);
|
|
end;
|
|
|
|
function LocateFile(FileList: string): string;
|
|
var FilePath: string;
|
|
function CheckFile(Path,Name: string): boolean;
|
|
var OK: boolean;
|
|
begin
|
|
Path:=CompleteDir(Path);
|
|
Path:=Path+Name;
|
|
OK:=ExistsFile(Path);
|
|
if OK then FilePath:=Path;
|
|
CheckFile:=OK;
|
|
end;
|
|
function LocateSingleFile(FileName: string): boolean;
|
|
var OK: boolean;
|
|
begin
|
|
OK:=CheckFile(FExpand('.'),FileName);
|
|
if OK=false then OK:=CheckFile(StartupDir,FileName);
|
|
if OK=false then OK:=CheckFile(IDEDir,FileName);
|
|
LocateSingleFile:=OK;
|
|
end;
|
|
var P: integer;
|
|
begin
|
|
FilePath:='';
|
|
if FileList<>'' then
|
|
repeat
|
|
P:=Pos(ListSeparator,FileList); if P=0 then P:=length(FileList)+1;
|
|
LocateSingleFile(copy(FileList,1,P-1));
|
|
Delete(FileList,1,P);
|
|
until (FilePath<>'') or (FileList='');
|
|
LocateFile:=FilePath;
|
|
end;
|
|
|
|
function LocatePasFile(const FileName:string):string;
|
|
var
|
|
s : string;
|
|
begin
|
|
LocatePasFile:=FileName;
|
|
if ExistsFile(FileName) or (ExtOf(FileName)<>'') then
|
|
exit;
|
|
S:=FileName+PPExt;
|
|
if ExistsFile(S) then
|
|
begin
|
|
LocatePasFile:=S;
|
|
exit;
|
|
end;
|
|
S:=FileName+PasExt;
|
|
if ExistsFile(S) then
|
|
begin
|
|
LocatePasFile:=S;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function LocateExeFile(var FileName:string): boolean;
|
|
var
|
|
dir,s : string;
|
|
i : longint;
|
|
begin
|
|
LocateExeFile:=False;
|
|
if ExistsFile(FileName) then
|
|
begin
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
end;
|
|
|
|
S:=GetEnv('PATH');
|
|
While Length(S)>0 do
|
|
begin
|
|
i:=1;
|
|
While (i<=Length(S)) and not (S[i] in ListSep) do
|
|
Inc(i);
|
|
Dir:=CompleteDir(Copy(S,1,i-1));
|
|
if i<Length(S) then
|
|
Delete(S,1,i)
|
|
else
|
|
S:='';
|
|
if ExistsFile(Dir+FileName) then
|
|
Begin
|
|
FileName:=Dir+FileName;
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
End;
|
|
end;
|
|
end;
|
|
|
|
function GetStr(const P: PString): string;
|
|
begin
|
|
if P=nil then GetStr:='' else GetStr:=P^;
|
|
end;
|
|
|
|
function EraseFile(FileName: string): boolean;
|
|
var f: file;
|
|
begin
|
|
if FileName='' then Exit;
|
|
{$I-}
|
|
Assign(f,FileName);
|
|
Erase(f);
|
|
{$I+}
|
|
EraseFile:=(EatIO=0);
|
|
end;
|
|
|
|
procedure ReplaceStr(var S: string; const What,NewS: string);
|
|
var I : Sw_integer;
|
|
begin
|
|
repeat
|
|
I:=Pos(What,S);
|
|
if I>0 then
|
|
begin
|
|
Delete(S,I,length(What));
|
|
Insert(NewS,S,I);
|
|
end;
|
|
until I=0;
|
|
end;
|
|
|
|
procedure ReplaceStrI(var S: string; What: string; const NewS: string);
|
|
var I : integer;
|
|
UpcaseS: string;
|
|
begin
|
|
UpcaseS:=UpcaseStr(S); What:=UpcaseStr(What);
|
|
repeat
|
|
I:=Pos(What,UpcaseS);
|
|
if I>0 then
|
|
begin
|
|
Delete(S,I,length(What));
|
|
Insert(NewS,S,I);
|
|
end;
|
|
until I=0;
|
|
end;
|
|
|
|
|
|
END.
|
|
{
|
|
$Log$
|
|
Revision 1.1 2001-08-04 11:30:24 peter
|
|
* ide works now with both compiler versions
|
|
|
|
Revision 1.1.2.7 2001/03/06 21:57:29 pierre
|
|
* some more generic code
|
|
|
|
Revision 1.1.2.6 2000/11/27 11:57:29 pierre
|
|
* some duplicates with wutils commented out
|
|
|
|
Revision 1.1.2.5 2000/11/14 09:23:56 marco
|
|
* Second batch
|
|
|
|
Revision 1.1.2.4 2000/11/13 16:59:09 pierre
|
|
* some function in double removed from fputils unit
|
|
|
|
Revision 1.1.2.3 2000/11/03 15:45:57 pierre
|
|
* fix LTrim for AnsiStrings
|
|
|
|
Revision 1.1.2.2 2000/08/15 03:40:53 peter
|
|
[*] no more fatal exits when the IDE can't find the error file (containing
|
|
the redirected assembler/linker output) after compilation
|
|
[*] hidden windows are now added always at the end of the Window List
|
|
[*] TINIFile parsed entries encapsulated in string delimiters incorrectly
|
|
[*] selection was incorrectly adjusted when typing in overwrite mode
|
|
[*] the line wasn't expanded when it's end was reached in overw. mode
|
|
[*] the IDE now tries to locate source files also in the user specified
|
|
unit dirs (for ex. as a response to 'Open at cursor' (Ctrl+Enter) )
|
|
[*] 'Open at cursor' is now aware of the extension (if specified)
|
|
|
|
Revision 1.1.2.1 2000/07/20 11:02:15 michael
|
|
+ Fixes from gabor. See fixes.txt
|
|
|
|
Revision 1.1 2000/07/13 09:48:36 michael
|
|
+ Initial import
|
|
|
|
Revision 1.16 2000/06/22 09:07:13 pierre
|
|
* Gabor changes: see fixes.txt
|
|
|
|
Revision 1.15 2000/04/18 11:42:37 pierre
|
|
lot of Gabor changes : see fixes.txt
|
|
|
|
Revision 1.14 2000/01/03 11:38:34 michael
|
|
Changes from Gabor
|
|
|
|
Revision 1.13 1999/04/15 08:58:07 peter
|
|
* syntax highlight fixes
|
|
* browser updates
|
|
|
|
Revision 1.12 1999/04/07 21:55:55 peter
|
|
+ object support for browser
|
|
* html help fixes
|
|
* more desktop saving things
|
|
* NODEBUG directive to exclude debugger
|
|
|
|
Revision 1.11 1999/03/19 16:04:31 peter
|
|
* new compiler dialog
|
|
|
|
Revision 1.10 1999/03/08 14:58:14 peter
|
|
+ prompt with dialogs for tools
|
|
|
|
Revision 1.9 1999/03/01 15:42:06 peter
|
|
+ Added dummy entries for functions not yet implemented
|
|
* MenuBar didn't update itself automatically on command-set changes
|
|
* Fixed Debugging/Profiling options dialog
|
|
* TCodeEditor converts spaces to tabs at save only if efUseTabChars is
|
|
set
|
|
* efBackSpaceUnindents works correctly
|
|
+ 'Messages' window implemented
|
|
+ Added '$CAP MSG()' and '$CAP EDIT' to available tool-macros
|
|
+ Added TP message-filter support (for ex. you can call GREP thru
|
|
GREP2MSG and view the result in the messages window - just like in TP)
|
|
* A 'var' was missing from the param-list of THelpFacility.TopicSearch,
|
|
so topic search didn't work...
|
|
* In FPHELP.PAS there were still context-variables defined as word instead
|
|
of THelpCtx
|
|
* StdStatusKeys() was missing from the statusdef for help windows
|
|
+ Topic-title for index-table can be specified when adding a HTML-files
|
|
|
|
Revision 1.8 1999/02/22 02:15:20 peter
|
|
+ default extension for save in the editor
|
|
+ Separate Text to Find for the grep dialog
|
|
* fixed redir crash with tp7
|
|
|
|
Revision 1.7 1999/02/16 17:13:55 pierre
|
|
+ findclose added for FPC
|
|
|
|
Revision 1.6 1999/02/05 12:12:01 pierre
|
|
+ SourceDir that stores directories for sources that the
|
|
compiler should not know about
|
|
Automatically asked for addition when a new file that
|
|
needed filedialog to be found is in an unknown directory
|
|
Stored and retrieved from INIFile
|
|
+ Breakpoints conditions added to INIFile
|
|
* Breakpoints insterted and removed at debin and end of debug session
|
|
|
|
Revision 1.5 1999/02/02 16:41:43 peter
|
|
+ automatic .pas/.pp adding by opening of file
|
|
* better debuggerscreen changes
|
|
|
|
Revision 1.4 1999/01/21 11:54:25 peter
|
|
+ tools menu
|
|
+ speedsearch in symbolbrowser
|
|
* working run command
|
|
|
|
Revision 1.3 1999/01/12 14:29:40 peter
|
|
+ Implemented still missing 'switch' entries in Options menu
|
|
+ Pressing Ctrl-B sets ASCII mode in editor, after which keypresses (even
|
|
ones with ASCII < 32 ; entered with Alt+<###>) are interpreted always as
|
|
ASCII chars and inserted directly in the text.
|
|
+ Added symbol browser
|
|
* splitted fp.pas to fpide.pas
|
|
|
|
Revision 1.2 1998/12/28 15:47:53 peter
|
|
+ Added user screen support, display & window
|
|
+ Implemented Editor,Mouse Options dialog
|
|
+ Added location of .INI and .CFG file
|
|
+ Option (INI) file managment implemented (see bottom of Options Menu)
|
|
+ Switches updated
|
|
+ Run program
|
|
|
|
Revision 1.31 1998/12/27 11:25:37 gabor
|
|
+ MatchesMask(), MatchesMaskList() and MatchesFileList() added
|
|
+ NameAndExtOf() added
|
|
Revision 1.3 1998/12/22 10:39:52 peter
|
|
+ options are now written/read
|
|
+ find and replace routines
|
|
|
|
}
|