📄 imore.cpp
字号:
// ============================================================================
// imore.cpp,v 4.10 2003/11/01 11:15:23 dhinton Exp
//
// = 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/FIFO_Recv.h"
#include "ace/FIFO_Send.h"
#include "ace/Pipe.h"
#include "ace/Get_Opt.h"
#include "ace/Process.h"
#include "ace/Signal.h"
ACE_RCSID(Process, imore, "imore.cpp,v 4.10 2003/11/01 11:15:23 dhinton Exp")
#if defined (ACE_WIN32)
static const char * executable = "MORE.COM";
static const char *rendezvous_dir = "c:/temp";
static const char *rendezvous_pfx = "imore";
#else
static const char * executable = "more"; // I like less better.
static const char *rendezvous_dir = "/tmp";
static const char *rendezvous_pfx = "imore";
#endif /* ACE_WIN32 */
static char *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, char **argv)
{
ACE_Get_Opt get_opt (argc, argv, "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.
char *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
main (int argc, char *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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -