home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / lib / gcc-lib / djgpp / 2.952 / units / pipe.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  20.8 KB  |  580 lines

  1. {
  2. Piping data from and to processes and process signaling
  3.  
  4. Copyright (C) 1998-2001 Free Software Foundation, Inc.
  5.  
  6. Author: Frank Heckenbach <frank@pascal.gnu.de>
  7.  
  8. This file is part of GNU Pascal.
  9.  
  10. GNU Pascal is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2, or (at your option)
  13. any later version.
  14.  
  15. GNU Pascal is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19.  
  20. You should have received a copy of the GNU General Public License
  21. along with GNU Pascal; see the file COPYING. If not, write to the
  22. Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  23. 02111-1307, USA.
  24.  
  25. As a special exception, if you link this file with files compiled
  26. with a GNU compiler to produce an executable, this does not cause
  27. the resulting executable to be covered by the GNU General Public
  28. License. This exception does not however invalidate any other
  29. reasons why the executable file might be covered by the GNU General
  30. Public License.
  31. }
  32.  
  33. {$gnu-pascal,B-,I-}
  34. {$if __GPC_RELEASE__ < 20000412}
  35. {$error This unit requires GPC release 20000412 or newer.}
  36. {$endif}
  37.  
  38. { Keep this consistent with the one in pipec.c }
  39. {$if defined (MSDOS) or defined (__MINGW32__)}
  40. {$define NOFORK}
  41. {$endif}
  42.  
  43. unit Pipe;
  44.  
  45. interface
  46.  
  47. uses GPC;
  48.  
  49. (*$local W-*)type PPStrings = ^TPStrings;TPStrings (Count: Cardinal) = array [1 .. Count] of ^String; (*@@two unit bug with definition in gpc.pas in programs using these two units*) (*$endlocal*)
  50.  
  51. const
  52.   PipeForking = {$ifdef NOFORK} False {$else} True {$endif};
  53.  
  54. type
  55.   TProcedure = procedure;
  56.  
  57.   PWaitPIDResult = ^TWaitPIDResult;
  58.   TWaitPIDResult = (PIDNothing, PIDExited, PIDSignaled, PIDStopped, PIDUnknown);
  59.  
  60.   PPipeProcess = ^TPipeProcess;
  61.   TPipeProcess = record
  62.     PID       : Integer;        { Process ID of process forked }
  63.     SignalPID : Integer;        { Process ID to send the signal to.
  64.                                   Equals PID by default }
  65.     OpenPipes : Integer;        { Number of pipes to/from the
  66.                                   process, for internal use }
  67.     Signal    : Integer;        { Send this signal (if not 0) to the
  68.                                   process after all pipes have been
  69.                                   closed after some time }
  70.     Seconds   : Integer;        { Wait so many seconds before
  71.                                   sending the signal if the process
  72.                                   has not terminated by itself }
  73.     Wait      : Boolean;        { Wait for the process, even longer
  74.                                   than Seconds seconds, after
  75.                                   sending the signal (if any) }
  76.     Result    : PWaitPIDResult; { Default nil. If a pointer to a
  77.                                   variable is stored here, its
  78.                                   destination will contain the
  79.                                   information whether the process
  80.                                   terminated by itself, or was
  81.                                   terminated or stopped by a signal,
  82.                                   when waiting after closing the
  83.                                   pipes }
  84.     Status    : ^Integer;       { Default nil. If a pointer to a
  85.                                   variable is stored here, its
  86.                                   destination will contain the exit
  87.                                   status if the process terminated
  88.                                   by itself, or the number of the
  89.                                   signal otherwise, when waiting
  90.                                   after closing the pipes }
  91.   end;
  92.  
  93. const
  94.   EFork  = 600; { cannot fork `%s'' }
  95.   ESpawn = 601; { cannot spawn `%s'' }
  96.  
  97. var
  98.   { Default values for TPipeProcess records created by Pipe }
  99.   DefaultPipeSignal  : Integer = 0;
  100.   DefaultPipeSeconds : Integer = 0;
  101.   DefaultPipeWait    : Boolean = True;
  102.  
  103. {
  104.   The procedure Pipe starts a process whose name is given by
  105.   ProcessName, with the given parameters (can be null if no
  106.   parameters) and environment, and create pipes from and/or to the
  107.   process' standard input/output/error. ProcessName is searched for
  108.   in the PATH with FSearchExecutable. Any of ToInputFile,
  109.   FromOutputFile and FromStdErrFile can be null if the corresponding
  110.   pipe is not wanted. FromOutputFile and FromStdErrFile may be
  111.   identical, in which case standard output and standard error are
  112.   redirected to the same pipe. The behaviour of other pairs of files
  113.   being identical is undefined, and useless, anyway. The files are
  114.   Assigned and Reset or Rewritten as appropriate. Errors are
  115.   returned in IOResult. If Process is not null, a pointer to a
  116.   record is stored there, from which the PID of the process created
  117.   can be read, and by writing to which the action after all pipes
  118.   have been closed can be changed. (The record is automatically
  119.   Dispose'd of after all pipes have been closed.) If automatic
  120.   waiting is turned off, the caller should get the PID from the
  121.   record before it's Dispose'd of, and wait for the process sometime
  122.   in order to avoid zombies. If no redirections are performed (i.e.,
  123.   all 3 files are null), the caller should wait for the process with
  124.   WaitPipeProcess. When an error occurs, Process is not assigned to,
  125.   and the state of the files is undefined, so be sure to check
  126.   IOResult before going on.
  127.  
  128.   ChildProc, if not nil, is called in the child process after
  129.   forking and redirecting I/O, but before executing the new process.
  130.   It can even be called instead of executing a new process
  131.   (ProcessName can be empty then).
  132.  
  133.   The procedure even works under Dos, but, of course, in a limited
  134.   sense: if ToInputFile is used, the process will not actually be
  135.   started until ToInputFile is closed. Signal, Seconds and Wait of
  136.   TPipeProcess are ignored, and PID and SignalPID do not contain a
  137.   Process ID, but an internal value without any meaning to the
  138.   caller. Result will always be PIDExited. So, Status is the only
  139.   interesting field (but Result should also be checked). Since there
  140.   is no forking under Dos, ChildProc, if not nil, is called in the
  141.   main process before spawning the program. So, to be portable, it
  142.   should not do any things that would influence the process after
  143.   the return of the Pipe function.
  144.  
  145.   The only portable way to use "pipes" in both directions is to call
  146.   `Pipe', write all the Input data to ToInputFile, close
  147.   ToInputFile, and then read the Output and StdErr data from
  148.   FromOutputFile and FromStdErrFile. However, since the capacity of
  149.   pipes is limited, one should also check for Data from
  150.   FromOutputFile and FromStdErrFile (using CanRead, IOSelect or
  151.   IOSelectRead) while writing the Input data (under Dos, there
  152.   simply won't be any data then, but checking for data doesn't do
  153.   any harm). Please see pipedemo.pas for an example.
  154. }
  155. (*@@IO critical*) procedure Pipe (var ToInputFile, FromOutputFile, FromStdErrFile : AnyFile; (*@@fjf265 const*) ProcessName : String; protected var Parameters : TPStrings; ProcessEnvironment : PCStrings; var Process : PPipeProcess; ChildProc : TProcedure);
  156.  
  157. {
  158.   Waits for a process created by Pipe as determined in the Process
  159.   record. (Process is Dispose'd of afterwards.) Returns True if
  160.   successful.
  161. }
  162. function WaitPipeProcess (Process : PPipeProcess) : Boolean;
  163.  
  164. implementation
  165.  
  166. {$L pipec.c}
  167.  
  168. {$ifndef NOFORK}
  169.  
  170. type
  171.   PInteger = ^Integer;
  172.  
  173.   PFileProcess = ^TFileProcess;
  174.   TFileProcess = record
  175.     FilePtr : PAnyFile;
  176.     OldCloseProc : TCloseProc;
  177.     ProcessPtr : PPipeProcess
  178.   end;
  179.  
  180. function CPipe (Path : CString; CProcessParameters, ProcessEnvironment : PCStrings; PPipeStdIn, PPipeStdOut, PPipeStdErr : PInteger; ChildProc : TProcedure) : Integer; asmname '_p_pipe';
  181.  
  182. function WaitPipeProcess (Process : PPipeProcess) : Boolean;
  183. var Dummy : Boolean;
  184.  
  185.   function DoWaitPID (Block : Boolean) = WPID : Integer;
  186.   var
  187.     Result : TWaitPIDResult;
  188.     WStatus, Status : Integer;
  189.   begin
  190.     WPID := WaitPID (Process^.PID, WStatus, Block);
  191.     if WPID <= 0 then
  192.       begin
  193.         Result := PIDNothing;
  194.         Status := 0
  195.       end
  196.     else if StatusExited (WStatus) then
  197.       begin
  198.         Result := PIDExited;
  199.         Status := StatusExitCode (WStatus)
  200.       end
  201.     else if StatusSignaled (WStatus) then
  202.       begin
  203.         Result := PIDSignaled;
  204.         Status := StatusTermSignal (WStatus)
  205.       end
  206.     else if StatusStopped (WStatus) then
  207.       begin
  208.         Result := PIDStopped;
  209.         Status := StatusStopSignal (WStatus)
  210.       end
  211.     else
  212.       begin
  213.         Result := PIDUnknown;
  214.         Status := 0
  215.       end;
  216.     if Process^.Result <> nil then Process^.Result^ := Result;
  217.     if Process^.Status <> nil then Process^.Status^ := Status
  218.   end;
  219.  
  220. begin
  221.   WaitPipeProcess := True;
  222.   with Process^ do
  223.     begin
  224.       while Seconds <> 0 do
  225.         begin
  226.           if DoWaitPID (False) = PID then
  227.             begin
  228.               Dispose (Process);
  229.               Exit
  230.             end;
  231.           Sleep (1);
  232.           Dec (Seconds)
  233.         end;
  234.       if Signal <> 0 then Dummy := Kill (SignalPID, Signal);
  235.       if not Wait or (DoWaitPID (True) <= 0) then
  236.         WaitPipeProcess := False
  237.       else
  238.         Dispose (Process)
  239.     end
  240. end;
  241.  
  242. procedure PipeTFDDClose (var PrivateData);
  243. var
  244.   FileProcess : TFileProcess absolute PrivateData;
  245.   OpenProc   : TOpenProc;
  246.   SelectFunc : TSelectFunc;
  247.   SelectProc : TSelectProc;
  248.   ReadFunc   : TReadFunc;
  249.   WriteFunc  : TWriteFunc;
  250.   FlushProc  : TFlushProc;
  251.   DoneProc   : TDoneProc;
  252.   FPrivateData : Pointer;
  253.   Dummy : Boolean;
  254. begin
  255.   with FileProcess do
  256.     begin
  257.       GetTFDD (FilePtr^, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, null, DoneProc, FPrivateData);
  258.       SetTFDD (FilePtr^, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, OldCloseProc, DoneProc, FPrivateData);
  259.       Close (FilePtr^);
  260.       Dec (ProcessPtr^.OpenPipes);
  261.       if ProcessPtr^.OpenPipes = 0 then Dummy := WaitPipeProcess (ProcessPtr)
  262.     end;
  263.   Dispose (@FileProcess)
  264. end;
  265.  
  266. procedure SetCloseAction (var f : AnyFile; PProcess : PPipeProcess);
  267. var
  268.   p : PFileProcess;
  269.   OpenProc   : TOpenProc;
  270.   SelectFunc : TSelectFunc;
  271.   SelectProc : TSelectProc;
  272.   ReadFunc   : TReadFunc;
  273.   WriteFunc  : TWriteFunc;
  274.   FlushProc  : TFlushProc;
  275.   DoneProc   : TDoneProc;
  276.   PrivateData : Pointer;
  277. begin
  278.   if InOutRes <> 0 then Exit;
  279.   New (p);
  280.   p^.FilePtr := @f;
  281.   p^.ProcessPtr := PProcess;
  282.   Inc (PProcess^.OpenPipes);
  283.   GetTFDD (f, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, p^.OldCloseProc, DoneProc, PrivateData);
  284.   SetTFDD (f, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, PipeTFDDClose, DoneProc, p)
  285. end;
  286.  
  287. procedure Pipe (var ToInputFile, FromOutputFile, FromStdErrFile : AnyFile; (*@@fjf265 const*) ProcessName : String; protected var Parameters : TPStrings; ProcessEnvironment : PCStrings; var Process : PPipeProcess; ChildProc : TProcedure);
  288. var
  289.   ParameterCount, i : Cardinal;
  290.   PipeStdIn, PipeStdOut, PipeStdErr : Integer;
  291.   PPipeStdIn, PPipeStdOut, PPipeStdErr : PInteger;
  292.   PID : Integer;
  293.   PProcess : PPipeProcess;
  294.   ProcessPath : TString;
  295. begin
  296.   if @Process <> nil then Process := nil;
  297.   if InOutRes <> 0 then Exit;
  298.   if @Parameters = nil then ParameterCount := 0 else ParameterCount := Parameters.Count;
  299.   var CProcessParameters : array [0 .. ParameterCount + 1] of CString;
  300.   CProcessParameters [0] := ProcessName;
  301.   for i := 1 to ParameterCount do CProcessParameters [i] := Parameters [i]^;
  302.   CProcessParameters [ParameterCount + 1] := nil;
  303.   if @ToInputFile = nil then PPipeStdIn := nil else PPipeStdIn := @PipeStdIn;
  304.   if @FromOutputFile = nil then PPipeStdOut := nil else PPipeStdOut := @PipeStdOut;
  305.   if @FromStdErrFile = nil then PPipeStdErr := nil else
  306.     if @FromStdErrFile = @FromOutputFile then PPipeStdErr := @PipeStdOut else PPipeStdErr := @PipeStdErr;
  307.   if ProcessName = ''
  308.     then ProcessPath := ''
  309.     else ProcessPath := FSearchExecutable (ProcessName, GetEnv (PathEnvVar));
  310.   if (ProcessName <> '') and (ProcessPath = '')
  311.     then PID := - 1
  312.     else PID := CPipe (ProcessPath, PCStrings (@CProcessParameters), ProcessEnvironment, PPipeStdIn, PPipeStdOut, PPipeStdErr, ChildProc);
  313.   if PID <= 0 then
  314.     begin
  315.       IOErrorCString (EFork, ProcessName);
  316.       Exit
  317.     end;
  318.   New (PProcess);
  319.   PProcess^.PID := PID;
  320.   PProcess^.SignalPID := PID;
  321.   PProcess^.Signal := DefaultPipeSignal;
  322.   PProcess^.Seconds := DefaultPipeSeconds;
  323.   PProcess^.Wait := DefaultPipeWait;
  324.   PProcess^.OpenPipes := 0;
  325.   PProcess^.Result := nil;
  326.   PProcess^.Status := nil;
  327.   if @Process <> nil then Process := PProcess;
  328.   if @ToInputFile <> nil then
  329.     begin
  330.       AssignHandle (ToInputFile, PipeStdIn);
  331.       Rewrite (ToInputFile);
  332.       SetCloseAction (ToInputFile, PProcess)
  333.     end;
  334.   if @FromOutputFile <> nil then
  335.     begin
  336.       AssignHandle (FromOutputFile, PipeStdOut);
  337.       Reset (FromOutputFile);
  338.       SetCloseAction (FromOutputFile, PProcess)
  339.     end;
  340.   if (@FromStdErrFile <> nil) and (@FromStdErrFile <> @FromOutputFile) then
  341.     begin
  342.       AssignHandle (FromStdErrFile, PipeStdErr);
  343.       Reset (FromStdErrFile);
  344.       SetCloseAction (FromStdErrFile, PProcess)
  345.     end
  346. end;
  347.  
  348. {$else}
  349.  
  350. { NOTE: This emulation code is quite a mess! Be warned if you want
  351.   to understand it, and don't make any quick changes here unless you
  352.   fully understand it. }
  353.  
  354. function CPipe (Path : CString; CProcessParameters, ProcessEnvironment : PCStrings; NameStdIn, NameStdOut, NameStdErr : CString; ChildProc : TProcedure) : Integer; asmname '_p_pipe';
  355.  
  356. type
  357.   PPipeData = ^TPipeData;
  358.   TPipeData = record
  359.     ProcName, Path : CString;
  360.     ParameterCount : Cardinal;
  361.     CProcessParameters, CProcessEnvironment : PCStrings;
  362.     NameStdOut, NameStdErr, NameStdIn : TString;
  363.     CNameStdOut, CNameStdErr, CNameStdIn : CString;
  364.     PToInputFile, PFromOutputFile, PFromStdErrFile : ^AnyFile;
  365.     InternalToInputFile : Text;
  366.     aChildProc : TProcedure;
  367.     PipeProcess : TPipeProcess
  368.   end;
  369.  
  370.   PFileProcess = ^TFileProcess;
  371.   TFileProcess = record
  372.     FilePtr : PAnyFile;
  373.     OldCloseProc : TCloseProc;
  374.     PipeDataPtr : PPipeData
  375.   end;
  376.  
  377. { TPipeProcess.PID actually holds the exit status here }
  378.  
  379. function WaitPipeProcess (Process : PPipeProcess) : Boolean;
  380. begin
  381.   if Process^.Result <> nil then Process^.Result^ := PIDExited;
  382.   if Process^.Status <> nil then Process^.Status^ := Process^.PID;
  383.   WaitPipeProcess := Process^.PID >= 0
  384. end;
  385.  
  386. procedure DoPipe (var PipeData : TPipeData);
  387. var
  388.   i : Cardinal;
  389.   Dummy : Boolean;
  390. begin
  391.   with PipeData do
  392.     begin
  393.       PipeProcess.PID := CPipe (Path, CProcessParameters, CProcessEnvironment, CNameStdIn, CNameStdOut, CNameStdErr, aChildProc);
  394.       PipeProcess.SignalPID := PipeProcess.PID;
  395.       if PToInputFile <> nil then Erase (InternalToInputFile);
  396.       if PipeProcess.PID < 0 then IOErrorCString (ESpawn, ProcName);
  397.       Dispose (ProcName);
  398.       Dispose (Path);
  399.       for i := 0 to ParameterCount do Dispose (CProcessParameters^[i]);
  400.       Dispose (CProcessParameters);
  401.       Dummy := WaitPipeProcess (@PipeProcess);
  402.       if PipeProcess.PID < 0 then Exit;
  403.       if PFromOutputFile <> nil then
  404.         begin
  405.           Reset (PFromOutputFile^, NameStdOut);
  406.           Erase (PFromOutputFile^)
  407.         end;
  408.       if (PFromStdErrFile <> nil) and (PFromStdErrFile <> PFromOutputFile) then
  409.         begin
  410.           Reset (PFromStdErrFile^, NameStdErr);
  411.           Erase (PFromStdErrFile^)
  412.         end
  413.     end
  414. end;
  415.  
  416. function PipeInTFDDWrite (var PrivateData; const Buffer; Size : SizeType) : SizeType;
  417. var
  418.   Data : TPipeData absolute PrivateData;
  419.   CharBuffer : array [1 .. Size] of Char absolute Buffer;
  420. begin
  421.   with Data do
  422.     Write (InternalToInputFile, CharBuffer);
  423.   PipeInTFDDWrite := Size
  424. end;
  425.  
  426. procedure PipeInTFDDClose (var PrivateData);
  427. var Data : TPipeData absolute PrivateData;
  428. begin
  429.   with Data do
  430.     begin
  431.       Close (InternalToInputFile);
  432.       if PFromOutputFile <> nil then Close (PFromOutputFile^);
  433.       if (PFromStdErrFile <> nil) and (PFromStdErrFile <> PFromOutputFile) then Close (PFromStdErrFile^);
  434.       Dec (Data.PipeProcess.OpenPipes);
  435.       DoPipe (Data);
  436.       Dispose (@Data)
  437.     end
  438. end;
  439.  
  440. procedure PipeOutTFDDClose (var PrivateData);
  441. var
  442.   FileProcess : TFileProcess absolute PrivateData;
  443.   OpenProc   : TOpenProc;
  444.   SelectFunc : TSelectFunc;
  445.   SelectProc : TSelectProc;
  446.   ReadFunc   : TReadFunc;
  447.   WriteFunc  : TWriteFunc;
  448.   FlushProc  : TFlushProc;
  449.   DoneProc   : TDoneProc;
  450.   FPrivateData : Pointer;
  451.   Dummy : Boolean;
  452. begin
  453.   with FileProcess do
  454.     begin
  455.       GetTFDD (FilePtr^, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, null, DoneProc, FPrivateData);
  456.       SetTFDD (FilePtr^, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, OldCloseProc, DoneProc, FPrivateData);
  457.       Close (FilePtr^);
  458.       Dec (PipeDataPtr^.PipeProcess.OpenPipes);
  459.       if PipeDataPtr^.PipeProcess.OpenPipes = 0 then
  460.         begin
  461.           Dummy := WaitPipeProcess (@PipeDataPtr^.PipeProcess);
  462.           Dispose (PipeDataPtr)
  463.         end
  464.     end;
  465.   Dispose (@FileProcess)
  466. end;
  467.  
  468. procedure SetCloseAction (var f : AnyFile; PipeData : PPipeData);
  469. var
  470.   p : PFileProcess;
  471.   OpenProc   : TOpenProc;
  472.   SelectFunc : TSelectFunc;
  473.   SelectProc : TSelectProc;
  474.   ReadFunc   : TReadFunc;
  475.   WriteFunc  : TWriteFunc;
  476.   FlushProc  : TFlushProc;
  477.   DoneProc   : TDoneProc;
  478.   PrivateData : Pointer;
  479. begin
  480.   if InOutRes <> 0 then Exit;
  481.   New (p);
  482.   p^.FilePtr := @f;
  483.   p^.PipeDataPtr := PipeData;
  484.   GetTFDD (f, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, p^.OldCloseProc, DoneProc, PrivateData);
  485.   SetTFDD (f, OpenProc, SelectFunc, SelectProc, ReadFunc, WriteFunc, FlushProc, PipeOutTFDDClose, DoneProc, p)
  486. end;
  487.  
  488. { The "pipes" that come from the process are reset to nothing until the
  489.   process is started. Use a TFDD, not an empty file or the null device,
  490.   so that IOSelect will not select these files. }
  491. procedure ResetNothing (var f : AnyFile);
  492. begin
  493.   AssignTFDD (f, nil, nil, nil, nil, nil, nil, nil, nil, nil);
  494.   Reset (f)
  495. end;
  496.  
  497. procedure Pipe (var ToInputFile, FromOutputFile, FromStdErrFile : AnyFile; (*@@fjf265 const*) ProcessName : String; protected var Parameters : TPStrings; ProcessEnvironment : PCStrings; var Process : PPipeProcess; ChildProc : TProcedure);
  498. var
  499.   i : Cardinal;
  500.   PipeData : PPipeData;
  501.   ProcessPath : TString;
  502. begin
  503.   if @Process <> nil then Process := nil;
  504.   if ProcessName = ''
  505.     then ProcessPath := ''
  506.     else ProcessPath := FSearchExecutable (ProcessName, GetEnv (PathEnvVar));
  507.   if (ProcessName <> '') and (ProcessPath = '') then
  508.     begin
  509.       IOErrorCString (ESpawn, ProcessName);
  510.       Exit
  511.     end;
  512.   New (PipeData);
  513.   with PipeData^ do
  514.     begin
  515.       aChildProc := ChildProc;
  516.       ProcName := NewCString (ProcessName);
  517.       Path := NewCString (ProcessPath);
  518.       if @Parameters = nil then ParameterCount := 0 else ParameterCount := Parameters.Count;
  519.       GetMem (CProcessParameters, (ParameterCount + 2) * SizeOf (CString));
  520.       CProcessParameters^[0] := NewCString (ProcessName);
  521.       for i := 1 to ParameterCount do CProcessParameters^[i] := NewCString (Parameters [i]^);
  522.       CProcessParameters^[ParameterCount + 1] := nil;
  523.       CProcessEnvironment := ProcessEnvironment;
  524.       PipeProcess.PID := - 1;
  525.       PipeProcess.SignalPID := - 1;
  526.       PipeProcess.Signal := DefaultPipeSignal;
  527.       PipeProcess.Seconds := DefaultPipeSeconds;
  528.       PipeProcess.Wait := DefaultPipeWait;
  529.       PipeProcess.OpenPipes := 0;
  530.       PipeProcess.Result := nil;
  531.       PipeProcess.Status := nil;
  532.       if @Process <> nil then Process := @PipeProcess;
  533.       PToInputFile := @ToInputFile;
  534.       PFromOutputFile := @FromOutputFile;
  535.       PFromStdErrFile := @FromStdErrFile;
  536.       if @FromOutputFile = nil then
  537.         CNameStdOut := nil
  538.       else
  539.         begin
  540.           Inc (PipeProcess.OpenPipes);
  541.           NameStdOut := GetTempFileName;
  542.           CNameStdOut := NameStdOut;
  543.           if @ToInputFile <> nil then ResetNothing (FromOutputFile)
  544.         end;
  545.       if @FromStdErrFile = nil then
  546.         CNameStdErr := nil
  547.       else if @FromStdErrFile = @FromOutputFile then
  548.         CNameStdErr := CNameStdOut
  549.       else
  550.         begin
  551.           Inc (PipeProcess.OpenPipes);
  552.           NameStdErr := GetTempFileName;
  553.           CNameStdErr := NameStdErr;
  554.           if @ToInputFile <> nil then ResetNothing (FromStdErrFile)
  555.         end;
  556.       if @ToInputFile = nil then
  557.         begin
  558.           CNameStdIn := nil;
  559.           DoPipe (PipeData^);
  560.           if @FromOutputFile <> nil then
  561.             SetCloseAction (FromOutputFile, PipeData);
  562.           if (@FromStdErrFile <> nil) and (@FromStdErrFile <> @FromOutputFile) then
  563.             SetCloseAction (FromStdErrFile, PipeData)
  564.         end
  565.       else
  566.         begin
  567.           Inc (PipeProcess.OpenPipes);
  568.           NameStdIn := GetTempFileName;
  569.           CNameStdIn := NameStdIn;
  570.           Rewrite (InternalToInputFile, NameStdIn);
  571.           AssignTFDD (ToInputFile, nil, nil, nil, nil, PipeInTFDDWrite, nil, PipeInTFDDClose, nil, PipeData);
  572.           Rewrite (ToInputFile)
  573.         end
  574.     end
  575. end;
  576.  
  577. {$endif}
  578.  
  579. end.
  580.