fpc/tests/utils/redir.pp
Jonas Maebe 060d81b8fa Merged revisions 11878,11881-11882,11889,11891-11893,11895,11899-11902,11935,11938,12212,12304,12308-12310,12316,12330-12332,12334,12339-12340 via svnmerge from
svn+ssh://jonas@svn.freepascal.org/FPC/svn/fpc/branches/wpo

........
r11878 | jonas | 2008-10-11 02:25:18 +0200 (Sat, 11 Oct 2008) | 19 lines

  + initial implementation of whole-program optimisation framework
  + implementation of whole-program devirtualisation
  o use:
     a) generate whole-program optimisation information (no need
        to completely compile the program and all of its units
        with -OW/-FW, only the main program is sufficient)
      fpc -OWdevirtcalls -FWmyprog.wpo myprog
     b) use it to optimise the program
      fpc -B -Owdevirtcalls -Fwmyprog.wpo myprog
     (the -B is not required, but only sources recompiled during
      the second pass will actually be optimised -- if you want,
      you can even rebuild the rtl devirtualised for a particular 
      program; and these options can obviously also be used         
      together with regular optimisation switches)
  o warning:
    - there are no checks yet to ensure that you do not use 
      units optimised for a particular program with another
      program (or with a changed version of the same program)

........
r11881 | jonas | 2008-10-11 19:35:52 +0200 (Sat, 11 Oct 2008) | 13 lines

  * extracted code to detect constructed class/object types from
    tcallnode.gen_vmt_tree into its own method to avoid clutter
  * detect x.classtype.create constructs (with classtype = the
    system.tobject.classtype method), and treat them as if a
    "class of x" has been instantiated rather than a
    "class of tobject". this required storing the instantiated
    classrefs in their own array though, because at such a
    point we don't have a "class of x" tdef available (so
    now "x", and all other defs instantiated via a classref,
    are now stored as tobjectdefs in a separate array)
  + support for devirtualising class methods (including
    constructors)

........
r11882 | jonas | 2008-10-11 20:44:02 +0200 (Sat, 11 Oct 2008) | 7 lines

  + -Owoptvmts whole program optimisation which replaces vmt entries
    with method names of child classes in case the current class'
    method can never be called (e.g., because this class is never
    instantiated). As a result, such methods can then be removed
    by dead code removal/smart linking (not much effect for either
    the compiler, lazarus or a trivial lazarus app though).

........
r11889 | jonas | 2008-10-12 14:29:54 +0200 (Sun, 12 Oct 2008) | 2 lines

  * some comment fixes

........
r11891 | jonas | 2008-10-12 18:49:13 +0200 (Sun, 12 Oct 2008) | 4 lines

  * fixed twpofilereader.getnextnoncommentline() when reusing a previously
    read line
  * fixed skipping of unnecessary wpo feedback file sections

........
r11892 | jonas | 2008-10-12 23:42:43 +0200 (Sun, 12 Oct 2008) | 31 lines

  + symbol liveness wpo information extracted from smartlinked programs
    (-OW/-Owsymbolliveness)
  + use symbol liveness information to improve devirtualisation (don't
    consider classes created in code that has been dead code stripped).
    This requires at least two passes of using wpo (first uses dead code
    info to locate classes that are constructed only in dead code,
    second pass uses this info to potentially further devirtualise).
    I.e.:
     1) generate initial liveness and devirtualisation feedback
       fpc -FWtt.wpo -OWall tt.pp -Xs- -CX -XX
     2) use previously generated feedback, and regenerate new feedback
        based on this (i.e., disregard classes created in dead code)
       fpc -FWtt-1.wpo -OWall -Fwtt.wo -Owall tt.pp -Xs- -CX -XX
     3) use the newly generated feedback (in theory, it is possible
        that even more opportunities pop up afterwards; you can
        continue until the program does not get smaller anymore)
       fpc -Fwtt-1.wpo -Owall tt.pp -CX -XX
  * changed all message() to cgmessage() calls so the set codegenerror
  * changed static fsectionhandlers field to a regular field called
    fwpocomponents
  * changed registration of wpocomponents: no longer happens in the
    initialization section of their unit, but in the InitWpo routine
    (which has been moved from the woinfo to the wpo unit). This way
    you can register different classes based on the target/parameters.
  + added static method to twpocomponentbase for checking whether
    the command line parameters don't conflict with the requested
    optimisations (e.g. generating liveness info requires that
    smartlinking is turned on)
  + added static method to twpocomponentbase to request the
    section name

........
r11893 | jonas | 2008-10-12 23:53:57 +0200 (Sun, 12 Oct 2008) | 3 lines

  * fixed comment error (twpodeadcodeinfo keeps a list of live,
    not dead symbols)

........
r11895 | jonas | 2008-10-13 00:13:59 +0200 (Mon, 13 Oct 2008) | 2 lines

  + documented -OW<x>, -Ow<x>, -FW<x> and -Fw<x> wpo parameters

........
r11899 | jonas | 2008-10-14 22:14:56 +0200 (Tue, 14 Oct 2008) | 2 lines

  * replaced hardcoded string with objdumpsearchstr constant

........
r11900 | jonas | 2008-10-14 22:15:25 +0200 (Tue, 14 Oct 2008) | 2 lines

  * reset wpofeedbackinput and wpofeedbackoutput in wpodone

........
r11901 | jonas | 2008-10-14 22:16:07 +0200 (Tue, 14 Oct 2008) | 2 lines

  * various additional comments and comment fixes

........
r11902 | jonas | 2008-10-15 18:09:42 +0200 (Wed, 15 Oct 2008) | 5 lines

  * store vmt procdefs in the ppu files so we don't have to use a hack to
    regenerate them for whole-program optimisation
  * fixed crash when performing devirtualisation optimisation on programs
    that do not construct any classes/objects with optimisable vmts

........
r11935 | jonas | 2008-10-19 12:24:26 +0200 (Sun, 19 Oct 2008) | 4 lines

  * set the vmt entries of non-class virtual methods of not instantiated
    objects/classes to FPC_ABSTRACTERROR so the code they refer to can
    be thrown away if it is not referred to in any other way either

........
r11938 | jonas | 2008-10-19 20:55:02 +0200 (Sun, 19 Oct 2008) | 7 lines

  * record all classrefdefs/objdefs for which a loadvmtaddrnode is generated,
    and instead of marking all classes that derive from instantiated
    classrefdefs as instantiated, only mark those classes from the above
    collection that derive from instantiated classrefdefs as
    instantiated (since to instantiate a class, you have to load its vmt
    somehow -- this may be broken by using assembler code though)

........
r12212 | jonas | 2008-11-23 12:26:34 +0100 (Sun, 23 Nov 2008) | 3 lines

  * fixed to work with the new vmtentries that are always available and
    removed previously added code to save/load vmtentries to ppu files

........
r12304 | jonas | 2008-12-05 22:23:30 +0100 (Fri, 05 Dec 2008) | 4 lines

  * check whether the correct wpo feedback file is used in the current
    compilation when using units that were compiled using wpo information
    during a previous compilation run

........
r12308 | jonas | 2008-12-06 18:03:39 +0100 (Sat, 06 Dec 2008) | 2 lines

  * abort compilation if an error occurred during wpo initialisation

........
r12309 | jonas | 2008-12-06 18:04:28 +0100 (Sat, 06 Dec 2008) | 3 lines

  * give an error message instead of crashing with an io exception if the
    compiler is unable to create the wpo feedback file specified using -FW

........
r12310 | jonas | 2008-12-06 18:12:43 +0100 (Sat, 06 Dec 2008) | 3 lines

  * don't let the used wpo feedback file influence the interface crc (there's
    a separate check for such changes)

........
r12316 | jonas | 2008-12-08 19:08:25 +0100 (Mon, 08 Dec 2008) | 3 lines

  * document the format of the sections of the wpo feedback file inside the
    feedback file itself

........
r12330 | jonas | 2008-12-10 22:26:47 +0100 (Wed, 10 Dec 2008) | 2 lines

  * use sysutils instead of dos to avoid command line length limits

........
r12331 | jonas | 2008-12-10 22:31:11 +0100 (Wed, 10 Dec 2008) | 3 lines

  + support for testing whole program optimisation tests (multiple
    compilations using successively generated feedback files)

........
r12332 | jonas | 2008-12-10 22:31:40 +0100 (Wed, 10 Dec 2008) | 2 lines

  + whole program optimisation tests

........
r12334 | jonas | 2008-12-10 22:38:07 +0100 (Wed, 10 Dec 2008) | 2 lines

  - removed unused local variable

........
r12339 | jonas | 2008-12-11 18:06:36 +0100 (Thu, 11 Dec 2008) | 2 lines

  + comments for newly added fields to tobjectdef for devirtualisation

........
r12340 | jonas | 2008-12-11 18:10:01 +0100 (Thu, 11 Dec 2008) | 2 lines

  * increase ppu version (was no longer different from trunk due to merging)

........

git-svn-id: trunk@12341 -
2008-12-11 17:40:18 +00:00

