sommergyll.software(c++);
"programming the standard streams for output and error output"
 

Introduction

Sometimes it is useful and necessary to redirect the standard streams for output and error output. By default they are printed on the console screen but by redirection, it is possible to capture the printed text in a e.g. log file. This guide shows one way of doing this.

A Simple Redirection Example

We will implement a console application that redirects the stdout and stderr to a log file. The code that does the actual starting and stopping of the redirection is put in a separate class. Note that this is only tested on MS Windows XP.

Main method

The listing below consists of the redirecting class and the main method. The main method is very straightforward: first it creates an object of SimpleRedirect and then it makes a call to the StartRedirect method. This causes the output to be saved in a custom log file. We now make a couple of system calls, e.g. system("dir") and system("silly"). The "silly" command is obviously invalid and will therefore be printed in the log file by the stderr stream redirection while the valid "dir" will be printed by the stdout. This is exactly what we wanted in this guide!

The call to EndRedirect will "switch off" the log file output and redirect stdout and stderr back to printing on the console screen.

 

By using the class to hide the implementation of the redirection, it is possible to keep a clean and simple code that focus on the main tasks. Next we investigate the SimpleRedirect class.

// Main.cpp
// Copyright (c) Sommergyll Software 2007-2010
//
#include <tchar.h>
#include <string>
#include <iostream>
#include "SimpleRedirect.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{  
    const string KFileLocation = "C:\\Temp\\output.txt";                

    // initialize
    SimpleRedirect* redirect = SimpleRedirect::New();
    if (redirect != NULL)
    {
        // change output destination to the log file
        redirect->StartRedirect(KFileLocation);

        // write some text to the log file
        system("dir");                
        // and a dummy call using the stderr
        system("silly");  

        // change output destination back to the console
        redirect->EndRedirect();

        // valid system call is displayed on console
        system("echo to console");
        // and so is this dummy system call
        system("no-good");
         
        delete redirect;        
    }

    return 0;
}

The SimpleRedirect Class Header

Below is the header file with the class declaration. We have implemented this class as a singleton, as there is only one stdout and stderr. That way, it is harder to make mistakes and easier to avoid bugs. This is the reason for declaring the copy constructor, copy assignment and default constructor as private.

// SimpleRedirect.h
// Copyright (c) Sommergyll Software 2007-2010
//
#pragma once

#include <string>
#include <io.h>

using namespace std;

// Redirection of stdout and stderr
// to a file and retrieving of
// the content from the file
class SimpleRedirect
{
public:    
    static SimpleRedirect* New();
    ~SimpleRedirect(void);

    bool StartRedirect(string aFileName);
    void EndRedirect(void);    

private: // not implemented
    SimpleRedirect(void);  
    SimpleRedirect(const SimpleRedirect&);
    SimpleRedirect& operator=(const SimpleRedirect&);

private:
    int iOldStdout;
    int iOldStderr;
    bool iIsRedirecting;
    FILE* iFile;    
    static SimpleRedirect* iInstance;
};

The Source Code

Finally, we have listed the source code for SimpleRedirect. Please read the inline comments for information about the code. Notice how we have used the C runtime to implement the behaviour.

// SimpleRedirect.cpp
// Copyright (c) Sommergyll Software 2007-2010
//
#include "SimpleRedirect.h"

// Initialise the static pointer
SimpleRedirect* SimpleRedirect::iInstance = NULL;

// Creates the single object
// @return A pointer to the only object
SimpleRedirect* SimpleRedirect::New()
{    
    if (iInstance == NULL)
    {
        iInstance = new SimpleRedirect();
    }
    return iInstance;
}

SimpleRedirect::SimpleRedirect(void)
: iOldStdout(0), iOldStderr(0), 
  iIsRedirecting(false), iFile(NULL)  
{
}

SimpleRedirect::~SimpleRedirect(void)
{
    EndRedirect();       
}

// Redirect both stdout and stderr
// @param aFileName The file to write output to
// @return true if successful
bool SimpleRedirect::StartRedirect(string aFileName)
{
    bool result = false;
    
    if (iIsRedirecting)
    {
        EndRedirect();
    }
    
    // open file for sharing and writing
    iFile = _fsopen(aFileName.c_str(), "w+", SH_DENYNO);    
    if (iFile != NULL)
    {            
        // copy the current stdout stream
        iOldStdout = _dup(1); 
        // copy the current stderr stream
        iOldStderr = _dup(2); 
        // redirect stdout and stderr to file
        if (!_dup2(_fileno(iFile), 1) && !_dup2(_fileno(iFile), 2))
        {
            iIsRedirecting = true;
            result = true;    
        }
    }

    return result;
}

// Redirect back to original 
// stdout and stderr. Will do nothing
// if not currently redirecting
void SimpleRedirect::EndRedirect()
{
    if (iIsRedirecting)
    {
        // redirect back to the old values
        _dup2(iOldStdout, 1);        
        _dup2(iOldStderr, 2);
                
        fclose(iFile);  
        iIsRedirecting = false;
    }
}

 

 

Front Page | Disclaimer

© Copyright 2003-2010 Sommergyll Software. All Rights Reserved.

Programming the standard streams for output and error output