So what's the fun of letting output handle by streams? 

Reusable code!

Once you communicate through streams all your software expecting information
from istreams and writing output to ostreams is maintenance free. Let's
concentrate on ostreams:

    - you can write to your screen
    - you can write to files on disk
    - you can write (e.g., using TCP/IP) to any computer anywhere in the world
    - you can write to the syslog
    - you can write to your friends living on Mars

There's no end to the fun. The only thing you need is a stream to which you
write as usual, which offers the adaptor to the device you want to send
information to. 

-----------------------------

OForkStream in this archive does exactly that. OForkStream receives lots of
information, but it's too much to show in a convenient way on your screen. In
such cases the program 'less' is a convenient tool: it allows you to page
through your information either by stepping (paging) back or by stepping
(paging) forward.

-----------------------------

Here's the core problem: we can define a new (o)stream: we've done that, and
essentially all it requires is a stream buffer overriding the virtual member
'overflow'. 

But the problem we must solve is: less doesn't know about overflow, but it
knows about its own standard input. Our stream buffer's task is to send each
character it receives not to some file, but to less's input.

-----------------------------

For that we use pipes. See the pipe(2) man page. But if you read that man-page
I guess it won't make your day... But the concept is easy: if you have two
processes (like when using fork) then you can create a pipe (before the fork)
and then use that pipe to communicate between the two processes:

Pre-fork:
                +-----------------------+    
                |                       |
                | pipe d_pipe           |
                |                       |
                +-----------------------+    

Post-fork:

        Parent:                                 Child
     +-----------------------+               +-----------------------+    
     |                       |               |                       |    
     | pipe d_pipe  ---------------------------> pipe d_pipe         |    
     |                       |               |                       |    
     +-----------------------+               +-----------------------+    

Here the pipe is used to send information from the paretn to the child, 
and the other direction is also possible (using another pipe)

-----------------------------

Pipe-ends (like the reading end at the child or the writing end at the parent)
are file-descriptors. 

OK, we can use write (see the write(2) man-page) to pipes, but that's not
funny: write doesn't work like streams. 

But we can use an existing ostream adaptor: Bobcat's OFdStream: create an
OFdStream by passing it a writing-end of a pipe and you can do things like

    OFdStream ofd{ pipe };
    ofd << "hello world" << endl;

Doesn't that look familiar?

This will nicely stash that familiar string into the pipe.

-----------------------------

We're getting close. Concentrate on the child process: 

                +-----------------------+    
                |                       |
      ------------> pipe d_pipe         |
                |      (for reading)    |
                |                       |
                +-----------------------+    

Once we fork, the child process itself calls 'less', right? But just before
that we fool less by making it believe it reads its std. input stream while in
fact it reads from the pipe:

                +-----------------------+     +--------------------------+    
                |                       |     |                          |    
      ------------> pipe d_pipe  ----------------> less (thinks it       |    
                |      (for reading)    |     |    reads its std. input) |    
                |                       |     |                          |    
                +-----------------------+     +--------------------------+        

That's all, folks.

-----------------------------

So how do we fool less? For that we redirect: another interesting Bobcat tool:
its Pipe class. 
    
    - first we create a Bobcat Pipe d_childInput, meaning the that's a pipe
      that will be used by the child process for reading. 

    - in the parent process we construct an OFdStream, passing it the writing
        end of Bobcat's Pipe:

            OFdStream{ d_childInput.writeOnly() };

      Since the child reads, the parent uses the writing end of the pipe.

    - in the child process we redirect the pipe's reading end to the child
      process's standard input. That happens just before calling less:

        d_childInput.readFrom(Redirector::STDIN);
                   // or use: STDIN_FILENO

-----------------------------

The child process looks a lot like what you've used for the compiler-program:
the child process itself is replaced by the less-process, which now nicely
reads from our pipe. To call less I didn't struggle with a member of the
exec-family but used yet another Bobcat class: Process.

-----------------------------

The program ends once we decide that all input has been sent to less. At that
point OForkStream goes out of scope, flushing its buffer.  Then it dies,
immediately followed by the destruction of its stream buffer. That also ends the
parent process: its destructor flushes its pipe, then closes its pipe.

Less, noticing that it has reached the end of its input quits, and so the
streambuf's destructor receives less's exit code via 'waitForChild', and we're
done. 

-----------------------------

So:
    - we created an ostream
    - it communicates with its streambuf
    - its streambuf sets up a pipe
    - the streambuf's child process is replaced by 'less'
    - less reads from the pipe
    - once we're done inserting info into the ostream, the pipe is
      closed, less ends, and we properly wait for less to end its work

Want to write to a different destination: put main's insertions in a function
expecting an ostream &, and pass that function, e.g., cout, and OForkStream
object, an ofstream object, and .... take your pick.


If you want to run the program yourself, either use icmake's 'icmbuild' script
or use your own favorite maintenance tool. Essentially: compile all .cc files,
and link 'em to the bobcat library. Note that the class Fork (in the ./fork
directory) isn't used: no need to compile its sources.

------------------------------

Postscript: 

    In the code you'll find in the tar there's lots of commented out stuff. I
    didn't construct OForkStream in 5 minutes time. Many of the things I did
    are still visible in commented-out sections of the source files.
