summaryrefslogtreecommitdiff
path: root/ACE/examples/OS/Process/imore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/examples/OS/Process/imore.cpp')
-rw-r--r--ACE/examples/OS/Process/imore.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/ACE/examples/OS/Process/imore.cpp b/ACE/examples/OS/Process/imore.cpp
new file mode 100644
index 00000000000..181254e0cb4
--- /dev/null
+++ b/ACE/examples/OS/Process/imore.cpp
@@ -0,0 +1,267 @@
+// ============================================================================
+// $Id$
+//
+// = LIBRARY
+// examples
+//
+// = FILENAME
+// imore.cpp (imore stands for indirect more.)
+//
+// = DESCRIPTION
+// This program demonstrates how to redirect stdout of a parent
+// process to the stdin of its child process using either unnamed pipe
+// or named pipes to relay data to subprocess which runs "more" to
+// display data on the screen. Run imore to see how to use this
+// program.
+//
+// Unfortunately, on Win32, this program doesn't use any pipe at all because
+// using pipes confuses MORE.COM on Win32 and it just acts like "cat" on Unix.
+//
+// = AUTHOR
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/FIFO_Recv.h"
+#include "ace/FIFO_Send.h"
+#include "ace/Pipe.h"
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+#include "ace/Process.h"
+#include "ace/Signal.h"
+
+ACE_RCSID(Process, imore, "$Id$")
+
+#if defined (ACE_WIN32)
+static const ACE_TCHAR *executable = ACE_TEXT("MORE.COM");
+static const ACE_TCHAR *rendezvous_dir = ACE_TEXT("c:/temp");
+static const ACE_TCHAR *rendezvous_pfx = ACE_TEXT("imore");
+#else
+static const char * executable = "more"; // I like less better.
+static const ACE_TCHAR *rendezvous_dir = ACE_TEXT("/tmp");
+static const ACE_TCHAR *rendezvous_pfx = ACE_TEXT("imore");
+#endif /* ACE_WIN32 */
+
+static ACE_TCHAR *fname = 0; // File you want to view.
+static int use_named_pipe = 0; // Do we want to use named pipe?
+
+static void
+usage (void)
+{
+ ACE_ERROR ((LM_ERROR, "Usage: imore [-n|-u] <filename>\n"
+ "\t-n Use named pipe.\n"
+ "\t-u Use unnamed pipe.\n"));
+}
+
+static int
+parse_args (int argc, ACE_TCHAR **argv)
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("un"));
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ {
+ switch (c)
+ {
+ case 'n': // We want to use named pipe.
+#if !defined (ACE_WIN32)
+ use_named_pipe = 1;
+#else
+ ACE_ERROR_RETURN ((LM_ERROR, "Named pipes not supported on Win32\n"), -1);
+#endif /* !ACE_WIN32 */
+ break;
+ case 'u': // Use unnamed pipe.
+ use_named_pipe = 0;
+ break;
+ default: // What are you talking about?
+ usage ();
+ return -1;
+ }
+ }
+
+ if (get_opt.opt_ind () >= argc) // Do you forget to give me a filename to "more?"
+ {
+ usage ();
+ return -1;
+ }
+ else
+ fname = argv[get_opt.opt_ind ()]; // Alright.
+
+ return 0;
+}
+
+static int
+setup_named_pipes (ACE_Process_Options &opt)
+{
+ // Create a unique temporary name for named pipe.
+ ACE_TCHAR *rendezvous = ACE_OS::tempnam (rendezvous_dir,
+ rendezvous_pfx);
+
+ // Out of memory?
+ if (rendezvous == NULL)
+ return -1;
+
+ // Alright, this is indeed strange. Named pipes are meant to be
+ // used for unrelated processes. Because of the constraints in
+ // ACE_Process, I have to pre-open the named pipes here.
+ ACE_FIFO_Recv rfifo; // read end fifo.
+ ACE_FIFO_Send wfifo; // write end fifo.
+
+ // Check if the pipes are created successfully.
+ if (rfifo.open (rendezvous) == -1 || wfifo.open (rendezvous) == -1)
+ {
+ ACE_OS::free (rendezvous);
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "fifo.open"), -1);
+ }
+
+ // Remove (rm, del) the file after no one uses it any more.
+ ACE_OS::unlink (rendezvous);
+ ACE_OS::free (rendezvous);
+
+ // Setting up pipe between parent and child process. Use the read
+ // end of the named pipe as child process'es ACE_STDIN.
+ // ACE_Process_Options will keep copies (by dup) of fd's that we
+ // pass in. Notice that we have to specify child process to use
+ // ACE_STDOUT for output explicitly because we'll close it down in
+ // the line after. Child process will use whatever we use to dup2
+ // ACE_STDOUT as its stdout.
+ opt.set_handles (rfifo.get_handle (), ACE_STDOUT);
+
+ // The previous keep a copy of original ACE_STDOUT fd, now we
+ // can replace ACE_STDOUT of parent process to the write end
+ // of the named pipe.
+ ACE_OS::dup2 (wfifo.get_handle (), ACE_STDOUT);
+
+ // Close unused fd's. Notice ACE_FIFO doesn't close the fd
+ // when it goes out of scope.
+ rfifo.close ();
+ wfifo.close ();
+ return 0;
+}
+
+static int
+setup_unnamed_pipe (ACE_Process_Options &opt)
+{
+ // Create an unnamed pipe instance.
+ ACE_Pipe pipe;
+
+ // Check if the pipe is created successfully.
+ if (pipe.open () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pipe.open"), -1);
+
+ // Setting up pipe between parent and child process. Use the pipe
+ // as child process'es ACE_STDIN. ACE_Process_Options will keep
+ // copies (by dup) of fd's that we pass in. Notice that we have to
+ // specify child process to use ACE_STDOUT for output explicitly
+ // because we'll close it down in the line after. Child process
+ // will use whatever we use to dup2 ACE_STDOUT as its stdout.
+ opt.set_handles (pipe.read_handle (), ACE_STDOUT);
+
+ // The previous keep a copy of original ACE_STDOUT fd, now we
+ // can replace ACE_STDOUT of parent process to the pipe.
+ ACE_OS::dup2 (pipe.write_handle (), ACE_STDOUT);
+
+ // Don't forget to close the unused fd.
+ pipe.close ();
+ return 0;
+}
+
+static int
+print_file (ACE_HANDLE infd)
+{
+ char buffer[BUFSIZ];
+ ssize_t len;
+
+ while ((len = ACE_OS::read (infd, buffer, BUFSIZ)) > 0)
+ {
+ if ((ACE_OS::write (ACE_STDOUT, buffer, len) != len))
+ if (errno == EPIPE)
+ {
+ // I tried to "produce" EPIPE warning to test
+ // the program but never seen one. (odd.)
+ // ACE_ERROR ((LM_ERROR, "\n\nEPIPE\n"));
+ break;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "write"), -1);
+ }
+ return 0;
+}
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // Ignore SIGPIPE signal on Unix platforms in case
+ // child process (more) terminates before we finish
+ // writing to stdout.
+#if !defined (ACE_WIN32)
+ ACE_Sig_Action sig_act (SIG_IGN);
+ if (sig_act.register_action (SIGPIPE) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Sig_Action::register_action"), -1);
+#endif /* ACE_WIN32 */
+
+ // Alright, what you want me to do now?
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+ // Can I find the file you want?
+ ACE_HANDLE infile = ACE_OS::open (fname, O_RDONLY);
+ if (infile == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_DEBUG, "%p\n", fname), -1);
+
+ ACE_Process new_process;
+
+ // Notice that we must enclose ACE_Process_Options in the block
+ // so the file handlers it keeps can be close elegantly.
+#if !defined (ACE_WIN32)
+ {
+ ACE_Process_Options options;
+
+ if ((use_named_pipe ? ::setup_named_pipes :
+ ::setup_unnamed_pipe) (options) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1);
+
+ options.command_line (executable);
+ if (new_process.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n",
+ "test_more", error), -1);
+ }
+ }
+
+ // write file to ACE_STDOUT.
+ if (::print_file (infile) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Error, bailing out!\n"), -1);
+
+ // Close the STDOUT to inform child eof.
+ ACE_OS::close (ACE_STDOUT);
+#else
+ // We can only pass a file handler directly to child process
+ // otherwise "more" doesn't act quite the way we want. Nonetheless,
+ // if your child process don't need to interact with the terminal,
+ // we can use the exact code for Unixes on NT.
+ ACE_Process_Options options;
+ options.command_line (executable);
+ options.set_handles (infile);
+ if (new_process.spawn (options) == -1)
+ {
+ int error = ACE_OS::last_error ();
+ ACE_ERROR_RETURN ((LM_ERROR, "%p errno = %d.\n",
+ "test_more", error), -1);
+ }
+#endif /* ! ACE_WIN32 */
+
+ // Wait till we are done.
+ ACE_exitcode status;
+ new_process.wait (&status);
+ ACE_DEBUG ((LM_DEBUG, "Process exit with status %d\n", status));
+
+ ACE_OS::close (infile);
+
+ return 0;
+}