PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 2001 Pascal Vincent, Yoshua Bengio and University of Montreal 00005 // 00006 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 00036 00037 00038 /* ******************************************************* 00039 * $Id: Popen.cc 9130 2008-06-16 18:21:54Z saintmlx $ 00040 * This file is part of the PLearn library. 00041 ******************************************************* */ 00042 00043 #include "Popen.h" 00044 00045 #include <nspr/prio.h> 00046 #include <nspr/prproces.h> 00047 #include <nspr/prenv.h> 00048 #include <plearn/base/stringutils.h> 00049 #include <plearn/base/PrUtils.h> 00050 #include <plearn/io/PrPStreamBuf.h> 00051 #include <plearn/io/openString.h> 00052 00053 00054 namespace PLearn { 00055 using namespace std; 00056 00057 void Popen::launch(const string& program, const vector<string>& arguments, bool redirect_stderr) 00058 { 00059 // Create pipes to communicate to/from child process. 00060 PRFileDesc* stdout_child; 00061 PRFileDesc* stdout_parent; 00062 00063 if (PR_CreatePipe(&stdout_parent, &stdout_child) != PR_SUCCESS) 00064 PLERROR("Popen: error creating first pipe pair. (%s)", 00065 getPrErrorString().c_str()); 00066 PRFileDesc* stdin_child; 00067 PRFileDesc* stdin_parent; 00068 00069 if (PR_CreatePipe(&stdin_child, &stdin_parent) != PR_SUCCESS) { 00070 PR_Close(stdout_child); 00071 PR_Close(stdout_parent); 00072 PLERROR("Popen: error creating second pipe pair. (%s)", 00073 getPrErrorString().c_str()); 00074 } 00075 00076 PRFileDesc* stderr_child; 00077 PRFileDesc* stderr_parent; 00078 00079 if(redirect_stderr) 00080 if (PR_CreatePipe(&stderr_child, &stderr_parent) != PR_SUCCESS) 00081 { 00082 PR_Close(stderr_child); 00083 PR_Close(stderr_parent); 00084 PLERROR("Popen: error creating third (err) pipe pair. (%s)", 00085 getPrErrorString().c_str()); 00086 } 00087 00088 // Set up redirection of stdin/stdout for the (future) child process. 00089 PRProcessAttr* process_attr = PR_NewProcessAttr(); 00090 PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardInput, stdin_child); 00091 PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardOutput, stdout_child); 00092 if(redirect_stderr) 00093 PR_ProcessAttrSetStdioRedirect(process_attr, PR_StandardError, stderr_child); 00094 00095 // Set up argument list for the CreateProcess call. args[0] shoud be the 00096 // name of the program. args[1]...arg[n] hold the actual arguments, 00097 // arg[n+1] is NULL. 00098 #if !defined(_MINGW_) && !defined(WIN32) 00099 const char** args = new const char*[4]; 00100 // NSPR doesn't have a way to search through the PATH when creating 00101 // a new process. Use /bin/sh for now to spawn the process as a workaround. 00102 args[0] = "/bin/sh"; 00103 args[1] = "-c"; 00104 00105 string concatenated_args = program; 00106 for (vector<string>::const_iterator it = arguments.begin(); it != arguments.end(); 00107 ++it) 00108 concatenated_args += " "+quote_string(*it); 00109 args[2] = concatenated_args.c_str(); 00110 args[3] = 0; 00111 00112 process = PR_CreateProcess("/bin/sh", 00113 const_cast<char* const *>(args), 00114 NULL, process_attr); 00115 #else 00116 const char** args = new const char*[arguments.size()+2]; 00117 // PR_CreateProcess on Windows goes through the PATH. 00118 // No workaround needed here. 00119 args[0] = program.c_str(); 00120 int i = 1; 00121 for (vector<string>::const_iterator it = arguments.begin(); it != arguments.end(); 00122 ++it) 00123 args[i++] = it->c_str(); 00124 args[i] = 0; 00125 00126 process = PR_CreateProcess(program.c_str(), 00127 const_cast<char* const *>(args), 00128 NULL, process_attr); 00129 #endif 00130 00131 // Important: close unused files in the parent. 00132 PR_Close(stdin_child); 00133 PR_Close(stdout_child); 00134 if(redirect_stderr) 00135 PR_Close(stderr_child); 00136 00137 delete[] args; 00138 if (!process) { 00139 PR_Close(stdin_parent); 00140 PR_Close(stdout_parent); 00141 if(redirect_stderr) 00142 PR_Close(stderr_parent); 00143 PLERROR("Popen: could not create subprocess for command '%s'. (%s)", 00144 program.c_str(), getPrErrorString().c_str()); 00145 } 00146 process_alive = true; 00147 00148 in = new PrPStreamBuf(stdout_parent, stdin_parent); 00149 in.setBufferCapacities(0, 0, 0); 00150 out = in; 00151 00152 if(redirect_stderr) 00153 { 00154 err= new PrPStreamBuf(stderr_parent); 00155 err.setBufferCapacities(0, 0, 0); 00156 } 00157 } 00158 00159 00160 void Popen::launch(const string& commandline, bool redirect_stderr) 00161 { 00162 // Parse command line into individual argments 00163 string tmp_commandline = "[" + commandline + "]"; 00164 PStream s = openString(tmp_commandline, PStream::plearn_ascii); 00165 00166 vector<string> command_and_args; 00167 s >> command_and_args; 00168 const string command = command_and_args[0]; 00169 const vector<string> args(command_and_args.begin()+1, 00170 command_and_args.end()); 00171 launch(command, args, redirect_stderr); 00172 } 00173 00174 00175 int Popen::wait() 00176 { 00177 int status = 0; 00178 if (process_alive) 00179 if (PR_WaitProcess(process, &status) != PR_SUCCESS) 00180 PLERROR("Popen: error while waiting for subprocess to terminate. (%s)", 00181 getPrErrorString().c_str()); 00182 process_alive = false; 00183 00184 return status; 00185 } 00186 00187 00188 Popen::~Popen() 00189 { 00190 // If we get here, there's no way the caller that instantiated us will be 00191 // reading any more from the process at the other end of the pipe, and they 00192 // won't be able to retrieve the exit code either. So just make sure we 00193 // don't hang on the wait and that we don't leave zombie processes around. 00194 PR_KillProcess(process); 00195 wait(); 00196 } 00197 00198 00199 vector<string> execute(const string& command, bool redirect_stderr) 00200 { 00201 Popen p(command, redirect_stderr); 00202 vector<string> result; 00203 while(p.in.good()) 00204 { 00205 string line = p.in.getline(); 00206 result.push_back(line); 00207 } 00208 return result; 00209 } 00210 00211 } // end of namespace PLearn 00212 00213 00214 /* 00215 Local Variables: 00216 mode:c++ 00217 c-basic-offset:4 00218 c-file-style:"stroustrup" 00219 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00220 indent-tabs-mode:nil 00221 fill-column:79 00222 End: 00223 */ 00224 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :