subprocesses.hpp

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