mirror of https://gitlab.com/basile.b/dexed.git
815 lines
18 KiB
Plaintext
815 lines
18 KiB
Plaintext
unit ce_common;
|
|
|
|
{$I ce_defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, ExtCtrls,
|
|
{$IFDEF WINDOWS}
|
|
Windows,
|
|
{$ENDIF}
|
|
ActnList, dialogs, forms, process, asyncprocess;
|
|
|
|
const
|
|
DdiagFilter = 'D source|*.d|D interface|*.di|All files|*.*';
|
|
exeExt = {$IFDEF WINDOWS} '.exe' {$ELSE} '' {$ENDIF};
|
|
objExt = {$IFDEF WINDOWS} '.obj' {$ELSE} '.o' {$ENDIF};
|
|
libExt = {$IFDEF WINDOWS} '.lib' {$ELSE} '.a' {$ENDIF};
|
|
|
|
var
|
|
dExtList: TStringList;
|
|
DCompiler: string = 'dmd';
|
|
|
|
type
|
|
|
|
(**
|
|
* Workaround for a TAsyncProcess Linux issue: OnTerminate event not called.
|
|
* An idle timer is started when executing and trigs the event if necessary.
|
|
*)
|
|
TCheckedAsyncProcess = class(TAsyncProcess)
|
|
{$IFDEF LINUX}
|
|
private
|
|
fTimer: TIdleTimer;
|
|
procedure checkTerminated(sender: TObject);
|
|
public
|
|
constructor Create(aOwner: TComponent); override;
|
|
procedure Execute; override;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
(**
|
|
* MRU list for strings
|
|
*)
|
|
TMRUList = class(TStringList)
|
|
private
|
|
fMaxCount: Integer;
|
|
fObj: TObject;
|
|
protected
|
|
fChecking: boolean;
|
|
procedure clearOutOfRange;
|
|
procedure setMaxCount(aValue: Integer);
|
|
function checkItem(const S: string): boolean; virtual;
|
|
procedure Put(Index: Integer; const S: string); override;
|
|
procedure InsertItem(Index: Integer; const S: string); override;
|
|
published
|
|
property maxCount: Integer read fMaxCount write setMaxCount;
|
|
public
|
|
constructor Create;
|
|
procedure Insert(Index: Integer; const S: string); override;
|
|
property objectTag: TObject read fObj write fObj;
|
|
end;
|
|
|
|
(**
|
|
* MRU list for filenames
|
|
*)
|
|
TMRUFileList = class(TMRUList)
|
|
protected
|
|
function checkItem(const S: string): boolean; override;
|
|
public
|
|
procedure assign(src: TPersistent); override;
|
|
end;
|
|
|
|
(**
|
|
* TProcess with assign() 'overriden'.
|
|
*)
|
|
TProcessEx = class helper for TProcess
|
|
public
|
|
procedure Assign(aValue: TPersistent);
|
|
end;
|
|
|
|
(**
|
|
* Makes TReader.ReadProperties visible
|
|
*)
|
|
TReaderEx = class helper for TReader
|
|
public
|
|
procedure ReadPersistent(aValue: TPersistent);
|
|
end;
|
|
|
|
(**
|
|
* Makes TWriter.WriteProperties visible
|
|
* W
|
|
*)
|
|
TWriterEx = class helper for TWriter
|
|
public
|
|
// works as bin but raises because of 'ObjectBinaryToText'
|
|
procedure WritePersistent(aValue: TPersistent);
|
|
end;
|
|
|
|
(**
|
|
* Save a component with a readable aspect.
|
|
*)
|
|
procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
|
|
|
|
(**
|
|
* Load a component.
|
|
*)
|
|
procedure loadCompFromTxtFile(const aComp: TComponent; const aFilename: string;
|
|
aPropNotFoundHandler: TPropertyNotFoundEvent = nil; anErrorHandler: TReaderError = nil);
|
|
|
|
(**
|
|
* Converts a relative path to an absolute path.
|
|
*)
|
|
function expandFilenameEx(const aBasePath, aFilename: string): string;
|
|
|
|
(**
|
|
* Patches the directory separators from a string.
|
|
* This is used to ensure that a project saved on a platform can be loaded
|
|
* on another one.
|
|
*)
|
|
function patchPlateformPath(const aPath: string): string;
|
|
procedure patchPlateformPaths(const sPaths: TStrings);
|
|
|
|
(**
|
|
* Patches the file extension from a string.
|
|
* This is used to ensure that a project saved on a platform can be loaded
|
|
* on another one. Note that the ext which are handled are specific to coedit projects.
|
|
*)
|
|
function patchPlateformExt(const aFilename: string): string;
|
|
|
|
(**
|
|
* Ok/Cancel modal dialog
|
|
*)
|
|
function dlgOkCancel(const aMsg: string): TModalResult;
|
|
|
|
(**
|
|
* Info message
|
|
*)
|
|
function dlgOkInfo(const aMsg: string): TModalResult;
|
|
|
|
(**
|
|
* Error message
|
|
*)
|
|
function dlgOkError(const aMsg: string): TModalResult;
|
|
|
|
(**
|
|
* Returns an unique object identifier, based on its heap address.
|
|
*)
|
|
function uniqueObjStr(const aObject: Tobject): string;
|
|
|
|
(**
|
|
* Reduces a filename if its length is over the threshold defined by charThresh.
|
|
* Even if the result is not usable anymore, it avoids any "visually-overloaded" MRU menu.
|
|
*)
|
|
function shortenPath(const aPath: string; charThresh: Word = 60): string;
|
|
|
|
(**
|
|
* Returns the folder Coedit documents and settings.
|
|
*)
|
|
function getDocPath: string;
|
|
|
|
(**
|
|
* Fills aList with the names of the files located in aPath.
|
|
*)
|
|
procedure listFiles(aList: TStrings; const aPath: string; recursive: boolean = false);
|
|
|
|
(**
|
|
* Fills aList with the names of the folders located in aPath.
|
|
*)
|
|
procedure listFolders(aList: TStrings; const aPath: string);
|
|
|
|
(**
|
|
* Checks if aPath contains at least one sub-folder.
|
|
*)
|
|
function hasFolder(const aPath: string): boolean;
|
|
|
|
(**
|
|
* Fills aList with the system drives.
|
|
*)
|
|
procedure listDrives(aList: TStrings);
|
|
|
|
(**
|
|
* If aPath ends with an asterisk then fills aList with the names of the files located in aPath.
|
|
* Returns true if aPath was 'asterisk-ifyed'.
|
|
*)
|
|
function listAsteriskPath(const aPath: string; aList: TStrings; someExts: TStrings = nil): boolean;
|
|
|
|
(**
|
|
* Lets the shell open a file
|
|
*)
|
|
function shellOpen(const aFilename: string): boolean;
|
|
|
|
(**
|
|
* Returns true if anExeName can be spawn without its full path.
|
|
*)
|
|
function exeInSysPath(anExeName: string): boolean;
|
|
|
|
(**
|
|
* Clears then fills aList with aProcess output stream.
|
|
*)
|
|
procedure processOutputToStrings(aProcess: TProcess; var aList: TStringList);
|
|
|
|
(**
|
|
* Terminates and frees aProcess;
|
|
*)
|
|
procedure killProcess(var aProcess: TAsyncProcess);
|
|
|
|
procedure killProcess(var aProcess: TCheckedAsyncProcess);
|
|
|
|
(**
|
|
* Ensures that the in/out process pipes are not redirected, that it has a console, if it waits on exit.
|
|
*)
|
|
procedure ensureNoPipeIfWait(aProcess: TProcess);
|
|
|
|
implementation
|
|
|
|
{$IFDEF LINUX}
|
|
constructor TCheckedAsyncProcess.Create(aOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
fTimer := TIdleTimer.Create(self);
|
|
fTimer.Enabled := false;
|
|
fTimer.Interval :=50;
|
|
fTimer.AutoEnabled := false;
|
|
end;
|
|
|
|
procedure TCheckedAsyncProcess.Execute;
|
|
begin
|
|
if OnTerminate <> nil then fTimer.Enabled :=true;
|
|
fTimer.OnTimer := @checkTerminated;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCheckedAsyncProcess.checkTerminated(sender: TObject);
|
|
begin
|
|
if Running then exit;
|
|
if OnTerminate = nil then exit;
|
|
fTimer.Enabled:=false;
|
|
OnTerminate(Self);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
// https://stackoverflow.com/questions/25438091/objectbinarytotext-error-with-a-treader-twriter-helper-class
|
|
// http://forum.lazarus.freepascal.org/index.php/topic,25557.0.html
|
|
procedure TProcessEx.Assign(aValue: TPersistent);
|
|
var
|
|
src: TProcess;
|
|
begin
|
|
if aValue is TProcess then
|
|
begin
|
|
src := TProcess(aValue);
|
|
PipeBufferSize := src.PipeBufferSize;
|
|
Active := src.Active;
|
|
Executable := src.Executable;
|
|
Parameters := src.Parameters;
|
|
ConsoleTitle := src.ConsoleTitle;
|
|
CurrentDirectory := src.CurrentDirectory;
|
|
Desktop := src.Desktop;
|
|
Environment := src.Environment;
|
|
Options := src.Options;
|
|
Priority := src.Priority;
|
|
StartupOptions := src.StartupOptions;
|
|
ShowWindow := src.ShowWindow;
|
|
WindowColumns := src.WindowColumns;
|
|
WindowHeight := src.WindowHeight;
|
|
WindowLeft := src.WindowLeft;
|
|
WindowRows := src.WindowRows;
|
|
WindowTop := src.WindowTop;
|
|
WindowWidth := src.WindowWidth;
|
|
FillAttribute := src.FillAttribute;
|
|
XTermProgram := src.XTermProgram;
|
|
end
|
|
else inherited;
|
|
end;
|
|
|
|
procedure TReaderEx.ReadPersistent(aValue: TPersistent);
|
|
begin
|
|
ReadListBegin;
|
|
while not EndOfList do
|
|
ReadProperty(aValue);
|
|
ReadListEnd;
|
|
end;
|
|
|
|
procedure TWriterEx.WritePersistent(aValue: TPersistent);
|
|
begin
|
|
WriteListBegin;
|
|
WriteProperties(aValue);
|
|
WriteListEnd;
|
|
end;
|
|
|
|
constructor TMRUList.Create;
|
|
begin
|
|
fMaxCount := 10;
|
|
end;
|
|
|
|
procedure TMRUList.clearOutOfRange;
|
|
begin
|
|
while Count > fMaxCount do
|
|
delete(Count-1);
|
|
end;
|
|
|
|
procedure TMRUList.setMaxCount(aValue: Integer);
|
|
begin
|
|
if aValue < 0 then
|
|
aValue := 0;
|
|
if fMaxCount = aValue then
|
|
exit;
|
|
fMaxCount := aValue;
|
|
clearOutOfRange;
|
|
end;
|
|
|
|
function TMRUList.checkItem(const S: string): boolean;
|
|
var
|
|
i: NativeInt;
|
|
begin
|
|
i := indexOf(S);
|
|
if i = -1 then
|
|
exit(true);
|
|
if i = 0 then
|
|
exit(false);
|
|
if Count < 2 then
|
|
exit(false);
|
|
exchange(i, i-1);
|
|
exit( false);
|
|
end;
|
|
|
|
procedure TMRUList.Put(Index: Integer; const S: string);
|
|
begin
|
|
if not (checkItem(S)) then
|
|
exit;
|
|
inherited;
|
|
clearOutOfRange;
|
|
end;
|
|
|
|
procedure TMRUList.InsertItem(Index: Integer; const S: string);
|
|
begin
|
|
if not (checkItem(S)) then
|
|
exit;
|
|
inherited;
|
|
clearOutOfRange;
|
|
end;
|
|
|
|
procedure TMRUList.Insert(Index: Integer; const S: string);
|
|
begin
|
|
if not (checkItem(S)) then
|
|
exit;
|
|
inherited;
|
|
clearOutOfRange;
|
|
end;
|
|
|
|
procedure TMRUFileList.assign(src: TPersistent);
|
|
var
|
|
i: NativeInt;
|
|
begin
|
|
inherited;
|
|
for i := Count-1 downto 0 do
|
|
if not fileExists(Strings[i]) then
|
|
Delete(i);
|
|
end;
|
|
|
|
function TMRUFileList.checkItem(const S: string): boolean;
|
|
begin
|
|
exit( inherited checkItem(S) and fileExists(S));
|
|
end;
|
|
|
|
procedure saveCompToTxtFile(const aComp: TComponent; const aFilename: string);
|
|
var
|
|
str1, str2: TMemoryStream;
|
|
begin
|
|
str1 := TMemoryStream.Create;
|
|
str2 := TMemoryStream.Create;
|
|
try
|
|
str1.WriteComponent(aComp);
|
|
str1.Position := 0;
|
|
ObjectBinaryToText(str1,str2);
|
|
str2.SaveToFile(aFilename);
|
|
finally
|
|
str1.Free;
|
|
str2.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure loadCompFromTxtFile(const aComp: TComponent; const aFilename: string;
|
|
aPropNotFoundHandler: TPropertyNotFoundEvent = nil; anErrorHandler: TReaderError = nil);
|
|
var
|
|
str1, str2: TMemoryStream;
|
|
rdr: TReader;
|
|
begin
|
|
str1 := TMemoryStream.Create;
|
|
str2 := TMemoryStream.Create;
|
|
try
|
|
str1.LoadFromFile(aFilename);
|
|
str1.Position := 0;
|
|
ObjectTextToBinary(str1,str2);
|
|
str2.Position := 0;
|
|
try
|
|
rdr := TReader.Create(str2, 4096);
|
|
try
|
|
rdr.OnPropertyNotFound := aPropNotFoundHandler;
|
|
rdr.OnError := anErrorHandler;
|
|
rdr.ReadRootComponent(aComp);
|
|
finally
|
|
rdr.Free;
|
|
end;
|
|
except
|
|
end;
|
|
finally
|
|
str1.Free;
|
|
str2.Free;
|
|
end;
|
|
end;
|
|
|
|
function expandFilenameEx(const aBasePath, aFilename: string): string;
|
|
var
|
|
curr: string;
|
|
begin
|
|
curr := '';
|
|
getDir(0, curr);
|
|
try
|
|
if curr <> aBasePath then
|
|
chDir(aBasePath);
|
|
result := expandFileName(aFilename);
|
|
finally
|
|
chDir(curr);
|
|
end;
|
|
end;
|
|
|
|
function patchPlateformPath(const aPath: string): string;
|
|
function patchProc(const src: string; const invalid: char): string;
|
|
var
|
|
i: Integer;
|
|
dir: string;
|
|
begin
|
|
dir := ExtractFileDrive(src);
|
|
if length(dir) > 0 then
|
|
result := src[length(dir)+1..length(src)]
|
|
else
|
|
result := src;
|
|
i := pos(invalid, result);
|
|
if i <> 0 then
|
|
begin
|
|
repeat
|
|
result[i] := directorySeparator;
|
|
i := pos(invalid,result);
|
|
until
|
|
i = 0;
|
|
end;
|
|
result := dir + result;
|
|
end;
|
|
begin
|
|
result := aPath;
|
|
{$IFDEF MSWINDOWS}
|
|
result := patchProc(result, '/');
|
|
result := patchProc(result, ':');
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
result := patchProc(result, '\');
|
|
result := patchProc(result, ':');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure patchPlateformPaths(const sPaths: TStrings);
|
|
var
|
|
i: Integer;
|
|
str: string;
|
|
begin
|
|
for i:= 0 to sPaths.Count-1 do
|
|
begin
|
|
str := sPaths.Strings[i];
|
|
sPaths.Strings[i] := patchPlateformPath(str);
|
|
end;
|
|
end;
|
|
|
|
function patchPlateformExt(const aFilename: string): string;
|
|
var
|
|
ext, newext: string;
|
|
begin
|
|
if aFilename = '' then exit(aFilename);
|
|
//
|
|
ext := extractFileExt(aFilename);
|
|
newext := '';
|
|
result := aFilename[1..length(aFilename)-length(ext)];
|
|
{$IFDEF MSWINDOWS}
|
|
case ext of
|
|
'.so': newext := '.dll';
|
|
'.dylib': newext := '.dll';
|
|
'.a': newext := '.lib';
|
|
'.o': newext := '.obj';
|
|
else newext := ext;
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
case ext of
|
|
'.dll': newext := '.so';
|
|
'.dylib': newext := '.so';
|
|
'.lib': newext := '.a';
|
|
'.obj': newext := '.o';
|
|
'.exe': newext := '';
|
|
else newext := ext;
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF MACOS}
|
|
case ext of
|
|
'.dll': newext := '.dylib';
|
|
'.so': newext := '.dylib';
|
|
'.lib': newext := '.a';
|
|
'.obj': newext := '.o';
|
|
'.exe': newext := '';
|
|
else newext := ext;
|
|
end;
|
|
{$ENDIF}
|
|
result += newext;
|
|
end;
|
|
|
|
function dlgOkCancel(const aMsg: string): TModalResult;
|
|
const
|
|
Btns = [mbOK,mbCancel];
|
|
begin
|
|
exit( MessageDlg('Coedit', aMsg, mtConfirmation, Btns, ''));
|
|
end;
|
|
|
|
function dlgOkInfo(const aMsg: string): TModalResult;
|
|
const
|
|
Btns = [mbOK];
|
|
begin
|
|
exit( MessageDlg('Coedit', aMsg, mtInformation, Btns, ''));
|
|
end;
|
|
|
|
function dlgOkError(const aMsg: string): TModalResult;
|
|
const
|
|
Btns = [mbOK];
|
|
begin
|
|
exit( MessageDlg('Coedit', aMsg, mtError, Btns, ''));
|
|
end;
|
|
|
|
function uniqueObjStr(const aObject: Tobject): string;
|
|
begin
|
|
{$HINTS OFF}{$WARNINGS OFF}
|
|
exit( format('%.8X',[NativeUint(@aObject)]));
|
|
{$HINTS ON}{$WARNINGS ON}
|
|
end;
|
|
|
|
function shortenPath(const aPath: string; charThresh: Word = 60): string;
|
|
var
|
|
i: NativeInt;
|
|
sepCnt: NativeInt;
|
|
drv: string;
|
|
pth1: string;
|
|
begin
|
|
sepCnt := 0;
|
|
if length(aPath) <= charThresh then
|
|
exit(aPath);
|
|
|
|
drv := extractFileDrive(aPath);
|
|
i := length(aPath);
|
|
while(i <> length(drv)+1) do
|
|
begin
|
|
Inc(sepCnt, Byte(aPath[i] = directorySeparator));
|
|
if sepCnt = 2 then
|
|
break;
|
|
Dec(i);
|
|
end;
|
|
pth1 := aPath[i..length(aPath)];
|
|
exit( format('%s%s...%s',[drv,directorySeparator,pth1]) );
|
|
end;
|
|
|
|
function getDocPath: string;
|
|
{$IFDEF WINDOWS}
|
|
var
|
|
PIDL : PItemIDList;
|
|
Folder : array[0..MAX_PATH] of Char;
|
|
const
|
|
CSIDL_APPDATA = $001A;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF WINDOWS}
|
|
PIDL := nil;
|
|
SHGetSpecialFolderLocation(0, CSIDL_APPDATA, PIDL);
|
|
SHGetPathFromIDList(PIDL, Folder);
|
|
result := Folder;
|
|
{$ENDIF}
|
|
{$IFDEF UNIX}
|
|
result := ExpandFileName('~/');
|
|
{$ENDIF}
|
|
result += directorySeparator + 'Coedit' + directorySeparator;
|
|
end;
|
|
|
|
function isFolder(sr: TSearchRec): boolean;
|
|
begin
|
|
result := (sr.Name <> '.') and (sr.Name <> '..' ) and (sr.Name <> '' ) and
|
|
(sr.Attr and faDirectory = faDirectory);
|
|
end;
|
|
|
|
procedure listFiles(aList: TStrings; const aPath: string; recursive: boolean = false);
|
|
var
|
|
sr: TSearchrec;
|
|
procedure tryAdd;
|
|
begin
|
|
if sr.Attr and faDirectory <> faDirectory then
|
|
aList.Add(aPath+ directorySeparator + sr.Name);
|
|
end;
|
|
begin
|
|
if findFirst(aPath + directorySeparator + '*', faAnyFile, sr) = 0 then
|
|
try
|
|
repeat
|
|
tryAdd;
|
|
if recursive then if isFolder(sr) then
|
|
listFiles(aList, aPath + directorySeparator + sr.Name, recursive);
|
|
until
|
|
findNext(sr) <> 0;
|
|
finally
|
|
sysutils.FindClose(sr);
|
|
end;
|
|
end;
|
|
|
|
procedure listFolders(aList: TStrings; const aPath: string);
|
|
var
|
|
sr: TSearchrec;
|
|
begin
|
|
if findFirst(aPath + '*', faAnyFile, sr) = 0 then
|
|
try
|
|
repeat if isFolder(sr) then
|
|
aList.Add(aPath + sr.Name);
|
|
until findNext(sr) <> 0;
|
|
finally
|
|
sysutils.FindClose(sr);
|
|
end;
|
|
end;
|
|
|
|
function hasFolder(const aPath: string): boolean;
|
|
var
|
|
sr: TSearchrec;
|
|
res: boolean;
|
|
begin
|
|
res := false;
|
|
if findFirst(aPath + directorySeparator + '*', faDirectory, sr) = 0 then
|
|
try
|
|
repeat if isFolder(sr) then
|
|
begin
|
|
res := true;
|
|
break;
|
|
end;
|
|
until findNext(sr) <> 0;
|
|
finally
|
|
sysutils.FindClose(sr);
|
|
end;
|
|
result := res;
|
|
end;
|
|
|
|
function listAsteriskPath(const aPath: string; aList: TStrings; someExts: TStrings = nil): boolean;
|
|
var
|
|
pth, ext, fname: string;
|
|
files: TStringList;
|
|
begin
|
|
result := false;
|
|
if aPath = '' then
|
|
exit;
|
|
//
|
|
if aPath[length(aPath)] = '*' then
|
|
begin
|
|
pth := aPath[1..length(aPath)-1];
|
|
if pth[length(pth)] in ['/', '\'] then
|
|
pth := pth[1..length(pth)-1];
|
|
if not directoryExists(pth) then exit(false);
|
|
//
|
|
files := TStringList.Create;
|
|
try
|
|
listFiles(files, pth, true);
|
|
for fname in files do
|
|
begin
|
|
if someExts = nil then
|
|
aList.Add(fname)
|
|
else
|
|
begin
|
|
ext := extractFileExt(fname);
|
|
if someExts.IndexOf(ext) <> -1 then
|
|
aList.Add(fname);
|
|
end;
|
|
end;
|
|
finally
|
|
files.Free;
|
|
end;
|
|
exit(true);
|
|
end;
|
|
exit(false);
|
|
end;
|
|
|
|
procedure listDrives(aList: TStrings);
|
|
{$IFDEF WINDOWS}
|
|
var
|
|
drv: char;
|
|
ltr: string;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF WINDOWS}
|
|
for drv := 'A' to 'Z' do
|
|
begin
|
|
ltr := drv + ':\';
|
|
case GetDriveType(PChar(ltr)) of
|
|
DRIVE_REMOVABLE,
|
|
DRIVE_FIXED,
|
|
DRIVE_REMOTE: aList.Add(ltr);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
// aList.LoadFromFile('/etc/fstab'); // to be parsed
|
|
aList.Add('/home/'); //TODO-cbugfix: AV when scanning non-users folder (e.g replace '/home/'' with '/')
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function shellOpen(const aFilename: string): boolean;
|
|
begin
|
|
{$IFDEF WINDOWS}
|
|
result := ShellExecute(0, 'OPEN', PChar(aFilename), nil, nil, SW_SHOW) > 32;
|
|
{$ENDIF}
|
|
{$IFDEF LINUX}
|
|
with TProcess.Create(nil) do
|
|
try
|
|
Executable := 'xdg-open';
|
|
Parameters.Add(aFilename);
|
|
Execute;
|
|
finally
|
|
result := true;
|
|
Free;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function exeInSysPath(anExeName: string): boolean;
|
|
var
|
|
ext: string;
|
|
begin
|
|
ext := extractFileExt(anExeName);
|
|
if ext <> exeExt then
|
|
anExeName += exeExt;
|
|
if FileExists(anExeName) then
|
|
exit(true)
|
|
else
|
|
exit(ExeSearch(anExeName, '') <> '');
|
|
end;
|
|
|
|
procedure processOutputToStrings(aProcess: TProcess; var aList: TStringList);
|
|
var
|
|
str: TMemoryStream;
|
|
sum: Integer;
|
|
cnt: Integer;
|
|
buffSz: Integer;
|
|
begin
|
|
if not (poUsePipes in aProcess.Options) then
|
|
exit;
|
|
//
|
|
sum := 0;
|
|
str := TMemoryStream.Create;
|
|
try
|
|
buffSz := aProcess.PipeBufferSize;
|
|
// temp fix: messages are cut if the TAsyncProcess version is used on simple TProcess.
|
|
if aProcess is TAsyncProcess then begin
|
|
while aProcess.Output.NumBytesAvailable <> 0 do begin
|
|
str.SetSize(sum + buffSz);
|
|
cnt := aProcess.Output.Read((str.Memory + sum)^, buffSz);
|
|
sum += cnt;
|
|
end;
|
|
end else begin
|
|
repeat
|
|
str.SetSize(sum + buffSz);
|
|
cnt := aProcess.Output.Read((str.Memory + sum)^, buffSz);
|
|
sum += cnt;
|
|
until
|
|
cnt = 0;
|
|
end;
|
|
str.Size := sum;
|
|
aList.LoadFromStream(str);
|
|
finally
|
|
str.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure killProcess(var aProcess: TAsyncProcess);
|
|
begin
|
|
if aProcess = nil then
|
|
exit;
|
|
if aProcess.Running then
|
|
aProcess.Terminate(0);
|
|
aProcess.Free;
|
|
aProcess := nil;
|
|
end;
|
|
|
|
procedure killProcess(var aProcess: TCheckedAsyncProcess);
|
|
begin
|
|
if aProcess = nil then
|
|
exit;
|
|
if aProcess.Running then
|
|
aProcess.Terminate(0);
|
|
aProcess.Free;
|
|
aProcess := nil;
|
|
end;
|
|
|
|
procedure ensureNoPipeIfWait(aProcess: TProcess);
|
|
begin
|
|
if not (poWaitonExit in aProcess.Options) then
|
|
exit;
|
|
//
|
|
aProcess.Options := aProcess.Options - [poStderrToOutPut, poUsePipes];
|
|
aProcess.Options := aProcess.Options + [poNewConsole];
|
|
end;
|
|
|
|
initialization
|
|
RegisterClasses([TMRUList, TMRUFileList]);
|
|
dExtList := TStringList.Create;
|
|
dExtList.AddStrings(['.d', '.D', '.di', '.DI', '.Di', '.dI']);
|
|
finalization
|
|
dExtList.Free;
|
|
end.
|