PLearn 0.1
Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes
PLearn::Popen Class Reference

#include <Popen.h>

Inheritance diagram for PLearn::Popen:
Inheritance graph
[legend]
Collaboration diagram for PLearn::Popen:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 Popen (const string &command, bool the_verbose=false, bool redirect_stderr=false)
 Popen (const string &command, const vector< string > &commandoptions, bool the_verbose=false, bool redirect_stderr=false)
int wait ()
 Wait for process termination and return exit value.
 ~Popen ()
 Close the pipes and forcibly terminate the process.

Public Attributes

PStream in
PStream out
PStream err

Protected Member Functions

void launch (const string &command, const vector< string > &commandoptions, bool redirect_stderr=false)
 Multi-argument variant: the arguments are passed in a vector.
void launch (const string &commandline, bool redirect_stderr=false)
 Full text variant.

Protected Attributes

bool verbose
bool process_alive
PRProcess * process

Detailed Description

Definition at line 59 of file Popen.h.


Constructor & Destructor Documentation

PLearn::Popen::Popen ( const string &  command,
bool  the_verbose = false,
bool  redirect_stderr = false 
) [inline]

Definition at line 79 of file Popen.h.

    { verbose = the_verbose; launch(command, redirect_stderr); }
PLearn::Popen::Popen ( const string &  command,
const vector< string > &  commandoptions,
bool  the_verbose = false,
bool  redirect_stderr = false 
) [inline]

Definition at line 83 of file Popen.h.

    { verbose = the_verbose; launch(command,commandoptions, redirect_stderr); }
PLearn::Popen::~Popen ( )

Close the pipes and forcibly terminate the process.

If you wait until the process terminates by itself, you should call the wait() member function before the destructor is called.

Definition at line 188 of file Popen.cc.

{
    // If we get here, there's no way the caller that instantiated us will be
    // reading any more from the process at the other end of the pipe, and they
    // won't be able to retrieve the exit code either. So just make sure we
    // don't hang on the wait and that we don't leave zombie processes around.
    PR_KillProcess(process);
    wait();
}

Member Function Documentation

void PLearn::Popen::launch ( const string &  command,
const vector< string > &  commandoptions,
bool  redirect_stderr = false 
) [protected]

Multi-argument variant: the arguments are passed in a vector.

Definition at line 57 of file Popen.cc.

References PLearn::getPrErrorString(), i, in, PLERROR, and PLearn::quote_string().

{
    // Create pipes to communicate to/from child process.
    PRFileDesc* stdout_child;
    PRFileDesc* stdout_parent;
  
    if (PR_CreatePipe(&stdout_parent, &stdout_child) != PR_SUCCESS)
        PLERROR("Popen: error creating first pipe pair. (%s)",
                getPrErrorString().c_str());
    PRFileDesc* stdin_child;
    PRFileDesc* stdin_parent;

    if (PR_CreatePipe(&stdin_child, &stdin_parent) != PR_SUCCESS) {
        PR_Close(stdout_child);
        PR_Close(stdout_parent);
        PLERROR("Popen: error creating second pipe pair. (%s)",
                getPrErrorString().c_str());
    }

    PRFileDesc* stderr_child;
    PRFileDesc* stderr_parent;

    if(redirect_stderr)
        if (PR_CreatePipe(&stderr_child, &stderr_parent) != PR_SUCCESS) 
        {
            PR_Close(stderr_child);
            PR_Close(stderr_parent);
            PLERROR("Popen: error creating third (err) pipe pair. (%s)",
                    getPrErrorString().c_str());
        }

    // Set up redirection of stdin/stdout for the (future) child process.
    PRProcessAttr* process_attr = PR_NewProcessAttr();
    PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardInput, stdin_child);
    PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardOutput, stdout_child);
    if(redirect_stderr)
        PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardError, stderr_child);

    // Set up argument list for the CreateProcess call. args[0] shoud be the
    // name of the program. args[1]...arg[n] hold the actual arguments,
    // arg[n+1] is NULL.
#if !defined(_MINGW_) && !defined(WIN32)
    const char** args = new const char*[4];
    // NSPR doesn't have a way to search through the PATH when creating
    // a new process. Use /bin/sh for now to spawn the process as a workaround.
    args[0] = "/bin/sh";
    args[1] = "-c";

    string concatenated_args = program;
    for (vector<string>::const_iterator it = arguments.begin(); it != arguments.end();
         ++it)
        concatenated_args += " "+quote_string(*it);
    args[2] = concatenated_args.c_str();
    args[3] = 0;
  
    process = PR_CreateProcess("/bin/sh",
                               const_cast<char* const *>(args),
                               NULL, process_attr);
#else
    const char** args = new const char*[arguments.size()+2];
    // PR_CreateProcess on Windows goes through the PATH.
    // No workaround needed here.
    args[0] = program.c_str();
    int i = 1;
    for (vector<string>::const_iterator it = arguments.begin(); it != arguments.end();
         ++it)
        args[i++] = it->c_str();
    args[i] = 0;
  
    process = PR_CreateProcess(program.c_str(),
                               const_cast<char* const *>(args),
                               NULL, process_attr);  
#endif

    // Important: close unused files in the parent.
    PR_Close(stdin_child);
    PR_Close(stdout_child);
    if(redirect_stderr)
        PR_Close(stderr_child);
  
    delete[] args;                        
    if (!process) {
        PR_Close(stdin_parent);
        PR_Close(stdout_parent);
        if(redirect_stderr)
            PR_Close(stderr_parent);
        PLERROR("Popen: could not create subprocess for command '%s'. (%s)",
                program.c_str(), getPrErrorString().c_str());
    }
    process_alive = true;

    in = new PrPStreamBuf(stdout_parent, stdin_parent);
    in.setBufferCapacities(0, 0, 0);
    out = in;

    if(redirect_stderr)
    {    
        err= new PrPStreamBuf(stderr_parent);
        err.setBufferCapacities(0, 0, 0);
    }
}

Here is the call graph for this function:

void PLearn::Popen::launch ( const string &  commandline,
bool  redirect_stderr = false 
) [protected]

Full text variant.

All arguments are passed together in a string.

Deprecated:
Use the other version of launch instead.

Definition at line 160 of file Popen.cc.

References PLearn::openString(), and PLearn::PStream::plearn_ascii.

{
    // Parse command line into individual argments
    string tmp_commandline = "[" + commandline + "]";
    PStream s = openString(tmp_commandline, PStream::plearn_ascii);

    vector<string> command_and_args;
    s >> command_and_args;
    const string command = command_and_args[0];
    const vector<string> args(command_and_args.begin()+1,
                              command_and_args.end());
    launch(command, args, redirect_stderr);
}

Here is the call graph for this function:

int PLearn::Popen::wait ( )

Wait for process termination and return exit value.

Note:
This must be called after all output from the program has been read. (Some progs block until their output is read.)

Definition at line 175 of file Popen.cc.

References PLearn::getPrErrorString(), and PLERROR.

{
    int status = 0;
    if (process_alive)
        if (PR_WaitProcess(process, &status) != PR_SUCCESS)
            PLERROR("Popen: error while waiting for subprocess to terminate. (%s)",
                    getPrErrorString().c_str());
    process_alive = false;
  
    return status;
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 77 of file Popen.h.

Definition at line 76 of file Popen.h.

PRProcess* PLearn::Popen::process [protected]

Definition at line 72 of file Popen.h.

Definition at line 70 of file Popen.h.

Definition at line 69 of file Popen.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines