mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 15:47:54 +02:00
1289 lines
29 KiB
ObjectPascal
1289 lines
29 KiB
ObjectPascal
{
|
|
This file is part of the Free Pascal Test Suite
|
|
Copyright (c) 1999-2000 by Pierre Muller
|
|
|
|
Unit to redirect output and error to files
|
|
|
|
Adapted from code donated to public domain by Schwartz Gabriel 20/03/1993
|
|
|
|
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 Redir;
|
|
Interface
|
|
|
|
{$mode objfpc}
|
|
{$H+}
|
|
{$R-}
|
|
{$ifndef Linux}
|
|
{$ifndef Unix}
|
|
{$S-}
|
|
{$endif}
|
|
{$endif}
|
|
|
|
{$ifdef Go32v2}
|
|
{$define implemented}
|
|
{$endif}
|
|
{$ifdef OS2}
|
|
{$define implemented}
|
|
{$endif}
|
|
|
|
{$ifdef windows}
|
|
{$define implemented}
|
|
{$if (FPC_FULLVERSION > 30300)}
|
|
{$define EXECUTEREDIR_USES_PROCESS}
|
|
{$ENDIF}
|
|
{$define USES_UNIT_PROCESS}
|
|
{$endif}
|
|
|
|
{$IFDEF UNIX}
|
|
{$define implemented}
|
|
{$ifndef MACOS}
|
|
{$if (FPC_FULLVERSION > 30300)}
|
|
{$define EXECUTEREDIR_USES_PROCESS}
|
|
{$ENDIF}
|
|
{$define USES_UNIT_PROCESS}
|
|
{$endif}
|
|
{$ENDIF}
|
|
|
|
Var
|
|
IOStatus : Integer;
|
|
RedirErrorOut,RedirErrorIn,
|
|
RedirErrorError : Integer;
|
|
ExecuteResult : Longint;
|
|
|
|
{------------------------------------------------------------------------------}
|
|
procedure InitRedir;
|
|
function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
|
|
procedure DosExecute(ProgName, ComLine : String);
|
|
|
|
function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
procedure RestoreRedirOut;
|
|
procedure DisableRedirOut;
|
|
procedure EnableRedirOut;
|
|
function ChangeRedirIn(Const Redir : String) : Boolean;
|
|
procedure RestoreRedirIn;
|
|
procedure DisableRedirIn;
|
|
procedure EnableRedirIn;
|
|
function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
procedure RestoreRedirError;
|
|
procedure DisableRedirError;
|
|
procedure EnableRedirError;
|
|
procedure RedirDisableAll;
|
|
procedure RedirEnableAll;
|
|
|
|
{ unused in UNIX }
|
|
const
|
|
UseComSpec : boolean = true;
|
|
|
|
Implementation
|
|
|
|
//or defined(windows)
|
|
{$if defined(macos) or defined(shell_implemented) or defined(go32v2)}
|
|
{$define usedos}
|
|
{$endif}
|
|
|
|
{$if defined(windows) and not defined(usedos)}
|
|
{$ifdef ver2_4}
|
|
{$define redirexecuteprocess}
|
|
{$endif}
|
|
{$endif}
|
|
|
|
Uses
|
|
{$ifdef go32v2}
|
|
go32,
|
|
{$endif go32v2}
|
|
{$ifdef windows}
|
|
windows,
|
|
{$endif windows}
|
|
{$IFDEF OS2}
|
|
{$IFNDEF EMX}
|
|
DosCalls,
|
|
{$ENDIF EMX}
|
|
{$ENDIF OS2}
|
|
{$ifdef unix}
|
|
baseunix,
|
|
unix,
|
|
{$endif unix}
|
|
{$ifdef redirexecuteprocess}
|
|
sysconst,
|
|
|
|
{$endif}
|
|
|
|
{$ifdef USES_UNIT_PROCESS}
|
|
process,
|
|
{$endif USES_UNIT_PROCESS}
|
|
|
|
{$ifdef usedos}
|
|
dos;
|
|
{$else}
|
|
sysutils;
|
|
{$endif}
|
|
|
|
Const
|
|
{$ifdef UNIX}
|
|
DirSep='/';
|
|
listsep = [';',':'];
|
|
exeext = '';
|
|
{$else UNIX}
|
|
{$ifdef MACOS}
|
|
DirSep=':';
|
|
listsep = [','];
|
|
exeext = '';
|
|
{$else MACOS}
|
|
DirSep='\';
|
|
listsep = [';'];
|
|
exeext = '.exe';
|
|
{$endif MACOS}
|
|
{$endif UNIX}
|
|
|
|
{$ifndef usedos}
|
|
{ code from: }
|
|
{ Lithuanian Text Tool version 0.9.0 (2001-04-19) }
|
|
{ Copyright (c) 1999-2001 Marius Gedminas <mgedmin@delfi.lt> }
|
|
{ (GPLv2 or later) }
|
|
|
|
function FExpand(const S: string): string;
|
|
begin
|
|
FExpand := ExpandFileName(S);
|
|
end;
|
|
|
|
type
|
|
PathStr = string;
|
|
DirStr = string;
|
|
NameStr = string;
|
|
ExtStr = string;
|
|
|
|
procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr; var Ext: ExtStr);
|
|
begin
|
|
Dir := ExtractFilePath(Path);
|
|
Name := ChangeFileExt(ExtractFileName(Path), '');
|
|
Ext := ExtractFileExt(Path);
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
var
|
|
FIN,FOUT,FERR : ^File;
|
|
RedirStdErrToStdOut,
|
|
RedirChangedOut,
|
|
RedirChangedIn : Boolean;
|
|
RedirChangedError : Boolean;
|
|
InRedirDisabled,OutRedirDisabled,ErrorRedirDisabled : Boolean;
|
|
|
|
|
|
{*****************************************************************************
|
|
Helpers
|
|
*****************************************************************************}
|
|
|
|
function FixPath(const s:string):string;
|
|
var
|
|
i : longint;
|
|
begin
|
|
{ Fix separator }
|
|
setlength(fixpath,length(s));
|
|
for i:=1 to length(s) do
|
|
if s[i] in ['/','\'] then
|
|
fixpath[i]:=DirSep
|
|
else
|
|
fixpath[i]:=s[i];
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Dos
|
|
*****************************************************************************}
|
|
|
|
{$ifdef implemented}
|
|
|
|
|
|
{$ifndef usedos}
|
|
{$if defined(ver2_4_0) or defined(ver2_4_1)}
|
|
|
|
Type
|
|
TExecuteFlags= set of (ExecInheritsHandles);
|
|
{$ifdef redirexecuteprocess}
|
|
|
|
function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
|
|
// win specific function
|
|
var
|
|
SI: TStartupInfo;
|
|
PI: TProcessInformation;
|
|
Proc : THandle;
|
|
l : DWord;
|
|
CommandLine : ansistring;
|
|
e : EOSError;
|
|
ExecInherits : longbool;
|
|
begin
|
|
FillChar(SI, SizeOf(SI), 0);
|
|
SI.cb:=SizeOf(SI);
|
|
SI.wShowWindow:=1;
|
|
{ always surround the name of the application by quotes
|
|
so that long filenames will always be accepted. But don't
|
|
do it if there are already double quotes, since Win32 does not
|
|
like double quotes which are duplicated!
|
|
}
|
|
if pos('"',path)=0 then
|
|
CommandLine:='"'+path+'"'
|
|
else
|
|
CommandLine:=path;
|
|
if ComLine <> '' then
|
|
CommandLine:=Commandline+' '+ComLine+#0
|
|
else
|
|
CommandLine := CommandLine + #0;
|
|
|
|
ExecInherits:=ExecInheritsHandles in Flags;
|
|
|
|
if not CreateProcess(nil, pchar(CommandLine),
|
|
Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
|
|
begin
|
|
e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
|
|
e.ErrorCode:=GetLastError;
|
|
raise e;
|
|
end;
|
|
Proc:=PI.hProcess;
|
|
if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
|
|
begin
|
|
GetExitCodeProcess(Proc,l);
|
|
CloseHandle(Proc);
|
|
CloseHandle(PI.hThread);
|
|
result:=l;
|
|
end
|
|
else
|
|
begin
|
|
e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
|
|
e.ErrorCode:=GetLastError;
|
|
CloseHandle(Proc);
|
|
CloseHandle(PI.hThread);
|
|
raise e;
|
|
end;
|
|
end;
|
|
{$else}
|
|
{$ifndef USES_UNIT_PROCESS}
|
|
function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
|
|
begin
|
|
result:=ExecuteProcess(path,comline);
|
|
end;
|
|
{$endif ndef USES_UNIT_PROCESS}
|
|
{$endif}
|
|
{$ifend}
|
|
{$endif}
|
|
|
|
|
|
{$ifndef windows}
|
|
var
|
|
TempHOut, TempHIn,TempHError : longint;
|
|
{$endif ndef windows}
|
|
|
|
{
|
|
For Unix the following functions exist
|
|
Function fpdup(oldfile:longint;var newfile:longint):Boolean;
|
|
Function fpdup2(oldfile,newfile:longint):Boolean;
|
|
Function fpClose(fd:longint):boolean;
|
|
}
|
|
{$ifdef go32v2}
|
|
|
|
function fpdup(fh : longint) : longint;
|
|
var
|
|
Regs : Registers;
|
|
begin
|
|
Regs.ah:=$45;
|
|
Regs.bx:=fh;
|
|
MsDos (Regs);
|
|
If (Regs.Flags and fCarry)=0 then
|
|
fpdup:=Regs.Ax
|
|
else
|
|
fpdup:=-1;
|
|
end;
|
|
|
|
function fpdup2(fh,nh : longint) : longint;
|
|
var
|
|
Regs : Registers;
|
|
begin
|
|
fpdup2:=0;
|
|
If fh=nh then
|
|
exit;
|
|
Regs.ah:=$46;
|
|
Regs.bx:=fh;
|
|
Regs.cx:=nh;
|
|
MsDos (Regs);
|
|
If (Regs.Flags and fCarry)<>0 then
|
|
fpdup2:=-1;
|
|
end;
|
|
|
|
Function fpclose (Handle : Longint) : boolean;
|
|
var Regs: registers;
|
|
begin
|
|
Regs.Eax := $3e00;
|
|
Regs.Ebx := Handle;
|
|
MsDos(Regs);
|
|
fpclose:=(Regs.Flags and fCarry)=0;
|
|
end;
|
|
|
|
{$endif def go32v2}
|
|
|
|
{$ifdef windows}
|
|
Function fpclose (Handle : Longint) : boolean;
|
|
begin
|
|
{ Do we need this ?? }
|
|
fpclose:=true;
|
|
end;
|
|
{$endif}
|
|
|
|
{$IFDEF OS2}
|
|
{$IFDEF EMX}
|
|
{$ASMMODE INTEL}
|
|
function fpDup (FH: longint): longint; assembler;
|
|
asm
|
|
mov ebx, eax
|
|
mov ah, 45h
|
|
call syscall
|
|
jnc @fpdup_end
|
|
mov eax, -1
|
|
@fpdup_end:
|
|
end;
|
|
|
|
function fpDup2 (FH, NH: longint): longint; assembler;
|
|
asm
|
|
cmp eax, edx
|
|
jnz @fpdup2_go
|
|
mov eax, 0
|
|
jmp @fpdup2_end
|
|
@fpdup2_go:
|
|
push ebx
|
|
mov ebx, eax
|
|
mov ecx, edx
|
|
mov ah, 46h
|
|
call syscall
|
|
pop ebx
|
|
jnc @fpdup2_end
|
|
mov eax, -1
|
|
@fpdup2_end:
|
|
end;
|
|
|
|
function fpClose (Handle: longint): boolean; assembler;
|
|
asm
|
|
push ebx
|
|
mov ebx, eax
|
|
mov ah, 3Eh
|
|
call syscall
|
|
pop ebx
|
|
mov eax, 1
|
|
jnc @fpclose_end
|
|
dec eax
|
|
end;
|
|
|
|
{$ASMMODE DEFAULT}
|
|
{$ELSE EMX}
|
|
|
|
function fpDup (FH: longint): longint;
|
|
var
|
|
NH: THandle;
|
|
begin
|
|
NH := THandle (-1);
|
|
if DosDupHandle (THandle (FH), NH) = 0 then
|
|
fpDup := longint (NH)
|
|
else
|
|
fpDup := -1;
|
|
end;
|
|
|
|
function fpDup2 (FH, NH: longint): longint;
|
|
begin
|
|
if FH = NH then
|
|
fpDup2 := 0
|
|
else
|
|
if DosDupHandle (THandle (FH), THandle (NH)) <> 0 then
|
|
fpDup2 := -1;
|
|
end;
|
|
|
|
function fpClose (Handle: longint): boolean;
|
|
begin
|
|
fpClose := DosClose (THandle (Handle)) = 0;
|
|
end;
|
|
{$ENDIF EMX}
|
|
{$ENDIF OS2}
|
|
|
|
|
|
{$I-}
|
|
function FileExist(const FileName : PathStr) : Boolean;
|
|
{$ifdef usedos}
|
|
var
|
|
f : file;
|
|
Attr : word;
|
|
{$endif}
|
|
begin
|
|
{$ifdef usedos}
|
|
Assign(f, FileName);
|
|
GetFAttr(f, Attr);
|
|
FileExist := DosError = 0;
|
|
{$else}
|
|
FileExist := Sysutils.FileExists(filename);
|
|
{$endif}
|
|
end;
|
|
|
|
function CompleteDir(const Path: string): string;
|
|
begin
|
|
{ keep c: untouched PM }
|
|
if (Path<>'') and (Path[Length(Path)]<>DirSep) and
|
|
(Path[Length(Path)]<>':') then
|
|
CompleteDir:=Path+DirSep
|
|
else
|
|
CompleteDir:=Path;
|
|
end;
|
|
|
|
|
|
function LocateExeFile(var FileName:string): boolean;
|
|
var
|
|
dir,s: string;
|
|
d: dirstr;
|
|
n: namestr;
|
|
e: extstr;
|
|
i : longint;
|
|
begin
|
|
LocateExeFile:=False;
|
|
if FileExist(FileName) then
|
|
begin
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
end;
|
|
|
|
Fsplit(Filename,d,n,e);
|
|
|
|
if (e='') and FileExist(FileName+exeext) then
|
|
begin
|
|
FileName:=FileName+exeext;
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
end;
|
|
|
|
{$ifdef usedos}
|
|
S:=GetEnv('PATH');
|
|
{$else}
|
|
S:=GetEnvironmentVariable('PATH');
|
|
{$endif}
|
|
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 FileExist(Dir+FileName) then
|
|
Begin
|
|
FileName:=Dir+FileName;
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
End;
|
|
end;
|
|
end;
|
|
|
|
|
|
{............................................................................}
|
|
|
|
function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
begin
|
|
ChangeRedirOut:=False;
|
|
If Redir = '' then Exit;
|
|
Assign (FOUT^, Redir);
|
|
If AppendToFile and FileExist(Redir) then
|
|
Begin
|
|
Reset(FOUT^,1);
|
|
Seek(FOUT^,FileSize(FOUT^));
|
|
End else Rewrite (FOUT^);
|
|
|
|
RedirErrorOut:=IOResult;
|
|
IOStatus:=RedirErrorOut;
|
|
If IOStatus <> 0 then Exit;
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
OldHandleOut:=Handles^[StdOutputHandle];
|
|
Handles^[StdOutputHandle]:=Handles^[FileRec (FOUT^).Handle];
|
|
ChangeRedirOut:=True;
|
|
OutRedirDisabled:=False;
|
|
{$else}
|
|
{$ifdef windows}
|
|
if SetStdHandle(Std_Output_Handle,FileRec(FOUT^).Handle) then
|
|
{$else not windows}
|
|
TempHOut:=fpdup(StdOutputHandle);
|
|
fpdup2(FileRec(FOUT^).Handle,StdOutputHandle);
|
|
if (TempHOut<>UnusedHandle) and
|
|
(StdOutputHandle<>UnusedHandle) then
|
|
{$endif not windows}
|
|
begin
|
|
ChangeRedirOut:=True;
|
|
OutRedirDisabled:=False;
|
|
end;
|
|
{$endif def FPC}
|
|
RedirChangedOut:=True;
|
|
end;
|
|
|
|
function ChangeRedirIn(Const Redir : String) : Boolean;
|
|
begin
|
|
ChangeRedirIn:=False;
|
|
If Redir = '' then Exit;
|
|
Assign (FIN^, Redir);
|
|
Reset(FIN^,1);
|
|
|
|
RedirErrorIn:=IOResult;
|
|
IOStatus:=RedirErrorIn;
|
|
If IOStatus <> 0 then Exit;
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
OldHandleIn:=Handles^[StdInputHandle];
|
|
Handles^[StdInputHandle]:=Handles^[FileRec (FIN^).Handle];
|
|
ChangeRedirIn:=True;
|
|
InRedirDisabled:=False;
|
|
{$else}
|
|
{$ifdef windows}
|
|
if SetStdHandle(Std_Input_Handle,FileRec(FIN^).Handle) then
|
|
{$else not windows}
|
|
TempHIn:=fpdup(StdInputHandle);
|
|
fpdup2(FileRec(FIn^).Handle,StdInputHandle);
|
|
if (TempHIn<>UnusedHandle) and
|
|
(StdInputHandle<>UnusedHandle) then
|
|
{$endif not windows}
|
|
begin
|
|
ChangeRedirIn:=True;
|
|
InRedirDisabled:=False;
|
|
end;
|
|
{$endif def FPC}
|
|
RedirChangedIn:=True;
|
|
end;
|
|
|
|
|
|
function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
var
|
|
PF : ^File;
|
|
begin
|
|
ChangeRedirError:=False;
|
|
If Redir = '' then
|
|
Exit;
|
|
RedirStdErrToStdOut:=(Redir='stdout');
|
|
if RedirStdErrToStdOut then
|
|
begin
|
|
PF:=FOut;
|
|
end
|
|
else
|
|
begin
|
|
Assign (FERR^, Redir);
|
|
If AppendToFile and FileExist(Redir) then
|
|
Begin
|
|
Reset(FERR^,1);
|
|
Seek(FERR^,FileSize(FERR^));
|
|
End
|
|
else
|
|
Rewrite (FERR^);
|
|
|
|
RedirErrorError:=IOResult;
|
|
IOStatus:=RedirErrorError;
|
|
If IOStatus <> 0 then Exit;
|
|
PF:=FErr;
|
|
end;
|
|
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
OldHandleError:=Handles^[StdErrorHandle];
|
|
Handles^[StdErrorHandle]:=Handles^[FileRec (PF^).Handle];
|
|
ChangeRedirError:=True;
|
|
ErrorRedirDisabled:=False;
|
|
{$else}
|
|
{$ifdef windows}
|
|
if SetStdHandle(Std_Error_Handle,FileRec(PF^).Handle) then
|
|
{$else not windows}
|
|
TempHError:=fpdup(StdErrorHandle);
|
|
fpdup2(FileRec(PF^).Handle,StdErrorHandle);
|
|
if (TempHError<>UnusedHandle) and
|
|
(StdErrorHandle<>UnusedHandle) then
|
|
{$endif not windows}
|
|
begin
|
|
ChangeRedirError:=True;
|
|
ErrorRedirDisabled:=False;
|
|
end;
|
|
{$endif}
|
|
RedirChangedError:=True;
|
|
end;
|
|
|
|
|
|
procedure RestoreRedirOut;
|
|
|
|
begin
|
|
If not RedirChangedOut then Exit;
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Output_Handle,StdOutputHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHOut,StdOutputHandle);
|
|
{$endif not windows}
|
|
Close (FOUT^);
|
|
{$ifndef windows}
|
|
fpclose(TempHOut);
|
|
{$endif ndef windows}
|
|
RedirChangedOut:=false;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure RestoreRedirIn;
|
|
|
|
begin
|
|
If not RedirChangedIn then Exit;
|
|
{$ifndef FPC}
|
|
Handles^[StdInputHandle]:=OldHandleIn;
|
|
OldHandleIn:=StdInputHandle;
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Input_Handle,StdInputHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHIn,StdInputHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
Close (FIn^);
|
|
{$ifndef windows}
|
|
fpclose(TempHIn);
|
|
{$endif ndef windows}
|
|
RedirChangedIn:=false;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure DisableRedirIn;
|
|
|
|
begin
|
|
If not RedirChangedIn then Exit;
|
|
If InRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles^[StdInputHandle]:=OldHandleIn;
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Input_Handle,StdInputHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHIn,StdInputHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
InRedirDisabled:=True;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure EnableRedirIn;
|
|
|
|
begin
|
|
If not RedirChangedIn then Exit;
|
|
If not InRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
Handles^[StdInputHandle]:=Handles^[FileRec (FIn^).Handle];
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Input_Handle,FileRec(FIn^).Handle);
|
|
{$else not windows}
|
|
fpdup2(FileRec(FIn^).Handle,StdInputHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
InRedirDisabled:=False;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure DisableRedirOut;
|
|
|
|
begin
|
|
If not RedirChangedOut then Exit;
|
|
If OutRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles^[StdOutputHandle]:=OldHandleOut;
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Output_Handle,StdOutputHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHOut,StdOutputHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
OutRedirDisabled:=True;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure EnableRedirOut;
|
|
|
|
begin
|
|
If not RedirChangedOut then Exit;
|
|
If not OutRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
Handles^[StdOutputHandle]:=Handles^[FileRec (FOut^).Handle];
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Output_Handle,FileRec(FOut^).Handle);
|
|
{$else not windows}
|
|
fpdup2(FileRec(FOut^).Handle,StdOutputHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
OutRedirDisabled:=False;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure RestoreRedirError;
|
|
|
|
begin
|
|
If not RedirChangedError then Exit;
|
|
{$ifndef FPC}
|
|
Handles^[StdErrorHandle]:=OldHandleError;
|
|
OldHandleError:=StdErrorHandle;
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Error_Handle,StdErrorHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHError,StdErrorHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
{ don't close when redirected to STDOUT }
|
|
if not RedirStdErrToStdOut then
|
|
Close (FERR^);
|
|
{$ifndef windows}
|
|
fpclose(TempHError);
|
|
{$endif ndef windows}
|
|
RedirChangedError:=false;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure DisableRedirError;
|
|
|
|
begin
|
|
If not RedirChangedError then Exit;
|
|
If ErrorRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles^[StdErrorHandle]:=OldHandleError;
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Error_Handle,StdErrorHandle);
|
|
{$else not windows}
|
|
fpdup2(TempHError,StdErrorHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
ErrorRedirDisabled:=True;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure EnableRedirError;
|
|
|
|
begin
|
|
If not RedirChangedError then Exit;
|
|
If not ErrorRedirDisabled then Exit;
|
|
{$ifndef FPC}
|
|
Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
|
|
Handles^[StdErrorHandle]:=Handles^[FileRec (FErr^).Handle];
|
|
{$else}
|
|
{$ifdef windows}
|
|
SetStdHandle(Std_Error_Handle,FileRec(FErr^).Handle);
|
|
{$else not windows}
|
|
fpdup2(FileRec(FERR^).Handle,StdErrorHandle);
|
|
{$endif not windows}
|
|
{$endif}
|
|
ErrorRedirDisabled:=False;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
{$ifdef EXECUTEREDIR_USES_PROCESS}
|
|
function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
|
|
|
|
const
|
|
max_count = 60000;
|
|
|
|
var
|
|
P : TProcess;
|
|
|
|
begin
|
|
Result:=false;
|
|
IOstatus:=0;
|
|
P := TProcess.Create(nil);
|
|
try
|
|
P.CommandLine:=Progname + ' ' + ComLine;
|
|
P.InputDescriptor.FileName:=RedirStdIn;
|
|
P.OutputDescriptor.FileName:=RedirStdOut;
|
|
if RedirStdErr='stdout' then
|
|
P.Options:=P.options+[poStdErrToOutput]
|
|
else
|
|
P.ErrorDescriptor.FileName:=RedirStdErr;
|
|
try
|
|
P.Execute;
|
|
Result:=P.WaitOnExit(max_count);
|
|
except
|
|
on e : exception do
|
|
begin
|
|
IOStatus:=2;
|
|
writeln(stderr,'ExecuteRedir generated an exception: ',E.Message);
|
|
end;
|
|
end;
|
|
if Result then
|
|
ExecuteResult:=P.ExitCode
|
|
else if (IOStatus<>0) then
|
|
ExecuteResult:=IOStatus*1000
|
|
else
|
|
begin
|
|
Writeln(stderr,'Terminate requested for ',Progname,' ',ComLine);
|
|
{ Issue it also to output, so it gets added to log file
|
|
if ExecuteRedir is in use }
|
|
Writeln('Terminate requested for ',Progname,' ',ComLine);
|
|
Repeat
|
|
P.Terminate(255);
|
|
Sleep(10);
|
|
Until not P.Running;
|
|
ExecuteResult:=1000+P.ExitCode;
|
|
end;
|
|
Result:=ExecuteResult=0;
|
|
finally
|
|
P.Free;
|
|
end;
|
|
end;
|
|
{$ELSE}
|
|
|
|
function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
|
|
Begin
|
|
RedirErrorOut:=0; RedirErrorIn:=0; RedirErrorError:=0;
|
|
ExecuteResult:=0;
|
|
IOStatus:=0;
|
|
if RedirStdIn<>'' then
|
|
ChangeRedirIn(RedirStdIn);
|
|
if RedirStdOut<>'' then
|
|
ChangeRedirOut(RedirStdOut,false);
|
|
if RedirStdErr<>'stderr' then
|
|
ChangeRedirError(RedirStdErr,false);
|
|
DosExecute(ProgName,ComLine);
|
|
RestoreRedirOut;
|
|
RestoreRedirIn;
|
|
RestoreRedirError;
|
|
ExecuteRedir:=(IOStatus=0) and (RedirErrorOut=0) and
|
|
(RedirErrorIn=0) and (RedirErrorError=0) and
|
|
(ExecuteResult=0);
|
|
End;
|
|
{$ENDIF}
|
|
|
|
{............................................................................}
|
|
|
|
procedure RedirDisableAll;
|
|
begin
|
|
If RedirChangedIn and not InRedirDisabled then
|
|
DisableRedirIn;
|
|
If RedirChangedOut and not OutRedirDisabled then
|
|
DisableRedirOut;
|
|
If RedirChangedError and not ErrorRedirDisabled then
|
|
DisableRedirError;
|
|
end;
|
|
|
|
{............................................................................}
|
|
|
|
procedure RedirEnableAll;
|
|
begin
|
|
If RedirChangedIn and InRedirDisabled then
|
|
EnableRedirIn;
|
|
If RedirChangedOut and OutRedirDisabled then
|
|
EnableRedirOut;
|
|
If RedirChangedError and ErrorRedirDisabled then
|
|
EnableRedirError;
|
|
end;
|
|
|
|
|
|
procedure InitRedir;
|
|
begin
|
|
end;
|
|
|
|
{$else not implemented}
|
|
|
|
|
|
{*****************************************************************************
|
|
Fake
|
|
*****************************************************************************}
|
|
|
|
{$IFDEF SHELL_IMPLEMENTED}
|
|
{$I-}
|
|
function FileExist(const FileName : PathStr) : Boolean;
|
|
var
|
|
f : file;
|
|
Attr : word;
|
|
begin
|
|
Assign(f, FileName);
|
|
GetFAttr(f, Attr);
|
|
FileExist := DosError = 0;
|
|
end;
|
|
|
|
function CompleteDir(const Path: string): string;
|
|
begin
|
|
{ keep c: untouched PM }
|
|
if (Path<>'') and (Path[Length(Path)]<>DirSep) and
|
|
(Path[Length(Path)]<>':') then
|
|
CompleteDir:=Path+DirSep
|
|
else
|
|
CompleteDir:=Path;
|
|
end;
|
|
|
|
function LocateExeFile(var FileName:string): boolean;
|
|
var
|
|
{$IFDEF USEDOS}
|
|
dir,s,d,n,e : shortstring;
|
|
{$ELSE USEDOS}
|
|
dir,s,d,n,e : string;
|
|
{$ENDIF USEDOS}
|
|
i : longint;
|
|
begin
|
|
LocateExeFile:=False;
|
|
if FileExist(FileName) then
|
|
begin
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
end;
|
|
|
|
Fsplit(Filename,d,n,e);
|
|
|
|
if (e='') and FileExist(FileName+exeext) then
|
|
begin
|
|
FileName:=FileName+exeext;
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
end;
|
|
{$ifdef macos}
|
|
S:=GetEnv('Commands');
|
|
{$else}
|
|
S:=GetEnv('PATH');
|
|
{$endif}
|
|
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 FileExist(Dir+FileName) then
|
|
Begin
|
|
FileName:=Dir+FileName;
|
|
LocateExeFile:=true;
|
|
Exit;
|
|
End;
|
|
end;
|
|
end;
|
|
|
|
function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
|
|
var
|
|
CmdLine2: string;
|
|
|
|
begin
|
|
{$ifdef macos}
|
|
if Lowercase(RedirStdIn) = 'stdin' then RedirStdIn := 'Dev:StdIn';
|
|
if Lowercase(RedirStdOut) = 'stdout' then RedirStdOut := 'Dev:Output';
|
|
if Lowercase(RedirStdOut) = 'stderr' then RedirStdOut := 'Dev:Error';
|
|
if Lowercase(RedirStdErr) = 'stdout' then RedirStdErr := 'Dev:Output';
|
|
if Lowercase(RedirStdErr) = 'stderr' then RedirStdErr := 'Dev:Error';
|
|
{$endif macos}
|
|
|
|
CmdLine2 := ComLine;
|
|
if RedirStdIn <> '' then CmdLine2 := CmdLine2 + ' < ' + RedirStdIn;
|
|
|
|
{$ifndef macos}
|
|
if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
|
|
if RedirStdErr <> '' then
|
|
begin
|
|
if RedirStdErr = RedirStdOut then
|
|
CmdLine2 := CmdLine2 + ' 2>&1'
|
|
else
|
|
CmdLine2 := CmdLine2 + ' 2> ' + RedirStdErr;
|
|
end;
|
|
{$else macos}
|
|
if RedirStdErr <> RedirStdOut then
|
|
if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
|
|
if RedirStdErr <> '' then
|
|
begin
|
|
if RedirStdErr = RedirStdOut then
|
|
CmdLine2 := CmdLine2 + ' ' + #183 + ' ' + RedirStdErr {#183 is "capital sigma" char in MacRoman}
|
|
else
|
|
CmdLine2 := CmdLine2 + ' ' + #179 + ' ' + RedirStdErr; {#179 is "greater or equal" char in MacRoman}
|
|
end;
|
|
{$endif macos}
|
|
|
|
DosExecute (ProgName, CmdLine2);
|
|
ExecuteRedir:=(IOStatus=0) and (ExecuteResult=0);
|
|
end;
|
|
|
|
{$ELSE SHELL_IMPLEMENTED}
|
|
function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
|
|
begin
|
|
ExecuteRedir:=false;
|
|
end;
|
|
{$ENDIF SHELL_IMPLEMENTED}
|
|
|
|
function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
begin
|
|
ChangeRedirOut:=false;
|
|
end;
|
|
|
|
|
|
procedure RestoreRedirOut;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure DisableRedirOut;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure EnableRedirOut;
|
|
begin
|
|
end;
|
|
|
|
|
|
function ChangeRedirIn(Const Redir : String) : Boolean;
|
|
begin
|
|
ChangeRedirIn:=false;
|
|
end;
|
|
|
|
|
|
procedure RestoreRedirIn;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure DisableRedirIn;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure EnableRedirIn;
|
|
begin
|
|
end;
|
|
|
|
|
|
function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
|
|
begin
|
|
ChangeRedirError:=false;
|
|
end;
|
|
|
|
|
|
procedure RestoreRedirError;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure DisableRedirError;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure EnableRedirError;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure RedirDisableAll;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure RedirEnableAll;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure InitRedir;
|
|
begin
|
|
end;
|
|
{$endif not implemented}
|
|
|
|
{............................................................................}
|
|
{$ifdef UNIX}
|
|
function TransformfpSystemToShell(s:cint):cint;
|
|
// transforms standarized (fp)System(3) result to the conventions of the old Unix.shell function.
|
|
begin
|
|
if s=-1 then exit(-1);
|
|
if wifexited(s) then
|
|
TransformfpSystemToShell:=wexitstatus(s)
|
|
else if (s>0) then
|
|
TransformfpSystemToShell:=-s
|
|
else
|
|
TransformfpSystemToShell:=s;
|
|
end;
|
|
{$endif def UNIX}
|
|
|
|
|
|
|
|
{****************************************************************************
|
|
Helpers
|
|
****************************************************************************}
|
|
|
|
{$ifdef USES_UNIT_PROCESS}
|
|
const
|
|
max_count = 60000; { should be 60 seconds }
|
|
|
|
function ExecuteProcess(const Path: string; const ComLine: string; Flags:TExecuteFlags=[]): integer;
|
|
var
|
|
P: TProcess;
|
|
counter : longint;
|
|
TerminateSentCount : longint;
|
|
|
|
begin
|
|
result := -1;
|
|
TerminateSentCount:=0;
|
|
|
|
P := TProcess.Create(nil);
|
|
try
|
|
P.CommandLine := Path + ' ' + ComLine;
|
|
|
|
P.InheritHandles:=(execinheritshandles in flags);
|
|
|
|
P.Execute;
|
|
{$if FPC_FULLVERSION < 30100}
|
|
{$ifdef Windows}
|
|
WaitForSingleObject(P.ProcessHandle,max_count);
|
|
counter:=max_count;
|
|
{$else not Windows}
|
|
counter:=0;
|
|
{$endif not Windows}
|
|
{$else}
|
|
P.WaitOnExit(max_count);
|
|
counter:=max_count;
|
|
{$endif}
|
|
|
|
while P.Running do
|
|
begin
|
|
if counter>max_count then
|
|
begin
|
|
P.Terminate(255);
|
|
if TerminateSentCount=0 then
|
|
{ also write ComLine in order to know which test is not ended in time }
|
|
begin
|
|
Writeln(stderr,'Terminate requested for ',Path,' ',ComLine);
|
|
{ Issue it also to output, so it gets added to log file
|
|
if ExecuteRedir is in use }
|
|
Writeln('Terminate requested for ',Path,' ',ComLine);
|
|
end;
|
|
Inc(TerminateSentCount);
|
|
end;
|
|
|
|
Sleep(1);
|
|
inc(counter);
|
|
end;
|
|
|
|
{ Be sure to return a non-zero value if Terminate was requested }
|
|
if (TerminateSentCount>0) and (P.ExitStatus>=0) then
|
|
result := 1000 + P.ExitStatus
|
|
else
|
|
result := P.ExitStatus;
|
|
finally
|
|
P.Free;
|
|
end;
|
|
end;
|
|
{$endif HAS_UNIT_PROCESS}
|
|
|
|
|
|
procedure DosExecute(ProgName, ComLine : String);
|
|
|
|
|
|
Begin
|
|
{$IfDef MsDos}
|
|
SmallHeap;
|
|
{$EndIf MsDos}
|
|
{$ifdef usedos}
|
|
SwapVectors;
|
|
{$endif usedos}
|
|
{ Must use shell/fpsystem() for *nix for the wildcard expansion (PFV) }
|
|
{$ifdef UNIX}
|
|
IOStatus:=0;
|
|
ExecuteResult:=Transformfpsystemtoshell(fpsystem((FixPath(Progname)+' '+Comline)));
|
|
if ExecuteResult<0 then
|
|
begin
|
|
IOStatus:=(-ExecuteResult) and $7f;
|
|
ExecuteResult:=((-ExecuteResult) and $ff00) shr 8;
|
|
end;
|
|
{$else}
|
|
{$ifdef windows}
|
|
|
|
{ Avoid dialog boxes if dll loading fails }
|
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
{$endif windows}
|
|
If UseComSpec then
|
|
begin
|
|
{$ifndef usedos}
|
|
try
|
|
ExecuteResult:=ExecuteProcess (Getenvironmentvariable('COMSPEC'),'/C '+FixPath(progname)+' '+Comline,[ExecInheritsHandles])
|
|
except
|
|
on e : exception do
|
|
IOStatus:=2;
|
|
end;
|
|
{$else}
|
|
DosError:=0;
|
|
Exec (Getenv('COMSPEC'),'/C '+FixPath(progname)+' '+Comline);
|
|
IOStatus:=DosError;
|
|
ExecuteResult:=DosExitCode;
|
|
{$endif}
|
|
end
|
|
else
|
|
begin
|
|
if LocateExeFile(progname) then
|
|
begin
|
|
{$ifndef usedos}
|
|
try
|
|
ExecuteResult:=ExecuteProcess(ProgName,Comline,[execinheritshandles])
|
|
except
|
|
on e : exception do
|
|
IOStatus:=2;
|
|
end;
|
|
{$else}
|
|
doserror:=0;
|
|
{$ifdef macos}
|
|
Dos.Exec(''''+ProgName+'''',Comline); {Quotes needed !}
|
|
{$else}
|
|
Dos.Exec(ProgName,Comline);
|
|
{$endif}
|
|
IOStatus:=DosError;
|
|
ExecuteResult:=DosExitCode;
|
|
{$endif}
|
|
end
|
|
else
|
|
IOStatus:=2
|
|
;
|
|
end;
|
|
{$ifdef windows}
|
|
SetErrorMode(0);
|
|
{$endif windows}
|
|
|
|
{$endif}
|
|
{$ifdef usedos}
|
|
SwapVectors;
|
|
{$endif}
|
|
{$ifdef CPU86}
|
|
{ reset the FPU }
|
|
{$asmmode att}
|
|
asm
|
|
fninit
|
|
end;
|
|
{$endif CPU86}
|
|
{$IfDef MsDos}
|
|
Fullheap;
|
|
{$EndIf MsDos}
|
|
End;
|
|
|
|
{*****************************************************************************
|
|
Initialize
|
|
*****************************************************************************}
|
|
|
|
initialization
|
|
New(FIn); New(FOut); New(FErr);
|
|
|
|
finalization
|
|
Dispose(FIn); Dispose(FOut); Dispose(FErr);
|
|
End.
|