Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / ACE / examples / OS / Process / imore.cpp
blobbee6f5cd3f6cddb7c88db0c1de8ad3ce06bc30fa
1 //=============================================================================
2 /**
3 * @file imore.cpp (imore stands for indirect more.)
5 * This program demonstrates how to redirect stdout of a parent
6 * process to the stdin of its child process using either unnamed pipe
7 * or named pipes to relay data to subprocess which runs "more" to
8 * display data on the screen. Run imore to see how to use this
9 * program.
11 * Unfortunately, on Win32, this program doesn't use any pipe at all because
12 * using pipes confuses MORE.COM on Win32 and it just acts like "cat" on Unix.
14 * @author Nanbor Wang <nanbor@cs.wustl.edu>
16 //=============================================================================
19 #include "ace/OS_NS_stdio.h"
20 #include "ace/OS_NS_errno.h"
21 #include "ace/OS_NS_unistd.h"
22 #include "ace/OS_NS_fcntl.h"
23 #include "ace/FIFO_Recv.h"
24 #include "ace/FIFO_Send.h"
25 #include "ace/Pipe.h"
26 #include "ace/Get_Opt.h"
27 #include "ace/Log_Msg.h"
28 #include "ace/Process.h"
29 #include "ace/Signal.h"
32 #if defined (ACE_WIN32)
33 static const ACE_TCHAR *executable = ACE_TEXT("MORE.COM");
34 #else
35 static const char * executable = "more"; // I like less better.
36 static const ACE_TCHAR *rendezvous_dir = ACE_TEXT("/tmp");
37 static const ACE_TCHAR *rendezvous_pfx = ACE_TEXT("imore");
38 #endif /* ACE_WIN32 */
40 static ACE_TCHAR *fname = 0; // File you want to view.
41 static int use_named_pipe = 0; // Do we want to use named pipe?
43 static void
44 usage ()
46 ACE_ERROR ((LM_ERROR, "Usage: imore [-n|-u] <filename>\n"
47 "\t-n Use named pipe.\n"
48 "\t-u Use unnamed pipe.\n"));
51 static int
52 parse_args (int argc, ACE_TCHAR **argv)
54 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("un"));
55 int c;
57 while ((c = get_opt ()) != -1)
59 switch (c)
61 case 'n': // We want to use named pipe.
62 #if !defined (ACE_WIN32)
63 use_named_pipe = 1;
64 #else
65 ACE_ERROR_RETURN ((LM_ERROR, "Named pipes not supported on Win32\n"), -1);
66 #endif /* !ACE_WIN32 */
67 break;
68 case 'u': // Use unnamed pipe.
69 use_named_pipe = 0;
70 break;
71 default: // What are you talking about?
72 usage ();
73 return -1;
77 if (get_opt.opt_ind () >= argc) // Do you forget to give me a filename to "more?"
79 usage ();
80 return -1;
82 else
83 fname = argv[get_opt.opt_ind ()]; // Alright.
85 return 0;
88 #if !defined (ACE_WIN32) && !defined (ACE_DISABLE_TEMPNAM)
89 static int
90 setup_named_pipes (ACE_Process_Options &opt)
92 // Create a unique temporary name for named pipe.
93 ACE_TCHAR *rendezvous = ACE_OS::tempnam (rendezvous_dir,
94 rendezvous_pfx);
96 // Out of memory?
97 if (rendezvous == 0)
98 return -1;
100 // Alright, this is indeed strange. Named pipes are meant to be
101 // used for unrelated processes. Because of the constraints in
102 // ACE_Process, I have to pre-open the named pipes here.
103 ACE_FIFO_Recv rfifo; // read end fifo.
104 ACE_FIFO_Send wfifo; // write end fifo.
106 // Check if the pipes are created successfully.
107 if (rfifo.open (rendezvous) == -1 || wfifo.open (rendezvous) == -1)
109 ACE_OS::free (rendezvous);
110 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "fifo.open"), -1);
113 // Remove (rm, del) the file after no one uses it any more.
114 ACE_OS::unlink (rendezvous);
115 ACE_OS::free (rendezvous);
117 // Setting up pipe between parent and child process. Use the read
118 // end of the named pipe as child process'es ACE_STDIN.
119 // ACE_Process_Options will keep copies (by dup) of fd's that we
120 // pass in. Notice that we have to specify child process to use
121 // ACE_STDOUT for output explicitly because we'll close it down in
122 // the line after. Child process will use whatever we use to dup2
123 // ACE_STDOUT as its stdout.
124 opt.set_handles (rfifo.get_handle (), ACE_STDOUT);
126 // The previous keep a copy of original ACE_STDOUT fd, now we
127 // can replace ACE_STDOUT of parent process to the write end
128 // of the named pipe.
129 ACE_OS::dup2 (wfifo.get_handle (), ACE_STDOUT);
131 // Close unused fd's. Notice ACE_FIFO doesn't close the fd
132 // when it goes out of scope.
133 rfifo.close ();
134 wfifo.close ();
135 return 0;
137 #endif
139 #if !defined (ACE_WIN32)
140 static int
141 setup_unnamed_pipe (ACE_Process_Options &opt)
143 // Create an unnamed pipe instance.
144 ACE_Pipe pipe;
146 // Check if the pipe is created successfully.
147 if (pipe.open () == -1)
148 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pipe.open"), -1);
150 // Setting up pipe between parent and child process. Use the pipe
151 // as child process'es ACE_STDIN. ACE_Process_Options will keep
152 // copies (by dup) of fd's that we pass in. Notice that we have to
153 // specify child process to use ACE_STDOUT for output explicitly
154 // because we'll close it down in the line after. Child process
155 // will use whatever we use to dup2 ACE_STDOUT as its stdout.
156 opt.set_handles (pipe.read_handle (), ACE_STDOUT);
158 // The previous keep a copy of original ACE_STDOUT fd, now we
159 // can replace ACE_STDOUT of parent process to the pipe.
160 ACE_OS::dup2 (pipe.write_handle (), ACE_STDOUT);
162 // Don't forget to close the unused fd.
163 pipe.close ();
164 return 0;
166 #endif
168 #if !defined (ACE_WIN32)
169 static int
170 print_file (ACE_HANDLE infd)
172 char buffer[BUFSIZ];
173 ssize_t len;
175 while ((len = ACE_OS::read (infd, buffer, BUFSIZ)) > 0)
177 if ((ACE_OS::write (ACE_STDOUT, buffer, len) != len))
179 if (errno == EPIPE)
181 // I tried to "produce" EPIPE warning to test
182 // the program but never seen one. (odd.)
183 // ACE_ERROR ((LM_ERROR, "\n\nEPIPE\n"));
184 break;
186 else
188 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "write"), -1);
193 return 0;
195 #endif
198 ACE_TMAIN (int argc, ACE_TCHAR *argv[])
200 // Ignore SIGPIPE signal on Unix platforms in case
201 // child process (more) terminates before we finish
202 // writing to stdout.
203 #if !defined (ACE_WIN32)
204 ACE_Sig_Action sig_act (SIG_IGN);
205 if (sig_act.register_action (SIGPIPE) == -1)
206 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Sig_Action::register_action"), -1);
207 #endif /* ACE_WIN32 */
209 // Alright, what you want me to do now?
210 if (::parse_args (argc, argv) == -1)
211 return -1;
213 // Can I find the file you want?
214 ACE_HANDLE infile = ACE_OS::open (fname, O_RDONLY);
215 if (infile == ACE_INVALID_HANDLE)
216 ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", fname), -1);
218 ACE_Process new_process;
220 // The ACE_Process_Options does not need to be enclosed in a block
221 // because it does not close the file handles, the ACE_Process closes
222 // them upon destruction.
223 #if !defined (ACE_WIN32)
224 ACE_Process_Options options;
226 if (use_named_pipe)
228 # if defined (ACE_DISABLE_TEMPNAM)
229 ACE_ERROR_RETURN ((LM_ERROR,
230 "ACE_DISABLE_TEMPNAM set; can't use named pipes\n"),
231 -1);
232 # else
233 if (::setup_named_pipes (options) == -1)
234 ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1);
235 # endif /* ACE_DISABLE_TEMPNAM */
237 else
239 if (::setup_unnamed_pipe (options) == -1)
240 ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1);
243 options.command_line (ACE_TEXT("%") ACE_TEXT_PRIs, executable);
244 if (new_process.spawn (options) == -1)
246 int const error_number = ACE_OS::last_error ();
247 ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n",
248 "test_more", error_number), -1);
251 // write file to ACE_STDOUT.
252 if (::print_file (infile) == -1)
253 ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1);
255 // Close the STDOUT to inform child eof.
256 ACE_OS::close (ACE_STDOUT);
257 #else
258 // We can only pass a file handler directly to child process
259 // otherwise "more" doesn't act quite the way we want. Nonetheless,
260 // if your child process don't need to interact with the terminal,
261 // we can use the exact code for Unixes on NT.
262 ACE_Process_Options options;
263 options.command_line (ACE_TEXT("%") ACE_TEXT_PRIs, executable);
264 options.set_handles (infile);
265 if (new_process.spawn (options) == -1)
267 int error = ACE_OS::last_error ();
268 ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n",
269 "test_more", error), -1);
271 #endif /* ! ACE_WIN32 */
273 // Wait till we are done.
274 ACE_exitcode status;
275 new_process.wait (&status);
276 ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
278 ACE_OS::close (infile);
280 return 0;