Node: Pipes, Next: Ports, Previous: Overlay, Up: GPC Units

#### Start a child process, connected with pipes, also on Dos

The following listing contains the interface of the Pipes unit.

This unit provides routines to start a child process and write to/read from its Input/Output/StdErr via pipes. All of this is emulated transparently under Dos as far as possible.

         { Piping data from and to processes

           Copyright (C) 1998-2004 Free Software Foundation, Inc.

           Author: Frank Heckenbach <frank@pascal.gnu.de>

           This file is part of GNU Pascal.

           GNU Pascal is free software; you can redistribute it and/or modify
           it under the terms of the GNU General Public License as published
           by the Free Software Foundation; either version 2, or (at your
           option) any later version.

           GNU Pascal 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. See the GNU
           General Public License for more details.

           You should have received a copy of the GNU General Public License
           along with GNU Pascal; see the file COPYING. If not, write to the
           Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
           02111-1307, USA.

           As a special exception, if you link this file with files compiled
           with a GNU compiler to produce an executable, this does not cause
           the resulting executable to be covered by the GNU General Public
           License. This exception does not however invalidate any other
           reasons why the executable file might be covered by the GNU
           General Public License. }

         {$gnu-pascal,I-}
         {$if __GPC_RELEASE__ < 20030303}
         {$error This unit requires GPC release 20030303 or newer.}
         {$endif}

         { Keep this consistent with the one in pipesc.c }
         {$if defined (MSDOS) or defined (__MINGW32__)}
         {$define NOFORK}
         {$endif}

         unit Pipes;

         interface

         uses GPC;

         const
           PipeForking = {$ifdef NOFORK} False {$else} True {$endif};

         type
           TProcedure = procedure;

           PWaitPIDResult = ^TWaitPIDResult;
           TWaitPIDResult = (PIDNothing, PIDExited, PIDSignaled, PIDStopped,
           PIDUnknown);

           PPipeProcess = ^TPipeProcess;
           TPipeProcess = record
             PID      : Integer;         { Process ID of process forked }
             SignalPID: Integer;         { Process ID to send the signal to.
                                           Equals PID by default }
             OpenPipes: Integer;         { Number of pipes to/from the
                                           process, for internal use }
             Signal   : Integer;         { Send this signal (if not 0) to the
                                           process after all pipes have been
                                           closed after some time }
             Seconds  : Integer;         { Wait so many seconds before
                                           sending the signal if the process
                                           has not terminated by itself }
             Wait     : Boolean;         { Wait for the process, even longer
                                           than Seconds seconds, after
                                           sending the signal (if any) }
             Result   : PWaitPIDResult;  { Default nil. If a pointer to a
                                           variable is stored here, its
                                           destination will contain the
                                           information whether the process
                                           terminated by itself, or was
                                           terminated or stopped by a signal,
                                           when waiting after closing the
                                           pipes }
             Status   : ^Integer;        { Default nil. If a pointer to a
                                           variable is stored here, its
                                           destination will contain the exit
                                           status if the process terminated
                                           by itself, or the number of the
                                           signal otherwise, when waiting
                                           after closing the pipes }
           end;

         var
           { Default values for TPipeProcess records created by Pipe }
           DefaultPipeSignal : Integer = 0;
           DefaultPipeSeconds: Integer = 0;
           DefaultPipeWait   : Boolean = True;

         { The procedure Pipe starts a process whose name is given by
           ProcessName, with the given parameters (can be Null if no
           parameters) and environment, and create pipes from and/or to the
           process' standard input/output/error. ProcessName is searched for
           in the PATH with FSearchExecutable. Any of ToInputFile,
           FromOutputFile and FromStdErrFile can be Null if the corresponding
           pipe is not wanted. FromOutputFile and FromStdErrFile may be
           identical, in which case standard output and standard error are
           redirected to the same pipe. The behaviour of other pairs of files
           being identical is undefined, and useless, anyway. The files are
           Assigned and Reset or Rewritten as appropriate. Errors are
           returned in IOResult. If Process is not Null, a pointer to a
           record is stored there, from which the PID of the process created
           can be read, and by writing to which the action after all pipes
           have been closed can be changed. (The record is automatically
           Dispose'd of after all pipes have been closed.) If automatic
           waiting is turned off, the caller should get the PID from the
           record before it's Dispose'd of, and wait for the process sometime
           in order to avoid zombies. If no redirections are performed (i.e.,
           all 3 files are Null), the caller should wait for the process with
           WaitPipeProcess. When an error occurs, Process is not assigned to,
           and the state of the files is undefined, so be sure to check
           IOResult before going on.

           ChildProc, if not nil, is called in the child process after
           forking and redirecting I/O, but before executing the new process.
           It can even be called instead of executing a new process
           (ProcessName can be empty then).

           The procedure even works under Dos, but, of course, in a limited
           sense: if ToInputFile is used, the process will not actually be
           started until ToInputFile is closed. Signal, Seconds and Wait of
           TPipeProcess are ignored, and PID and SignalPID do not contain a
           Process ID, but an internal value without any meaning to the
           caller. Result will always be PIDExited. So, Status is the only
           interesting field (but Result should also be checked). Since there
           is no forking under Dos, ChildProc, if not nil, is called in the
           main process before spawning the program. So, to be portable, it
           should not do any things that would influence the process after
           the return of the Pipe function.

           The only portable way to use "pipes" in both directions is to call
           Pipe, write all the Input data to ToInputFile, close
           ToInputFile, and then read the Output and StdErr data from
           FromOutputFile and FromStdErrFile. However, since the capacity of
           pipes is limited, one should also check for Data from
           FromOutputFile and FromStdErrFile (using CanRead, IOSelect or
           IOSelectRead) while writing the Input data (under Dos, there
           simply won't be any data then, but checking for data doesn't do
           any harm). Please see pipedemo.pas for an example. }
         procedure Pipe (var ToInputFile, FromOutputFile, FromStdErrFile:
           AnyFile; const ProcessName: String; protected var Parameters:
           TPStrings; ProcessEnvironment: PCStrings; var Process:
           PPipeProcess; ChildProc: TProcedure); attribute (iocritical);

         { Waits for a process created by Pipe as determined in the Process
           record. (Process is Dispose'd of afterwards.) Returns True if
           successful. }
         function WaitPipeProcess (Process: PPipeProcess): Boolean; attribute
           (ignorable);

         { Alternative interface from PExecute }

         const
           PExecute_First   = 1;
           PExecute_Last    = 2;
           PExecute_One     = PExecute_First or PExecute_Last;
           PExecute_Search  = 4;
           PExecute_Verbose = 8;

         { PExecute: execute a chain of processes.

           Program and Arguments are the arguments to execv/execvp.

           Flags and PExecute_Search is non-zero if $PATH should be searched.
           Flags and PExecute_First is nonzero for the first process in
           chain. Flags and PExecute_Last is nonzero for the last process in
           chain.

           The result is the pid on systems like Unix where we fork/exec and
           on systems like MS-Windows and OS2 where we use spawn. It is up to
           the caller to wait for the child.

           The result is the exit code on systems like MSDOS where we spawn
           and wait for the child here.

           Upon failure, ErrMsg is set to the text of the error message,
           and -1 is returned. errno is available to the caller to use.

           PWait: cover function for wait.

           PID is the process id of the task to wait for. Status is the
           status argument to wait. Flags is currently unused (allows
           future enhancement without breaking upward compatibility). Pass 0
           for now.

           The result is the process ID of the child reaped, or -1 for
           failure.

           On systems that don't support waiting for a particular child, PID
           is ignored. On systems like MSDOS that don't really multitask
           PWait is just a mechanism to provide a consistent interface for
           the caller. }
         function  PExecute (ProgramName: CString; Arguments: PCStrings; var
           ErrMsg: String; Flags: Integer): Integer; attribute (ignorable,
           name = '_p_PExecute');
         function  PWait (PID: Integer; var Status: Integer; Flags: Integer):
           Integer; attribute (ignorable, name = '_p_PWait');