portability/subprocesses.hpp

    1: #ifndef STLPLUS_SUBPROCESSES
    2: #define STLPLUS_SUBPROCESSES
    3: ////////////////////////////////////////////////////////////////////////////////
    4: 
    5: //   Author:    Andy Rushton
    6: //   Copyright: (c) Southampton University 1999-2004
    7: //              (c) Andy Rushton           2004-2009
    8: //   License:   BSD License, see ../docs/license.html
    9: 
   10: //   Platform-independent wrapper around the very platform-specific handling of
   11: //   subprocesses. Uses the C++ convention that all resources must be contained in
   12: //   an object so that when a subprocess object goes out of scope the subprocess
   13: //   itself gets closed down.
   14: 
   15: ////////////////////////////////////////////////////////////////////////////////
   16: #include "portability_fixes.hpp"
   17: #ifdef MSWINDOWS
   18: #include <windows.h>
   19: #endif
   20: #include <stdexcept>
   21: #include <vector>
   22: #include <string>
   23: #include <map> // for std::pair - why is this not defined separately?
   24: 
   25: ////////////////////////////////////////////////////////////////////////////////
   26: 
   27: namespace stlplus
   28: {
   29: 
   30:   ////////////////////////////////////////////////////////////////////////////////
   31:   // Argument vector class
   32:   // allows manipulation of argv-like vectors
   33:   // includes splitting of command lines into argvectors as per the shell
   34:   // (removing quotes) and the reverse conversion (adding quotes where necessary)
   35: 
   36:   class arg_vector
   37:   {
   38:   private:
   39:     char** m_argv;
   40: 
   41:   public:
   42:     // create an empty vector
   43:     arg_vector (void);
   44: 
   45:     // copy constructor (yes it copies)
   46:     arg_vector (const arg_vector&);
   47: 
   48:     // construct from an argv
   49:     arg_vector (char**);
   50: 
   51:     // construct from a command-line string
   52:     // includes de-quoting of values
   53:     arg_vector (const std::string&);
   54:     arg_vector (const char*);
   55: 
   56:     ~arg_vector (void);
   57: 
   58:     // assignment operators are compatible with the constructors
   59:     arg_vector& operator = (const arg_vector&);
   60:     arg_vector& operator = (char**);
   61:     arg_vector& operator = (const std::string&);
   62:     arg_vector& operator = (const char*);
   63: 
   64:     // add an argument to the vector
   65:     arg_vector& operator += (const std::string&);
   66:     arg_vector& operator -= (const std::string&);
   67: 
   68:     // insert/clear an argument at a certain index
   69:     // adding is like the other array classes - it moves the current item at index
   70:     // up one (and all subsequent values) to make room
   71:     void insert (unsigned index, const std::string&) throw(std::out_of_range);
   72:     void clear (unsigned index) throw(std::out_of_range);
   73:     void clear (void);
   74: 
   75:     // number of values in the vector (including argv[0], the command itself
   76:     unsigned size (void) const;
   77: 
   78:     // type conversion to the argv type
   79:     operator char** (void) const;
   80:     // function-based version of the above for people who don't like type conversions
   81:     char** argv (void) const;
   82: 
   83:     // access individual values in the vector
   84:     char* operator [] (unsigned index) const throw(std::out_of_range);
   85: 
   86:     // special-case access of the command name (e.g. to do path lookup on the command)
   87:     char* argv0 (void) const throw(std::out_of_range);
   88: 
   89:     // get the command-line string represented by this vector
   90:     // includes escaping of special characters and quoting
   91:     std::string image (void) const;
   92:   };
   93: 
   94:   ////////////////////////////////////////////////////////////////////////////////
   95:   // Environment class
   96:   // Allows manipulation of an environment vector
   97:   // This is typically used to create an environment to be used by a subprocess
   98:   // It does NOT modify the environment of the current process
   99: 
  100: #ifdef MSWINDOWS
  101: #define ENVIRON_TYPE char*
  102: #else
  103: #define ENVIRON_TYPE char**
  104: #endif
  105: 
  106:   class env_vector
  107:   {
  108:   private:
  109:     ENVIRON_TYPE m_env;
  110: 
  111:   public:
  112:     // create an env_vector vector from the current process
  113:     env_vector (void);
  114:     env_vector (const env_vector&);
  115:     ~env_vector (void);
  116: 
  117:     env_vector& operator = (const env_vector&);
  118: 
  119:     void clear (void);
  120: 
  121:     // manipulate the env_vector by adding or removing variables
  122:     // adding a name that already exists replaces its value
  123:     void add (const std::string& name, const std::string& value);
  124:     bool remove (const std::string& name);
  125: 
  126:     // get the value associated with a name
  127:     // the first uses an indexed notation (e.g. env["PATH"] )
  128:     // the second is a function based form (e.g. env.get("PATH"))
  129:     std::string operator [] (const std::string& name) const;
  130:     std::string get (const std::string& name) const;
  131: 
  132:     // number of name=value pairs in the env_vector
  133:     unsigned size (void) const;
  134: 
  135:     // get the name=value pairs by index (in the range 0 to size()-1)
  136:     std::pair<std::string,std::string> operator [] (unsigned index) const throw(std::out_of_range);
  137:     std::pair<std::string,std::string> get (unsigned index) const throw(std::out_of_range);
  138: 
  139:     // access the env_vector as an envp type - used for passing to subprocesses
  140:     ENVIRON_TYPE envp (void) const;
  141:   };
  142: 
  143:   ////////////////////////////////////////////////////////////////////////////////
  144: 
  145: #ifdef MSWINDOWS
  146: #define PID_TYPE PROCESS_INFORMATION
  147: #define PIPE_TYPE HANDLE
  148: #else
  149: #define PID_TYPE int
  150: #define PIPE_TYPE int
  151: #endif
  152: 
  153:   ////////////////////////////////////////////////////////////////////////////////
  154:   // Synchronous subprocess
  155: 
  156:   class subprocess
  157:   {
  158:   private:
  159: 
  160:     PID_TYPE m_pid;
  161: #ifdef MSWINDOWS
  162:     HANDLE m_job;
  163: #endif
  164:     PIPE_TYPE m_child_in;
  165:     PIPE_TYPE m_child_out;
  166:     PIPE_TYPE m_child_err;
  167:     env_vector m_env;
  168:     int m_err;
  169:     int m_status;
  170: 
  171:   public:
  172:     subprocess(void);
  173:     virtual ~subprocess(void);
  174: 
  175:     void add_variable(const std::string& name, const std::string& value);
  176:     bool remove_variable(const std::string& name);
  177: 
  178:     bool spawn(const std::string& path, const arg_vector& argv,
  179:                bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
  180:     bool spawn(const std::string& command_line,
  181:                bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
  182: 
  183:     virtual bool callback(void);
  184:     bool kill(void);
  185: 
  186:     int write_stdin(std::string& buffer);
  187:     int read_stdout(std::string& buffer);
  188:     int read_stderr(std::string& buffer);
  189: 
  190:     void close_stdin(void);
  191:     void close_stdout(void);
  192:     void close_stderr(void);
  193: 
  194:     bool error(void) const;
  195:     int error_number(void) const;
  196:     std::string error_text(void) const;
  197: 
  198:     int exit_status(void) const;
  199: 
  200:   private:
  201:     // disallow copying
  202:     subprocess(const subprocess&);
  203:     subprocess& operator=(const subprocess&);
  204:   };
  205: 
  206:   ////////////////////////////////////////////////////////////////////////////////
  207:   // Preconfigured subprocess which executes a command and captures its output
  208: 
  209:   class backtick_subprocess : public subprocess
  210:   {
  211:   private:
  212:     std::string m_text;
  213:   public:
  214:     backtick_subprocess(void);
  215:     virtual bool callback(void);
  216:     bool spawn(const std::string& path, const arg_vector& argv);
  217:     bool spawn(const std::string& command_line);
  218:     std::vector<std::string> text(void) const;
  219:   };
  220: 
  221:   std::vector<std::string> backtick(const std::string& path, const arg_vector& argv);
  222:   std::vector<std::string> backtick(const std::string& command_line);
  223: 
  224:   ////////////////////////////////////////////////////////////////////////////////
  225:   // Asynchronous subprocess
  226: 
  227:   class async_subprocess
  228:   {
  229:   private:
  230:     PID_TYPE m_pid;
  231: #ifdef MSWINDOWS
  232:     HANDLE m_job;
  233: #endif
  234:     PIPE_TYPE m_child_in;
  235:     PIPE_TYPE m_child_out;
  236:     PIPE_TYPE m_child_err;
  237:     env_vector m_env;
  238:     int m_err;
  239:     int m_status;
  240:     void set_error(int);
  241: 
  242:   public:
  243:     async_subprocess(void);
  244:     virtual ~async_subprocess(void);
  245: 
  246:     void add_variable(const std::string& name, const std::string& value);
  247:     bool remove_variable(const std::string& name);
  248: 
  249:     bool spawn(const std::string& path, const arg_vector& argv,
  250:                bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
  251:     bool spawn(const std::string& command_line,
  252:                bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
  253: 
  254:     virtual bool callback(void);
  255:     bool tick(void);
  256:     bool kill(void);
  257: 
  258:     int write_stdin(std::string& buffer);
  259:     int read_stdout(std::string& buffer);
  260:     int read_stderr(std::string& buffer);
  261: 
  262:     void close_stdin(void);
  263:     void close_stdout(void);
  264:     void close_stderr(void);
  265: 
  266:     bool error(void) const;
  267:     int error_number(void) const;
  268:     std::string error_text(void) const;
  269: 
  270:     int exit_status(void) const;
  271: 
  272:   private:
  273:     // disallow copying
  274:     async_subprocess(const async_subprocess&);
  275:     async_subprocess& operator=(const async_subprocess&);
  276:   };
  277: 
  278:   ////////////////////////////////////////////////////////////////////////////////
  279: 
  280: } // end namespace stlplus
  281: 
  282: #endif