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