1084 lines
25 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
{$H+}
{$R-}
{$ifndef Linux}
{$ifndef Unix}
{$S-}
{$endif}
{$endif}
{$ifdef TP}
{$define implemented}
{$endif TP}
{$ifdef Go32v2}
{$define implemented}
{$endif}
{$ifdef OS2}
{$define shell_implemented}
{$endif}
{$ifdef windows}
{$define implemented}
{$endif}
{$ifdef linux}
{$define implemented}
{$endif}
{$ifdef BSD}
{$define implemented}
{$endif}
{$ifdef BEOS}
{$define implemented}
{$endif}
{$ifdef macos}
{$define shell_implemented}
{$endif}
{$ifdef sunos}
{$define implemented}
{$endif}
{ be sure msdos is not set for FPC compiler }
{$ifdef FPC}
{$UnDef MsDos}
{$endif FPC}
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
{$ifdef macos}
{$define usedos}
{$endif}
Uses
{$ifdef go32v2}
go32,
{$endif go32v2}
{$ifdef windows}
windows,
{$endif windows}
{$ifdef unix}
{$ifdef ver1_0}
linux,
{$else}
baseunix,
unix,
{$endif}
{$endif unix}
{$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}
{$ifdef TP}
{$ifndef windows}
const
UnusedHandle = -1;
StdInputHandle = 0;
StdOutputHandle = 1;
StdErrorHandle = 2;
{$endif windows}
Type
PtrRec = packed record
Ofs, Seg : Word;
end;
PHandles = ^THandles;
THandles = Array [Byte] of Byte;
PWord = ^Word;
Var
MinBlockSize : Word;
MyBlockSize : Word;
Handles : PHandles;
PrefSeg : Word;
OldHandleOut,OldHandleIn,OldHandleError : Byte;
{$endif TP}
var
TempHOut, TempHIn,TempHError : longint;
{
For linux 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 dup(fh : longint;var nh : longint) : boolean;
var
Regs : Registers;
begin
Regs.ah:=$45;
Regs.bx:=fh;
MsDos (Regs);
dup:=true;
If (Regs.Flags and fCarry)=0 then
nh:=Regs.Ax
else
dup:=false;
end;
function dup2(fh,nh : longint) : boolean;
var
Regs : Registers;
begin
dup2:=true;
If fh=nh then
exit;
Regs.ah:=$46;
Regs.bx:=fh;
Regs.cx:=nh;
MsDos (Regs);
If (Regs.Flags and fCarry)<>0 then
dup2:=false;
end;
{$ifndef ver1_0}
function fpdup(fh:longint):longint;
begin
if not dup(fh,fpdup) then
fpdup:=-1;
end;
function fpdup2(fh,nh:longint):longint;
begin
if dup2(fh,nh) then
fpdup2:=0
else
fpdup2:=-1;
end;
{$endif ver1_0}
Function {$ifdef ver1_0}fdclose{$else}fpclose{$endif} (Handle : Longint) : boolean;
var Regs: registers;
begin
Regs.Eax := $3e00;
Regs.Ebx := Handle;
MsDos(Regs);
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}:=(Regs.Flags and fCarry)=0;
end;
{$endif def go32v2}
{$ifdef windows}
Function {$ifdef ver1_0}fdclose{$else}fpclose{$endif} (Handle : Longint) : boolean;
begin
{ Do we need this ?? }
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}:=true;
end;
{$endif}
{$ifdef os2}
Function {$ifdef ver1_0}fdclose{$else}fpclose{$endif} (Handle : Longint) : boolean;
begin
{ Do we need this ?? }
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}:=true;
end;
{$endif}
{$ifdef TP}
Function {$ifdef ver1_0}fdclose{$else}fpclose{$endif} (Handle : Longint) : boolean;
begin
{ if executed as under GO32 this hangs the DOS-prompt }
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}:=true;
end;
{$endif}
{$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,d,n,e : string;
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}
{$ifdef ver1_0}
dup(StdOutputHandle,TempHOut);
dup2(FileRec(FOUT^).Handle,StdOutputHandle);
{$else}
TempHOut:=fpdup(StdOutputHandle);
fpdup2(FileRec(FOUT^).Handle,StdOutputHandle);
{$endif}
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}
{$ifdef ver1_0}
dup(StdInputHandle,TempHIn);
dup2(FileRec(FIn^).Handle,StdInputHandle);
{$else}
TempHIn:=fpdup(StdInputHandle);
fpdup2(FileRec(FIn^).Handle,StdInputHandle);
{$endif}
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}
{$ifdef ver1_0}
dup(StdErrorHandle,TempHError);
dup2(FileRec(PF^).Handle,StdErrorHandle);
{$else}
TempHError:=fpdup(StdErrorHandle);
fpdup2(FileRec(PF^).Handle,StdErrorHandle);
{$endif}
if (TempHError<>UnusedHandle) and
(StdErrorHandle<>UnusedHandle) then
{$endif not windows}
begin
ChangeRedirError:=True;
ErrorRedirDisabled:=False;
end;
{$endif}
RedirChangedError:=True;
end;
{$IfDef MsDos}
{Set HeapEnd Pointer to Current Used Heapsize}
Procedure SmallHeap;assembler;
asm
mov bx,word ptr HeapPtr
shr bx,4
inc bx
add bx,word ptr HeapPtr+2
mov ax,PrefixSeg
sub bx,ax
mov es,ax
mov ah,4ah
int 21h
end;
{Set HeapEnd Pointer to Full Heapsize}
Procedure FullHeap;assembler;
asm
mov bx,word ptr HeapEnd
shr bx,4
inc bx
add bx,word ptr HeapEnd+2
mov ax,PrefixSeg
sub bx,ax
mov es,ax
mov ah,4ah
int 21h
end;
{$EndIf MsDos}
procedure RestoreRedirOut;
begin
If not RedirChangedOut then Exit;
{$ifndef FPC}
Handles^[StdOutputHandle]:=OldHandleOut;
OldHandleOut:=StdOutputHandle;
{$else}
{$ifdef windows}
SetStdHandle(Std_Output_Handle,StdOutputHandle);
{$else not windows}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(TempHOut,StdOutputHandle);
{$endif not windows}
{$endif FPC}
Close (FOUT^);
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}(TempHOut);
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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(TempHIn,StdInputHandle);
{$endif not windows}
{$endif}
Close (FIn^);
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}(TempHIn);
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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(TempHError,StdErrorHandle);
{$endif not windows}
{$endif}
{ don't close when redirected to STDOUT }
if not RedirStdErrToStdOut then
Close (FERR^);
{$ifdef ver1_0}fdclose{$else}fpclose{$endif}(TempHError);
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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(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}
{$ifdef ver1_0}dup2{$else}fpdup2{$endif}(FileRec(FERR^).Handle,StdErrorHandle);
{$endif not windows}
{$endif}
ErrorRedirDisabled:=False;
end;
{............................................................................}
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;
{............................................................................}
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
{$ifndef FPC}
PrefSeg:=PrefixSeg;
{$endif FPC}
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
dir,s,d,n,e : string;
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}
{............................................................................}
procedure DosExecute(ProgName, ComLine : String);
{$ifdef windows}
var
StoreInherit : BOOL;
{$endif windows}
Begin
{$IfDef MsDos}
SmallHeap;
{$EndIf MsDos}
{$ifdef usedos}
SwapVectors;
{$endif usedos}
{ Must use shell() for linux for the wildcard expansion (PFV) }
{$ifdef UNIX}
IOStatus:=0;
ExecuteResult:=Shell(FixPath(Progname)+' '+Comline);
{$ifdef ver1_0}
{ Signal that causes the stop of the shell }
IOStatus:=ExecuteResult and $7F;
{ Exit Code seems to be in the second byte,
is this also true for BSD ??
$80 bit is a CoreFlag apparently }
ExecuteResult:=(ExecuteResult and $ff00) shr 8;
{$else}
if ExecuteResult<0 then
begin
IOStatus:=(-ExecuteResult) and $7f;
ExecuteResult:=((-ExecuteResult) and $ff00) shr 8;
end;
{$endif}
{$else}
{$ifdef windows}
StoreInherit:=ExecInheritsHandles;
ExecInheritsHandles:=true;
{ Avoid dialog boxes if dll loading fails }
SetErrorMode(SEM_FAILCRITICALERRORS);
{$endif windows}
DosError:=0;
If UseComSpec then
Sysutils.ExecuteProcess (Getenv('COMSPEC'),'/C '+FixPath(progname)+' '+Comline)
else
begin
if LocateExeFile(progname) then
{$ifndef macos}
Sysutils.ExecuteProcess(ProgName,Comline)
{$else}
Dos.Exec(''''+ProgName+'''',Comline) {Quotes needed !}
{$endif}
else
DosError:=2;
end;
{$ifdef windows}
ExecInheritsHandles:=StoreInherit;
SetErrorMode(0);
{$endif windows}
IOStatus:=DosError;
ExecuteResult:=DosExitCode;
{$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.