first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / application / redirecter.h
1 #ifndef STDIO_REDIRECTER_CLASS
2 #define STDIO_REDIRECTER_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : stdio_redirecter                                                  *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
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 \*****************************************************************************/
17
18 #include <basis/contracts.h>
19 #include <basis/mutex.h>
20 #include <processes/ethread.h>
21
22 namespace application {
23
24 //! Redirects I/O for a newly launched application.
25
26 class stdio_redirecter : public virtual basis::root_object
27 {
28 public:
29   stdio_redirecter(const basis::astring &command, const basis::astring &parameters);
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
34     below. */
35
36   stdio_redirecter();
37     //!< creates a blank redirecter which should be started up with reset().
38
39   ~stdio_redirecter();
40     //!< shuts down the program that was launched, if it's still running.
41
42   basis::outcome reset(const basis::astring &command, const basis::astring &parameters);
43     //!< shuts down the active program and starts with new parameters.
44
45   DEFINE_CLASS_NAME("stdio_redirecter");
46
47   enum outcomes {
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.
53   };
54
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.
58     */
59
60   bool running();
61     //!< returns true if the application is still running.
62     /*!< if it exited on its own, then this will return false. */
63
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. */
68
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. */
72
73   void zap_program();
74     //!< attempts to force a shutdown of the launched application.
75     /*!< this also closes out all of our pipes and handles. */
76
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
80     in "received". */
81
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. */
87
88   basis::outcome write(const basis::astring &to_write, int &written);
89     //!< sends a string "to_write" to the launched program's standard input.
90
91   basis::outcome read_stderr(basis::byte_array &received);
92     //!< reads from the program's standard error stream similarly to read().
93
94   void close_input();
95     //!< shuts down the standard input to the program.
96     /*!< this simulates when the program receives an end of file on its
97     main input. */
98
99   // internal use only...
100
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. */
105
106 private:
107 #ifdef __UNIX__
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.
111 #endif
112 #ifdef __WIN32__
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.
116 #endif
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.
127
128   basis::outcome create_pipes();
129     //!< creates the three pipes that the child will be given as stdin, stdout and stderr.
130
131   basis::outcome launch_program(int &new_process_id);
132     //!< launches the application using the previously established pipes.
133 };
134
135 } //namespace.
136
137 #endif
138