On Friday 18 June 2004 10:49 am, Helge Hafting wrote:
> Angus Leeming wrote:
> >Can I choose a value for "d" such that I don't need to modify
> > "val" in foo, below? I've tried and failed and so have resorted
> > to this runtime modification.
> >
> >    int const a = 1;
> >    int const b = 2;
> >    int const c = 4;
> >    int const d = 8;
> >
> >void foo(int val)
> >{
> >    // (val & d) implies (val & b) and (val & c)
> >    if (val & d)
> >        val |= b | c;
> >    ...
> >}
>
> What is it you want to do here?
> Do you want to set some bits, or test some bits, or both?
>
> Your example does "if (val & 8) val |= 6", which cannot be
> simplified further.
>
> Is the stuff in the comment a condition you want to enforce, (your
> code does that)
> or is it something that is "known to be true" so you want to
> simplify the code?
> If it is known to always be true then you may remove the entire
> if-statement because it does not change anything. It sets bits that
> are known to be set already.
>
> Or am I misunderstanding something?

Ok, let me explain.

I have a class which is used to launch, and interact with, a child 
process. I can interact with the child by writing data to its 
standard input stream and by reading data from its standard output 
and standard error streams.

Thus, I can define three pipes, identified by
        typedef int pipe_mode;
        pipe_mode const child_stdin = 1;
        pipe_mode const child_stdout = 2;
        pipe_mode const child_stderr = 4;

When I spawn the child process, I want some combination of these pipes 
to be opened:
        void process::spawn(string const & command, pipe_mode mode);

Usage examples:
        process ls, wc;
        ls.spawn("ls -l", child_stdout);
        wc.spawn("wc -l", child_stdin | child_stdoout);

Generally speaking I have two separate pipes to read the child's 
stdout and stderr. However, I can also redirect output from the 
child's stderr to stdout. So, I need to augment pipe_mode above:
        pipe_mode const child_redirect_stderr = X;
where X is currently 8.

What I'm trying to say is that I can pass any combination of these 
pipe_mode data to spawn. Eg
        process.spawn("ls -l", 
                child_stdin | child_stdout | child_stderr | child_redirect_stderr);

but that setting child_redirect_stderr *implies* that the pipe to 
child_stdout is opened and that the pipe to child_stderr is not 
opened.

So, in spawn I currently have the run time check

        if (mode & child_redirect_stderr) {
                mode |= child_stdout;
                if (mode & child_stderr) mode ^= child_stderr;
        }

This works well enough, as exemplified by the attached program.

Thereafter, I open pipes with (neglecting error checks)
        if (mode & child_stdin)
                ::pipe(child_in_fd);
        if (mode & child_stdout)
                ::pipe(child_out_fd);
        if (mode & child_stderr)
                ::pipe(child_err_fd);

Ie, if child_redirect_stderr is set, the I open child_out_fd and do 
not open child_err_fd.

Finally, in the child process, I set these file descriptors to the 
child's standard input, output and error streams:

        pid = ::fork();
        switch (pid) {
        case 0 :
                // This is the new process.

                // For each open pipe close one end and redirect the
                // respective standard stream to the other end

                if (*child_id_fd >= 0) {
                        ::close(child_in_fd[WR]);
                        ::dup2(child_in_fd[RD], STDIN_FILENO);
                        ::close(child_in_fd[RD]);
                }
                if (*child_out_fd >= 0) {
                        ::close(child_out_fd[RD]);
                        ::dup2(child_out_fd[WR], STDOUT_FILENO);
                        ::close(child_out_fd[WR]);
                }
                if (*child_err_fd >= 0) {
                        ::close(child_err_fd[RD]);
                        ::dup2(child_err_fd[WR], STDERR_FILENO);
                        ::close(child_err_fd[WR]);
                }

                if (*child_out_fd >= 0 && mode & child_redirect_stderr)
                        ::dup2(STDOUT_FILENO, STDERR_FILENO);

                break;
        }

This works well enough, but I was wondering if, by choosing a 
different value for child_redirect_stderr, I could avoid the run time 
check:
        if (mode & child_redirect_stderr) {
                mode |= child_stdout;
                if (mode & child_stderr) mode ^= child_stderr;
        }

Angus
#include <iostream>

typedef int pipe_mode;
pipe_mode const child_stdin = 1;
pipe_mode const child_stdout = 2;
pipe_mode const child_stderr = 4;
pipe_mode const child_redirect_stderr = 8;

void test(std::ostream & os, char const * const name, pipe_mode mode)
{
	if (mode & child_redirect_stderr) {
		mode |= child_stdout;
		if (mode & child_stderr) mode ^= child_stderr;
	}

	os << "\nmode == " << name << '\n'
	   << "\tmode & child_stdin "
	   << bool(mode & child_stdin) << '\n'
	   << "\tmode & child_stdout "
	   << bool(mode & child_stdout) << '\n'
	   << "\tmode & child_stderr "
	   << bool(mode & child_stderr) << '\n'
	   << "\tmode & child_redirect_stderr "
	   << bool(mode & child_redirect_stderr) << std::endl;
}

int main()
{
	test(std::cout,
	     "child_stdin",
	     child_stdin);
	test(std::cout,
	     "child_stdin|child_stdout",
	     child_stdin|child_stdout);
	test(std::cout,
	     "child_stdin|child_stdout|child_stderr",
	     child_stdin|child_stdout|child_stderr);
	test(std::cout,
	     "child_stdin|child_stdout|child_redirect_stderr",
	     child_stdin|child_stdout|child_redirect_stderr);
	test(std::cout,
	     "child_stdin|child_stdout|child_stderr|child_redirect_stderr",
	     child_stdin|child_stdout|child_stderr|child_redirect_stderr);
	test(std::cout,
	     "child_stdin|child_stderr",
	     child_stdin|child_stderr);
	test(std::cout,
	     "child_stdin|child_stderr|child_redirect_stderr",
	     child_stdin|child_stderr|child_redirect_stderr);
	test(std::cout,
	     "child_stdin|child_redirect_stderr",
	     child_stdin|child_redirect_stderr);

	test(std::cout,
	     "child_stdout",
	     child_stdout);
	test(std::cout,
	     "child_stdout|child_stderr",
	     child_stdout|child_stderr);
	test(std::cout,
	     "child_stdout|child_redirect_stderr",
	     child_stdout|child_redirect_stderr);
	test(std::cout,
	     "child_stdout|child_stderr|child_redirect_stderr",
	     child_stdout|child_stderr|child_redirect_stderr);

	test(std::cout,
	     "child_stderr",
	     child_stderr);
	test(std::cout,
	     "child_stderr|child_redirect_stderr",
	     child_stderr|child_redirect_stderr);

	test(std::cout,
	     "child_redirect_stderr",
	     child_redirect_stderr);
	return 0;
}

Reply via email to