1 #ifndef STDIO_REDIRECTER_CLASS
2 #define STDIO_REDIRECTER_CLASS
4 /*****************************************************************************\
6 * Name : stdio_redirecter *
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 2005-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include <basis/contracts.h>
19 #include <basis/mutex.h>
20 #include <processes/ethread.h>
22 namespace application {
24 //! Redirects I/O for a newly launched application.
26 class stdio_redirecter : public virtual basis::root_object
29 stdio_redirecter(const basis::astring &command, const basis::astring ¶meters);
30 //!< controls the I/O for a program started with "command" and "parameters".
31 /*!< this creates an io redirecter that will trap the inputs and outputs
32 of a program called "command" that is launched with the "parameters".
33 the program can be communicated with via the read and write methods
37 //!< creates a blank redirecter which should be started up with reset().
40 //!< shuts down the program that was launched, if it's still running.
42 basis::outcome reset(const basis::astring &command, const basis::astring ¶meters);
43 //!< shuts down the active program and starts with new parameters.
45 DEFINE_CLASS_NAME("stdio_redirecter");
48 OKAY = basis::common::OKAY,
49 NOT_FOUND = basis::common::NOT_FOUND, //!< the file to launch was not found.
50 NONE_READY = basis::common::NONE_READY, //!< there was no data available.
51 PARTIAL = basis::common::PARTIAL, //!< only some of the bytes could be stored.
52 ACCESS_DENIED = basis::common::ACCESS_DENIED //!< the OS told us we could not.
55 basis::outcome health() const { return _persistent_result; }
56 //!< if the object constructed successfully, this returns OKAY.
57 /*!< otherwise an error occurred during the pipe creation or process fork.
61 //!< returns true if the application is still running.
62 /*!< if it exited on its own, then this will return false. */
64 int exit_value() const { return _exit_value; }
65 //!< returns the exit value from the app after it was launched.
66 /*!< this is only valid if the launch succeeded, the app ran, and now the
67 running() method is returning false because the application exited. */
69 int process_id() const { return _process_id; }
70 //!< the process id of the launched application.
71 /*!< this is only valid if the app is still running. */
74 //!< attempts to force a shutdown of the launched application.
75 /*!< this also closes out all of our pipes and handles. */
77 basis::outcome read(basis::byte_array &received);
78 //!< attempts to read bytes from the program's standard output.
79 /*!< if any bytes were found, OKAY is returned and the bytes are stored
82 basis::outcome write(const basis::byte_array &to_write, int &written);
83 //!< writes the bytes in "to_write" into the program's standard input.
84 /*!< OKAY is returned if all were successfully written. the number of
85 bytes that were actually sent to the program is put in "written". if only
86 a portion of the bytes could be written, then PARTIAL is returned. */
88 basis::outcome write(const basis::astring &to_write, int &written);
89 //!< sends a string "to_write" to the launched program's standard input.
91 basis::outcome read_stderr(basis::byte_array &received);
92 //!< reads from the program's standard error stream similarly to read().
95 //!< shuts down the standard input to the program.
96 /*!< this simulates when the program receives an end of file on its
99 // internal use only...
101 void std_thread_action(bool is_stdout);
102 //!< invoked by our threads when data becomes available.
103 /*!< if "is_stdout" is true, then that's the pipe we get data from.
104 otherwise we will try to get data from stderr. */
108 int _output_fds[2]; //!< file descriptors for parent's output.
109 int _input_fds[2]; //!< file descriptors for parent's input.
110 int _stderr_fds[2]; //!< file descriptors for standard error from child.
113 void *_child_in, *_child_out, *_child_err; //!< child process pipes replace io.
114 void *_parent_in, *_parent_out, *_parent_err; //!< our access to the pipes.
115 void *_app_handle; //!< refers to the launched application.
117 basis::astring *_command; //!< the application that we'll start and switch I/O on.
118 basis::astring *_parms; //!< the parameters for the app we will launch.
119 basis::outcome _persistent_result; //!< this records failures during construction.
120 processes::ethread *_stdout_reader; //!< gets data from process's stdout.
121 processes::ethread *_stderr_reader; //!< gets data from process's stderr.
122 basis::byte_array *_stdout_queue; //!< holds data acquired from stdout.
123 basis::byte_array *_stderr_queue; //!< holds data acquired from stderr.
124 basis::mutex *_lock; //!< protects our queues.
125 int _process_id; //!< pid for the launched program.
126 int _exit_value; //!< stored once when we notice app is gone.
128 basis::outcome create_pipes();
129 //!< creates the three pipes that the child will be given as stdin, stdout and stderr.
131 basis::outcome launch_program(int &new_process_id);
132 //!< launches the application using the previously established pipes.