Refactored a lot of code from headers into impl headers only compiled into one TU
- also added noimpl option to single header script - which only generates the non impl code
diff --git a/include/catch.hpp b/include/catch.hpp
index 600815f..28e7f9b 100644
--- a/include/catch.hpp
+++ b/include/catch.hpp
@@ -21,7 +21,7 @@
 #include "internal/catch_context.h"
 #include "internal/catch_test_registry.hpp"
 #include "internal/catch_capture.hpp"
-#include "internal/catch_section.hpp"
+#include "internal/catch_section.h"
 #include "internal/catch_generators.hpp"
 #include "internal/catch_interfaces_exception.h"
 #include "internal/catch_approx.hpp"
@@ -39,11 +39,11 @@
 
 #if defined( CATCH_CONFIG_MAIN ) || defined( CATCH_CONFIG_RUNNER )
 #include "internal/catch_impl.hpp"
-#endif
+#endif // CATCH_CONFIG_MAIN || CATCH_CONFIG_RUNNER
 
 #ifdef CATCH_CONFIG_MAIN
 #include "internal/catch_default_main.hpp"
-#endif
+#endif // CATCH_CONFIG_MAIN
 
 //////
 
diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp
index 849dee9..a352a62 100644
--- a/include/internal/catch_capture.hpp
+++ b/include/internal/catch_capture.hpp
@@ -12,11 +12,12 @@
 #include "catch_expressionresult_builder.h"
 #include "catch_message.h"
 #include "catch_interfaces_capture.h"
-#include "catch_debugger.hpp"
+#include "catch_debugger.h"
 #include "catch_context.h"
 #include "catch_common.h"
 #include "catch_tostring.hpp"
 #include "catch_interfaces_registry_hub.h"
+#include "catch_interfaces_config.h"
 #include "internal/catch_compiler_capabilities.h"
 
 #include <ostream>
@@ -66,7 +67,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_ACCEPT_EXPR( evaluatedExpr, resultDisposition, originalExpr ) \
     if( Catch::ResultAction::Value internal_catch_action = Catch::getResultCapture().acceptExpression( evaluatedExpr, INTERNAL_CATCH_ASSERTIONINFO_NAME )  ) { \
-        if( internal_catch_action & Catch::ResultAction::Debug ) BreakIntoDebugger(); \
+        if( internal_catch_action & Catch::ResultAction::Debug ) CATCH_BREAK_INTO_DEBUGGER(); \
         if( internal_catch_action & Catch::ResultAction::Abort ) throw Catch::TestFailureException(); \
         if( !Catch::shouldContinueOnFailure( resultDisposition ) ) throw Catch::TestFailureException(); \
         Catch::isTrue( false && originalExpr ); \
diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h
index 7759987..650e1fb 100644
--- a/include/internal/catch_common.h
+++ b/include/internal/catch_common.h
@@ -67,36 +67,17 @@
         std::for_each( container.begin(), container.end(), function );
     }
 
-    inline bool startsWith( std::string const& s, std::string const& prefix ) {
-        return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
-    }
-    inline bool endsWith( std::string const& s, std::string const& suffix ) {
-        return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
-    }
-    inline bool contains( std::string const& s, std::string const& infix ) {
-        return s.find( infix ) != std::string::npos;
-    }
-    inline void toLowerInPlace( std::string& s ) {
-        std::transform( s.begin(), s.end(), s.begin(), ::tolower );
-    }
-    inline std::string toLower( std::string const& s ) {
-        std::string lc = s;
-        toLowerInPlace( lc );
-        return lc;
-    }
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
 
     struct pluralise {
-        pluralise( std::size_t count, std::string const& label )
-        :   m_count( count ),
-            m_label( label )
-        {}
+        pluralise( std::size_t count, std::string const& label );
 
-        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
-            os << pluraliser.m_count << " " << pluraliser.m_label;
-            if( pluraliser.m_count != 1 )
-                os << "s";
-            return os;
-        }
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
 
         std::size_t m_count;
         std::string m_label;
@@ -104,43 +85,22 @@
 
     struct SourceLineInfo {
 
-        SourceLineInfo() : line( 0 ){}
-        SourceLineInfo( std::string const& _file, std::size_t _line )
-        :   file( _file ),
-            line( _line )
-        {}
-        SourceLineInfo( SourceLineInfo const& other )
-        :   file( other.file ),
-            line( other.line )
-        {}
-        bool empty() const {
-            return file.empty();
-        }
-        bool operator == ( SourceLineInfo const& other ) const {
-            return line == other.line && file == other.file;
-        }
+        SourceLineInfo();
+        SourceLineInfo( std::string const& _file, std::size_t _line );
+        SourceLineInfo( SourceLineInfo const& other );
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+
         std::string file;
         std::size_t line;
     };
 
-    inline std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
-#ifndef __GNUG__
-        os << info.file << "(" << info.line << ")";
-#else
-        os << info.file << ":" << info.line;
-#endif
-        return os;
-    }
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
 
     // This is just here to avoid compiler warnings with macro constants and boolean literals
     inline bool isTrue( bool value ){ return value; }
 
-    inline void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
-        std::ostringstream oss;
-        oss << locationInfo << ": Internal Catch error: '" << message << "'";
-        if( isTrue( true ))
-            throw std::logic_error( oss.str() );
-    }
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
 }
 
 #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
diff --git a/include/internal/catch_common.hpp b/include/internal/catch_common.hpp
new file mode 100644
index 0000000..4fbf1ff
--- /dev/null
+++ b/include/internal/catch_common.hpp
@@ -0,0 +1,86 @@
+/*
+ *  Created by Phil on 27/11/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+#include "catch_common.h"
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), ::tolower );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << " " << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << "s";
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : line( 0 ){}
+    SourceLineInfo::SourceLineInfo( std::string const& _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
+    :   file( other.file ),
+        line( other.line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file.empty();
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && file == other.file;
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << "(" << info.line << ")";
+#else
+        os << info.file << ":" << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << "'";
+        if( isTrue( true ))
+            throw std::logic_error( oss.str() );
+    }
+}
+
+#endif // TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index 51b5913..30cd34b 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -11,7 +11,7 @@
 #include "catch_test_spec.h"
 #include "catch_context.h"
 #include "catch_interfaces_config.h"
-#include "catch_stream.hpp"
+#include "catch_stream.h"
 
 #include <memory>
 #include <vector>
diff --git a/include/internal/catch_debugger.h b/include/internal/catch_debugger.h
new file mode 100644
index 0000000..0fb6621
--- /dev/null
+++ b/include/internal/catch_debugger.h
@@ -0,0 +1,49 @@
+/*
+ *  Created by Phil on 3/12/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+#ifndef TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+#include "catch_platform.h"
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #ifdef DEBUG
+        #if defined(__ppc64__) || defined(__ppc__)
+            #define CATCH_BREAK_INTO_DEBUGGER() \
+                if( Catch::isDebuggerActive() ) { \
+                    __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                    : : : "memory","r0","r3","r4" ); \
+                }
+        #else
+            #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
+        #endif
+    #endif
+
+#elif defined(_MSC_VER)
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER()
+#endif
+
+#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
diff --git a/include/internal/catch_debugger.hpp b/include/internal/catch_debugger.hpp
index 9979dff..f3ad100 100644
--- a/include/internal/catch_debugger.hpp
+++ b/include/internal/catch_debugger.hpp
@@ -5,14 +5,13 @@
  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  *
- * Provides a BreakIntoDebugger() macro for Windows and Mac (so far)
  */
 #ifndef TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
 
-#include <iostream>
+#include "catch_debugger.h"
 
-#include "catch_platform.h"
+#include <iostream>
 
 #ifdef CATCH_PLATFORM_MAC
 
@@ -29,7 +28,7 @@
 
         // Returns true if the current process is being debugged (either
         // running under the debugger or has a debugger attached post facto).
-        inline bool isDebuggerActive(){
+        bool isDebuggerActive(){
 
             int                 junk;
             int                 mib[4];
@@ -59,52 +58,42 @@
 
             return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
         }
-    }
-
-    // The following code snippet taken from:
-    // http://cocoawithlove.com/2008/03/break-into-debugger.html
-    #ifdef DEBUG
-        #if defined(__ppc64__) || defined(__ppc__)
-            #define BreakIntoDebugger() \
-            if( Catch::isDebuggerActive() ) { \
-            __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
-            : : : "memory","r0","r3","r4" ); \
-            }
-        #else
-            #define BreakIntoDebugger() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
-        #endif
-    #else
-        inline void BreakIntoDebugger(){}
-    #endif
+    } // namespace Catch
 
 #elif defined(_MSC_VER)
     extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
-    #define BreakIntoDebugger() if (IsDebuggerPresent() ) { __debugbreak(); }
-    inline bool isDebuggerActive() {
-        return IsDebuggerPresent() != 0;
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
     }
 #elif defined(__MINGW32__)
     extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
-    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
-    #define BreakIntoDebugger() if (IsDebuggerPresent() ) { DebugBreak(); }
-    inline bool isDebuggerActive() {
-        return IsDebuggerPresent() != 0;
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
     }
 #else
-       inline void BreakIntoDebugger(){}
+    namespace Catch {
        inline bool isDebuggerActive() { return false; }
-#endif
+    }
+#endif // Platform
 
 #ifdef CATCH_PLATFORM_WINDOWS
-extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
-inline void writeToDebugConsole( std::string const& text ) {
-    ::OutputDebugStringA( text.c_str() );
-}
+    extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
 #else
-inline void writeToDebugConsole( std::string const& text ) {
-    // !TBD: Need a version for Mac/ XCode and other IDEs
-    std::cout << text;
-}
-#endif // CATCH_PLATFORM_WINDOWS
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            std::cout << text;
+        }
+    }
+#endif // Platform
 
 #endif // TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp
index 30ac219..0152235 100644
--- a/include/internal/catch_impl.hpp
+++ b/include/internal/catch_impl.hpp
@@ -26,11 +26,15 @@
 #include "catch_expressionresult_builder.hpp"
 #include "catch_test_case_info.hpp"
 #include "catch_tags.hpp"
+#include "catch_test_spec.hpp"
 #include "catch_version.hpp"
 #include "catch_text.hpp"
 #include "catch_message.hpp"
 #include "catch_legacy_reporter_adapter.hpp"
 #include "catch_timer.hpp"
+#include "catch_common.hpp"
+#include "catch_section.hpp"
+#include "catch_debugger.hpp"
 
 #include "../reporters/catch_reporter_xml.hpp"
 #include "../reporters/catch_reporter_junit.hpp"
@@ -71,9 +75,6 @@
     FreeFunctionTestCase::~FreeFunctionTestCase() {}
     IGeneratorInfo::~IGeneratorInfo() {}
     IGeneratorsForTest::~IGeneratorsForTest() {}
-    TagParser::~TagParser() {}
-    TagExtracter::~TagExtracter() {}
-    TagExpressionParser::~TagExpressionParser() {}
 
     Matchers::Impl::StdString::Equals::~Equals() {}
     Matchers::Impl::StdString::Contains::~Contains() {}
diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h
index 2601ab4..de779e0 100644
--- a/include/internal/catch_interfaces_capture.h
+++ b/include/internal/catch_interfaces_capture.h
@@ -10,7 +10,6 @@
 
 #include <string>
 #include "catch_result_type.h"
-#include "catch_totals.hpp"
 #include "catch_common.h"
 
 namespace Catch {
@@ -22,6 +21,7 @@
     struct SectionInfo;
     struct MessageInfo;
     class ScopedMessageBuilder;
+    struct Counts;
 
     struct IResultCapture {
 
diff --git a/include/internal/catch_interfaces_registry_hub.h b/include/internal/catch_interfaces_registry_hub.h
index 7fae3ab..b657183 100644
--- a/include/internal/catch_interfaces_registry_hub.h
+++ b/include/internal/catch_interfaces_registry_hub.h
@@ -8,10 +8,7 @@
 #ifndef TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
 #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
 
-#include "catch_interfaces_reporter.h"
-#include "catch_interfaces_config.h"
-
-#include <vector>
+#include <string>
 
 namespace Catch {
 
@@ -19,6 +16,8 @@
     struct ITestCaseRegistry;
     struct IExceptionTranslatorRegistry;
     struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
 
     struct IRegistryHub {
         virtual ~IRegistryHub();
diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h
index 1de4778..eafaaa3 100644
--- a/include/internal/catch_interfaces_reporter.h
+++ b/include/internal/catch_interfaces_reporter.h
@@ -8,6 +8,7 @@
 #ifndef TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
 #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
 
+#include "catch_section_info.h"
 #include "catch_common.h"
 #include "catch_totals.hpp"
 #include "catch_ptr.hpp"
@@ -80,20 +81,6 @@
         std::size_t groupsCounts;
     };
 
-    struct SectionInfo {
-        SectionInfo(    std::string const& _name,
-                        std::string const& _description,
-                        SourceLineInfo const& _lineInfo )
-        :   name( _name ),
-            description( _description ),
-            lineInfo( _lineInfo )
-        {}
-
-        std::string name;
-        std::string description;
-        SourceLineInfo lineInfo;
-    };
-
     struct AssertionStats {
         AssertionStats( AssertionResult const& _assertionResult,
                         std::vector<MessageInfo> const& _infoMessages,
@@ -223,201 +210,6 @@
         virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
     };
 
-    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
-
-        StreamingReporterBase( ReporterConfig const& _config )
-        :   m_config( _config.fullConfig() ),
-            stream( _config.stream() )
-        {}
-
-        virtual ~StreamingReporterBase();
-
-        virtual void noMatchingTestCases( std::string const& ) {}
-
-        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
-            currentTestRunInfo = _testRunInfo;
-        }
-        virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
-            currentGroupInfo = _groupInfo;
-        }
-
-        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
-            currentTestCaseInfo = _testInfo;
-        }
-        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
-            m_sectionStack.push_back( _sectionInfo );
-        }
-
-        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
-            m_sectionStack.pop_back();
-        }
-        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
-            currentTestCaseInfo.reset();
-            assert( m_sectionStack.empty() );
-        }
-        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
-            currentGroupInfo.reset();
-        }
-        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
-            currentTestCaseInfo.reset();
-            currentGroupInfo.reset();
-            currentTestRunInfo.reset();
-        }
-
-        Ptr<IConfig> m_config;
-        std::ostream& stream;
-
-        LazyStat<TestRunInfo> currentTestRunInfo;
-        LazyStat<GroupInfo> currentGroupInfo;
-        LazyStat<TestCaseInfo> currentTestCaseInfo;
-
-        std::vector<SectionInfo> m_sectionStack;
-    };
-
-    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
-        template<typename T, typename ChildNodeT>
-        struct Node : SharedImpl<> {
-            explicit Node( T const& _value ) : value( _value ) {}
-            virtual ~Node() {}
-
-            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
-            T value;
-            ChildNodes children;
-        };
-        struct SectionNode : SharedImpl<> {
-            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
-            virtual ~SectionNode();
-
-            bool operator == ( SectionNode const& other ) const {
-                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
-            }
-            bool operator == ( Ptr<SectionNode> const& other ) const {
-                return operator==( *other );
-            }
-
-            SectionStats stats;
-            typedef std::vector<Ptr<SectionNode> > ChildSections;
-            typedef std::vector<AssertionStats> Assertions;
-            ChildSections childSections;
-            Assertions assertions;
-            std::string stdOut;
-            std::string stdErr;
-        };
-        friend bool operator == ( Ptr<SectionNode> const& node, SectionInfo const& other ) {
-            return node->stats.sectionInfo.lineInfo == other.lineInfo;
-        }
-
-        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
-        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
-        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
-
-        CumulativeReporterBase( ReporterConfig const& _config )
-        :   m_config( _config.fullConfig() ),
-            stream( _config.stream() )
-        {}
-        ~CumulativeReporterBase();
-
-        virtual void testRunStarting( TestRunInfo const& ) {}
-        virtual void testGroupStarting( GroupInfo const& ) {}
-
-        virtual void testCaseStarting( TestCaseInfo const& ) {}
-
-        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
-            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
-            Ptr<SectionNode> node;
-            if( m_sectionStack.empty() ) {
-                if( !m_rootSection )
-                    m_rootSection = new SectionNode( incompleteStats );
-                node = m_rootSection;
-            }
-            else {
-                SectionNode& parentNode = *m_sectionStack.back();
-                SectionNode::ChildSections::const_iterator it =
-                    std::find( parentNode.childSections.begin(), parentNode.childSections.end(), sectionInfo );
-                if( it == parentNode.childSections.end() ) {
-                    node = new SectionNode( incompleteStats );
-                    parentNode.childSections.push_back( node );
-                }
-                else
-                    node = *it;
-            }
-            m_sectionStack.push_back( node );
-            m_deepestSection = node;
-        }
-
-        virtual void assertionStarting( AssertionInfo const& ) {}
-
-        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
-            assert( !m_sectionStack.empty() );
-            SectionNode& sectionNode = *m_sectionStack.back();
-            sectionNode.assertions.push_back( assertionStats );
-            return true;
-        }
-        virtual void sectionEnded( SectionStats const& sectionStats ) {
-            assert( !m_sectionStack.empty() );
-            SectionNode& node = *m_sectionStack.back();
-            node.stats = sectionStats;
-            m_sectionStack.pop_back();
-        }
-        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
-            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
-            assert( m_sectionStack.size() == 0 );
-            node->children.push_back( m_rootSection );
-            m_testCases.push_back( node );
-            m_rootSection.reset();
-
-            assert( m_deepestSection );
-            m_deepestSection->stdOut = testCaseStats.stdOut;
-            m_deepestSection->stdErr = testCaseStats.stdErr;
-        }
-        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
-            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
-            node->children.swap( m_testCases );
-            m_testGroups.push_back( node );
-        }
-        virtual void testRunEnded( TestRunStats const& testRunStats ) {
-            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
-            node->children.swap( m_testGroups );
-            m_testRuns.push_back( node );
-            testRunEnded();
-        }
-        virtual void testRunEnded() = 0;
-
-        Ptr<IConfig> m_config;
-        std::ostream& stream;
-        std::vector<AssertionStats> m_assertions;
-        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
-        std::vector<Ptr<TestCaseNode> > m_testCases;
-        std::vector<Ptr<TestGroupNode> > m_testGroups;
-
-        std::vector<Ptr<TestRunNode> > m_testRuns;
-
-        Ptr<SectionNode> m_rootSection;
-        Ptr<SectionNode> m_deepestSection;
-        std::vector<Ptr<SectionNode> > m_sectionStack;
-
-    };
-
-    // Deprecated
-    struct IReporter : IShared {
-        virtual ~IReporter();
-
-        virtual bool shouldRedirectStdout() const = 0;
-
-        virtual void StartTesting() = 0;
-        virtual void EndTesting( Totals const& totals ) = 0;
-        virtual void StartGroup( std::string const& groupName ) = 0;
-        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
-        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
-        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
-        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
-        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
-        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
-        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
-        virtual void Aborted() = 0;
-        virtual void Result( AssertionResult const& result ) = 0;
-    };
-
 
     struct IReporterFactory {
         virtual ~IReporterFactory();
@@ -433,13 +225,6 @@
         virtual FactoryMap const& getFactories() const = 0;
     };
 
-    inline std::string trim( std::string const& str ) {
-        static char const* whitespaceChars = "\n\r\t ";
-        std::string::size_type start = str.find_first_not_of( whitespaceChars );
-        std::string::size_type end = str.find_last_not_of( whitespaceChars );
-
-        return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
-    }
 }
 
 #endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
diff --git a/include/internal/catch_interfaces_runner.h b/include/internal/catch_interfaces_runner.h
index ab127b9..6438f20 100644
--- a/include/internal/catch_interfaces_runner.h
+++ b/include/internal/catch_interfaces_runner.h
@@ -8,10 +8,6 @@
 #ifndef TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
 #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
 
-#include "catch_totals.hpp"
-
-#include <string>
-
 namespace Catch {
     class TestCase;
 
diff --git a/include/internal/catch_legacy_reporter_adapter.h b/include/internal/catch_legacy_reporter_adapter.h
index 32d03f1..fb579c7 100644
--- a/include/internal/catch_legacy_reporter_adapter.h
+++ b/include/internal/catch_legacy_reporter_adapter.h
@@ -12,6 +12,26 @@
 
 namespace Catch
 {
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
     class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
     {
     public:
diff --git a/include/internal/catch_list.hpp b/include/internal/catch_list.hpp
index 70d7668..1ee3d1f 100644
--- a/include/internal/catch_list.hpp
+++ b/include/internal/catch_list.hpp
@@ -11,6 +11,7 @@
 #include "catch_commandline.hpp"
 #include "catch_text.h"
 #include "catch_console_colour.hpp"
+#include "catch_interfaces_reporter.h"
 
 #include <limits>
 #include <algorithm>
diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp
index 45d64ba..85181f4 100644
--- a/include/internal/catch_objc.hpp
+++ b/include/internal/catch_objc.hpp
@@ -56,9 +56,6 @@
 
     namespace Detail{
 
-        inline bool startsWith( std::string const& str, std::string const& sub ) {
-            return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
-        }
 
         inline std::string getAnnotation(   Class cls,
                                             std::string const& annotationName,
@@ -88,7 +85,7 @@
                 for( u_int m = 0; m < count ; m++ ) {
                     SEL selector = method_getName(methods[m]);
                     std::string methodName = sel_getName(selector);
-                    if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
                         std::string testCaseName = methodName.substr( 15 );
                         std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
                         std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
diff --git a/include/internal/catch_section.h b/include/internal/catch_section.h
new file mode 100644
index 0000000..c1a81f6
--- /dev/null
+++ b/include/internal/catch_section.h
@@ -0,0 +1,49 @@
+/*
+ *  Created by Phil on 03/12/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+#include "catch_section_info.h"
+#include "catch_totals.hpp"
+#include "catch_timer.h"
+
+#include <string>
+
+namespace Catch {
+
+    class Section {
+    public:
+        Section(    SourceLineInfo const& lineInfo,
+                    std::string const& name,
+                    std::string const& description = "" );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool();
+
+    private:
+
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
diff --git a/include/internal/catch_section.hpp b/include/internal/catch_section.hpp
index e58e72a..96fc832 100644
--- a/include/internal/catch_section.hpp
+++ b/include/internal/catch_section.hpp
@@ -8,53 +8,33 @@
 #ifndef TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
 
+#include "catch_section.h"
 #include "catch_capture.hpp"
-#include "catch_totals.hpp"
 #include "catch_compiler_capabilities.h"
 #include "catch_timer.h"
 
-#include <string>
-
 namespace Catch {
 
-    class Section {
-    public:
-        Section(    SourceLineInfo const& lineInfo,
-                    std::string const& name,
-                    std::string const& description = "" )
-        :   m_info( name, description, lineInfo ),
-            m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
-        {
-            m_timer.start();
-        }
+    Section::Section(   SourceLineInfo const& lineInfo,
+                        std::string const& name,
+                        std::string const& description )
+    :   m_info( name, description, lineInfo ),
+        m_sectionIncluded( getCurrentContext().getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
 
-        ~Section() {
-            if( m_sectionIncluded )
-                getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
-        }
+    Section::~Section() {
+        if( m_sectionIncluded )
+            getCurrentContext().getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
+    }
 
-        // This indicates whether the section should be executed or not
-        operator bool() {
-            return m_sectionIncluded;
-        }
+    // This indicates whether the section should be executed or not
+    Section::operator bool() {
+        return m_sectionIncluded;
+    }
 
-    private:
-        SectionInfo m_info;
-
-        std::string m_name;
-        Counts m_assertions;
-        bool m_sectionIncluded;
-        Timer m_timer;
-    };
 
 } // end namespace Catch
 
-#ifdef CATCH_CONFIG_VARIADIC_MACROS
-    #define INTERNAL_CATCH_SECTION( ... ) \
-        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
-#else
-    #define INTERNAL_CATCH_SECTION( name, desc ) \
-        if( Catch::Section INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, name, desc ) )
-#endif
-
 #endif // TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
diff --git a/include/internal/catch_section_info.h b/include/internal/catch_section_info.h
new file mode 100644
index 0000000..6bcc72a
--- /dev/null
+++ b/include/internal/catch_section_info.h
@@ -0,0 +1,31 @@
+/*
+ *  Created by Phil on 03/11/2010.
+ *  Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+#include "catch_common.h"
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo(    std::string const& _name,
+                        std::string const& _description,
+                        SourceLineInfo const& _lineInfo )
+        :   name( _name ),
+            description( _description ),
+            lineInfo( _lineInfo )
+        {}
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h
new file mode 100644
index 0000000..70ddb58
--- /dev/null
+++ b/include/internal/catch_stream.h
@@ -0,0 +1,33 @@
+/*
+ *  Created by Phil on 2/12/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+#include <streambuf>
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    class Stream {
+    public:
+        Stream();
+        Stream( std::streambuf* _streamBuf, bool _isOwned );
+        void release();
+
+        std::streambuf* streamBuf;
+
+    private:
+        bool isOwned;
+    };
+}
+
+#endif // TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
diff --git a/include/internal/catch_stream.hpp b/include/internal/catch_stream.hpp
index eea576e..784ef86 100644
--- a/include/internal/catch_stream.hpp
+++ b/include/internal/catch_stream.hpp
@@ -9,8 +9,9 @@
 #ifndef TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
 
+#include "catch_stream.h"
 #include "catch_streambuf.h"
-#include "catch_debugger.hpp"
+#include "catch_debugger.h"
 
 #include <stdexcept>
 #include <cstdio>
@@ -62,29 +63,21 @@
         }
     };
 
-    class Stream {
-    public:
-        Stream()
-        : streamBuf( NULL ), isOwned( false )
-        {}
+    Stream::Stream()
+    : streamBuf( NULL ), isOwned( false )
+    {}
 
-        Stream( std::streambuf* _streamBuf, bool _isOwned )
-        : streamBuf( _streamBuf ), isOwned( _isOwned )
-        {}
+    Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
+    : streamBuf( _streamBuf ), isOwned( _isOwned )
+    {}
 
-        void release() {
-            if( isOwned ) {
-                delete streamBuf;
-                streamBuf = NULL;
-                isOwned = false;
-            }
+    void Stream::release() {
+        if( isOwned ) {
+            delete streamBuf;
+            streamBuf = NULL;
+            isOwned = false;
         }
-
-        std::streambuf* streamBuf;
-
-    private:
-        bool isOwned;
-    };
+    }
 }
 
 #endif // TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
diff --git a/include/internal/catch_tags.h b/include/internal/catch_tags.h
new file mode 100644
index 0000000..8fd20b7
--- /dev/null
+++ b/include/internal/catch_tags.h
@@ -0,0 +1,109 @@
+/*
+ *  Created by Phil on 2/12/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_TAGS_H_INCLUDED
+#define TWOBLUECUBES_CATCH_TAGS_H_INCLUDED
+
+#include "catch_common.h"
+
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+    class TagParser {
+    public:
+        virtual ~TagParser();
+
+        void parse( std::string const& str );
+
+    protected:
+        virtual void acceptTag( std::string const& tag ) = 0;
+        virtual void acceptChar( char c ) = 0;
+        virtual void endParse() {}
+
+    private:
+    };
+
+    class TagExtracter : public TagParser {
+    public:
+
+        TagExtracter( std::set<std::string>& tags );
+        virtual ~TagExtracter();
+
+        void parse( std::string& description );
+
+    private:
+        virtual void acceptTag( std::string const& tag );
+        virtual void acceptChar( char c );
+
+        TagExtracter& operator=(TagExtracter const&);
+
+        std::set<std::string>& m_tags;
+        std::string m_remainder;
+    };
+
+    class Tag {
+    public:
+        Tag();
+        Tag( std::string const& name, bool isNegated );
+        std::string getName() const;
+        bool isNegated() const;
+        bool operator ! () const;
+
+    private:
+        std::string m_name;
+        bool m_isNegated;
+    };
+
+    class TagSet {
+        typedef std::map<std::string, Tag> TagMap;
+    public:
+        void add( Tag const& tag );
+        bool empty() const;
+        bool matches( std::set<std::string> const& tags ) const;
+
+    private:
+        TagMap m_tags;
+    };
+
+
+    class TagExpression {
+    public:
+        bool matches( std::set<std::string> const& tags ) const;
+
+    private:
+        friend class TagExpressionParser;
+
+        std::vector<TagSet> m_tagSets;
+    };
+
+    class TagExpressionParser : public TagParser {
+    public:
+        TagExpressionParser( TagExpression& exp );
+        ~TagExpressionParser();
+
+    private:
+        virtual void acceptTag( std::string const& tag );
+        virtual void acceptChar( char c );
+        virtual void endParse();
+
+        TagExpressionParser& operator=(TagExpressionParser const&);
+
+        bool m_isNegated;
+        TagSet m_currentTagSet;
+        TagExpression& m_exp;
+    };
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
diff --git a/include/internal/catch_tags.hpp b/include/internal/catch_tags.hpp
index 36ecd1d..d02ed8d 100644
--- a/include/internal/catch_tags.hpp
+++ b/include/internal/catch_tags.hpp
@@ -8,188 +8,129 @@
 #ifndef TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_TAGS_HPP_INCLUDED
 
-#include "catch_common.h"
-
-#include <string>
-#include <set>
-#include <map>
-#include <vector>
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wpadded"
-#endif
+#include "catch_tags.h"
 
 namespace Catch {
-    class TagParser {
-    public:
-        virtual ~TagParser();
+    TagParser::~TagParser() {}
 
-        void parse( std::string const& str ) {
-            std::size_t pos = 0;
-            while( pos < str.size() ) {
-                char c = str[pos];
-                if( c == '[' ) {
-                    std::size_t end = str.find_first_of( ']', pos );
-                    if( end != std::string::npos ) {
-                        acceptTag( str.substr( pos+1, end-pos-1 ) );
-                        pos = end+1;
-                    }
-                    else {
-                        acceptChar( c );
-                        pos++;
-                    }
+    void TagParser::parse( std::string const& str ) {
+        std::size_t pos = 0;
+        while( pos < str.size() ) {
+            char c = str[pos];
+            if( c == '[' ) {
+                std::size_t end = str.find_first_of( ']', pos );
+                if( end != std::string::npos ) {
+                    acceptTag( str.substr( pos+1, end-pos-1 ) );
+                    pos = end+1;
                 }
                 else {
                     acceptChar( c );
                     pos++;
                 }
             }
-            endParse();
-        }
-
-    protected:
-        virtual void acceptTag( std::string const& tag ) = 0;
-        virtual void acceptChar( char c ) = 0;
-        virtual void endParse() {}
-
-    private:
-    };
-
-    class TagExtracter : public TagParser {
-    public:
-
-        TagExtracter( std::set<std::string>& tags )
-        :   m_tags( tags )
-        {}
-        virtual ~TagExtracter();
-
-        void parse( std::string& description ) {
-            TagParser::parse( description );
-            description = m_remainder;
-        }
-
-    private:
-        virtual void acceptTag( std::string const& tag ) {
-            m_tags.insert( toLower( tag ) );
-        }
-        virtual void acceptChar( char c ) {
-            m_remainder += c;
-        }
-
-        TagExtracter& operator=(TagExtracter const&);
-
-        std::set<std::string>& m_tags;
-        std::string m_remainder;
-    };
-
-    class Tag {
-    public:
-        Tag()
-        :   m_isNegated( false )
-        {}
-
-        Tag( std::string const& name, bool isNegated )
-        :   m_name( name ),
-            m_isNegated( isNegated )
-        {}
-
-        std::string getName() const {
-            return m_name;
-        }
-        bool isNegated() const {
-            return m_isNegated;
-        }
-
-        bool operator ! () const {
-            return m_name.empty();
-        }
-
-    private:
-        std::string m_name;
-        bool m_isNegated;
-    };
-
-    class TagSet {
-        typedef std::map<std::string, Tag> TagMap;
-    public:
-        void add( Tag const& tag ) {
-            m_tags.insert( std::make_pair( toLower( tag.getName() ), tag ) );
-        }
-
-        bool empty() const {
-            return m_tags.empty();
-        }
-
-        bool matches( std::set<std::string> const& tags ) const {
-            for(    TagMap::const_iterator
-                        it = m_tags.begin(), itEnd = m_tags.end();
-                    it != itEnd;
-                    ++it ) {
-                bool found = tags.find( it->first ) != tags.end();
-                if( found == it->second.isNegated() )
-                    return false;
-            }
-            return true;
-        }
-
-    private:
-        TagMap m_tags;
-    };
-
-    class TagExpression {
-    public:
-        bool matches( std::set<std::string> const& tags ) const {
-            for(    std::vector<TagSet>::const_iterator
-                        it = m_tagSets.begin(), itEnd = m_tagSets.end();
-                    it != itEnd;
-                    ++it )
-                if( it->matches( tags ) )
-                    return true;
-            return false;
-        }
-
-    private:
-        friend class TagExpressionParser;
-
-        std::vector<TagSet> m_tagSets;
-    };
-
-    class TagExpressionParser : public TagParser {
-    public:
-        TagExpressionParser( TagExpression& exp )
-        :   m_isNegated( false ),
-            m_exp( exp )
-        {}
-
-        ~TagExpressionParser();
-
-    private:
-        virtual void acceptTag( std::string const& tag ) {
-            m_currentTagSet.add( Tag( tag, m_isNegated ) );
-            m_isNegated = false;
-        }
-        virtual void acceptChar( char c ) {
-            switch( c ) {
-                case '~':
-                    m_isNegated = true;
-                    break;
-                case ',':
-                    m_exp.m_tagSets.push_back( m_currentTagSet );
-                    m_currentTagSet = TagSet();
-                    break;
+            else {
+                acceptChar( c );
+                pos++;
             }
         }
-        virtual void endParse() {
-            if( !m_currentTagSet.empty() )
+        endParse();
+    }
+
+    TagExtracter::TagExtracter( std::set<std::string>& tags )
+    :   m_tags( tags )
+    {}
+
+    TagExtracter::~TagExtracter() {}
+
+    void TagExtracter::parse( std::string& description ) {
+        TagParser::parse( description );
+        description = m_remainder;
+    }
+
+    void TagExtracter::acceptTag( std::string const& tag ) {
+        m_tags.insert( toLower( tag ) );
+    }
+    void TagExtracter::acceptChar( char c ) {
+        m_remainder += c;
+    }
+
+    Tag::Tag() : m_isNegated( false ) {}
+    Tag::Tag( std::string const& name, bool isNegated )
+    :   m_name( name ),
+        m_isNegated( isNegated )
+    {}
+
+    std::string Tag::getName() const {
+        return m_name;
+    }
+    bool Tag::isNegated() const {
+        return m_isNegated;
+    }
+
+    bool Tag::operator ! () const {
+        return m_name.empty();
+    }
+
+
+    void TagSet::add( Tag const& tag ) {
+        m_tags.insert( std::make_pair( toLower( tag.getName() ), tag ) );
+    }
+
+    bool TagSet::empty() const {
+        return m_tags.empty();
+    }
+
+    bool TagSet::matches( std::set<std::string> const& tags ) const {
+        for(    TagMap::const_iterator
+                    it = m_tags.begin(), itEnd = m_tags.end();
+                it != itEnd;
+                ++it ) {
+            bool found = tags.find( it->first ) != tags.end();
+            if( found == it->second.isNegated() )
+                return false;
+        }
+        return true;
+    }
+
+
+    bool TagExpression::matches( std::set<std::string> const& tags ) const {
+        for(    std::vector<TagSet>::const_iterator
+                    it = m_tagSets.begin(), itEnd = m_tagSets.end();
+                it != itEnd;
+                ++it )
+            if( it->matches( tags ) )
+                return true;
+        return false;
+    }
+
+    TagExpressionParser::TagExpressionParser( TagExpression& exp )
+    :   m_isNegated( false ),
+        m_exp( exp )
+    {}
+
+    TagExpressionParser::~TagExpressionParser() {}
+
+    void TagExpressionParser::acceptTag( std::string const& tag ) {
+        m_currentTagSet.add( Tag( tag, m_isNegated ) );
+        m_isNegated = false;
+    }
+
+    void TagExpressionParser::acceptChar( char c ) {
+        switch( c ) {
+            case '~':
+                m_isNegated = true;
+                break;
+            case ',':
                 m_exp.m_tagSets.push_back( m_currentTagSet );
+                m_currentTagSet = TagSet();
+                break;
         }
+    }
 
-        TagExpressionParser& operator=(TagExpressionParser const&);
-
-        bool m_isNegated;
-        TagSet m_currentTagSet;
-        TagExpression& m_exp;
-    };
+    void TagExpressionParser::endParse() {
+        if( !m_currentTagSet.empty() )
+            m_exp.m_tagSets.push_back( m_currentTagSet );
+    }
 
 } // end namespace Catch
 
diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp
index 59fc39f..3d46320 100644
--- a/include/internal/catch_test_case_info.hpp
+++ b/include/internal/catch_test_case_info.hpp
@@ -8,7 +8,7 @@
 #ifndef TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
 
-#include "catch_tags.hpp"
+#include "catch_tags.h"
 #include "catch_test_case_info.h"
 #include "catch_interfaces_testcase.h"
 #include "catch_common.h"
diff --git a/include/internal/catch_test_spec.h b/include/internal/catch_test_spec.h
index 05f877c..758f49e 100644
--- a/include/internal/catch_test_spec.h
+++ b/include/internal/catch_test_spec.h
@@ -8,15 +8,15 @@
 #ifndef TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED
 #define TWOBLUECUBES_CATCH_TEST_SPEC_H_INCLUDED
 
-#include "catch_test_case_info.h"
-#include "catch_tags.hpp"
-#include "catch_common.h"
+#include "catch_tags.h"
 
 #include <string>
 #include <vector>
 
 namespace Catch {
 
+    class TestCase;
+
     struct IfFilterMatches{ enum DoWhat {
         AutoDetectBehaviour,
         IncludeTests,
@@ -32,69 +32,13 @@
         };
 
     public:
-        TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour )
-        :   m_stringToMatch( toLower( testSpec ) ),
-            m_filterType( matchBehaviour ),
-            m_wildcardPosition( NoWildcard )
-        {
-            if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
-                if( startsWith( m_stringToMatch, "exclude:" ) ) {
-                    m_stringToMatch = m_stringToMatch.substr( 8 );
-                    m_filterType = IfFilterMatches::ExcludeTests;
-                }
-                else if( startsWith( m_stringToMatch, "~" ) ) {
-                    m_stringToMatch = m_stringToMatch.substr( 1 );
-                    m_filterType = IfFilterMatches::ExcludeTests;
-                }
-                else {
-                    m_filterType = IfFilterMatches::IncludeTests;
-                }
-            }
+        TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour = IfFilterMatches::AutoDetectBehaviour );
 
-            if( startsWith( m_stringToMatch, "*" ) ) {
-                m_stringToMatch = m_stringToMatch.substr( 1 );
-                m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
-            }
-            if( endsWith( m_stringToMatch, "*" ) ) {
-                m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
-                m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
-            }
-        }
+        IfFilterMatches::DoWhat getFilterType() const;
+        bool shouldInclude( TestCase const& testCase ) const;
 
-        IfFilterMatches::DoWhat getFilterType() const {
-            return m_filterType;
-        }
-
-        bool shouldInclude( TestCase const& testCase ) const {
-            return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
-        }
     private:
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
-#endif
-
-        bool isMatch( TestCase const& testCase ) const {
-            std::string name = testCase.getTestCaseInfo().name;
-            toLowerInPlace( name );
-
-            switch( m_wildcardPosition ) {
-                case NoWildcard:
-                    return m_stringToMatch == name;
-                case WildcardAtStart:
-                    return endsWith( name, m_stringToMatch );
-                case WildcardAtEnd:
-                    return startsWith( name, m_stringToMatch );
-                case WildcardAtBothEnds:
-                    return contains( name, m_stringToMatch );
-            }
-            throw std::logic_error( "Unhandled wildcard type" );
-        }
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
+        bool isMatch( TestCase const& testCase ) const;
 
         std::string m_stringToMatch;
         IfFilterMatches::DoWhat m_filterType;
@@ -103,57 +47,12 @@
 
     class TestCaseFilters {
     public:
-        TestCaseFilters( std::string const& name ) : m_name( name ) {}
+        TestCaseFilters( std::string const& name );
+        std::string getName() const;
+        void addFilter( TestCaseFilter const& filter );
+        void addTags( std::string const& tagPattern );
+        bool shouldInclude( TestCase const& testCase ) const;
 
-        std::string getName() const {
-            return m_name;
-        }
-
-        void addFilter( TestCaseFilter const& filter ) {
-            if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
-                m_exclusionFilters.push_back( filter );
-            else
-                m_inclusionFilters.push_back( filter );
-        }
-
-        void addTags( std::string const& tagPattern ) {
-            TagExpression exp;
-            TagExpressionParser( exp ).parse( tagPattern );
-
-            m_tagExpressions.push_back( exp );
-        }
-
-        bool shouldInclude( TestCase const& testCase ) const {
-            if( !m_tagExpressions.empty() ) {
-                std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
-                std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
-                for(; it != itEnd; ++it )
-                    if( it->matches( testCase.getTags() ) )
-                        break;
-                if( it == itEnd )
-                    return false;
-            }
-
-            if( !m_inclusionFilters.empty() ) {
-                std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
-                std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
-                for(; it != itEnd; ++it )
-                    if( it->shouldInclude( testCase ) )
-                        break;
-                if( it == itEnd )
-                    return false;
-            }
-            else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
-                return !testCase.isHidden();
-            }
-
-            std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
-            std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
-            for(; it != itEnd; ++it )
-                if( !it->shouldInclude( testCase ) )
-                    return false;
-            return true;
-        }
     private:
         std::vector<TagExpression> m_tagExpressions;
         std::vector<TestCaseFilter> m_inclusionFilters;
diff --git a/include/internal/catch_test_spec.hpp b/include/internal/catch_test_spec.hpp
new file mode 100644
index 0000000..6df01bc
--- /dev/null
+++ b/include/internal/catch_test_spec.hpp
@@ -0,0 +1,133 @@
+/*
+ *  Created by Phil on 2/12/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#include "catch_test_spec.hpp"
+#include "catch_test_case_info.h"
+#include "catch_common.h"
+
+namespace Catch {
+
+    TestCaseFilter::TestCaseFilter( std::string const& testSpec, IfFilterMatches::DoWhat matchBehaviour )
+    :   m_stringToMatch( toLower( testSpec ) ),
+        m_filterType( matchBehaviour ),
+        m_wildcardPosition( NoWildcard )
+    {
+        if( m_filterType == IfFilterMatches::AutoDetectBehaviour ) {
+            if( startsWith( m_stringToMatch, "exclude:" ) ) {
+                m_stringToMatch = m_stringToMatch.substr( 8 );
+                m_filterType = IfFilterMatches::ExcludeTests;
+            }
+            else if( startsWith( m_stringToMatch, "~" ) ) {
+                m_stringToMatch = m_stringToMatch.substr( 1 );
+                m_filterType = IfFilterMatches::ExcludeTests;
+            }
+            else {
+                m_filterType = IfFilterMatches::IncludeTests;
+            }
+        }
+
+        if( startsWith( m_stringToMatch, "*" ) ) {
+            m_stringToMatch = m_stringToMatch.substr( 1 );
+            m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtStart );
+        }
+        if( endsWith( m_stringToMatch, "*" ) ) {
+            m_stringToMatch = m_stringToMatch.substr( 0, m_stringToMatch.size()-1 );
+            m_wildcardPosition = (WildcardPosition)( m_wildcardPosition | WildcardAtEnd );
+        }
+    }
+
+    IfFilterMatches::DoWhat TestCaseFilter::getFilterType() const {
+        return m_filterType;
+    }
+
+    bool TestCaseFilter::shouldInclude( TestCase const& testCase ) const {
+        return isMatch( testCase ) == (m_filterType == IfFilterMatches::IncludeTests);
+    }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
+    bool TestCaseFilter::isMatch( TestCase const& testCase ) const {
+        std::string name = testCase.getTestCaseInfo().name;
+        toLowerInPlace( name );
+
+        switch( m_wildcardPosition ) {
+            case NoWildcard:
+                return m_stringToMatch == name;
+            case WildcardAtStart:
+                return endsWith( name, m_stringToMatch );
+            case WildcardAtEnd:
+                return startsWith( name, m_stringToMatch );
+            case WildcardAtBothEnds:
+                return contains( name, m_stringToMatch );
+        }
+        throw std::logic_error( "Unhandled wildcard type" );
+    }
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+    TestCaseFilters::TestCaseFilters( std::string const& name ) : m_name( name ) {}
+
+    std::string TestCaseFilters::getName() const {
+        return m_name;
+    }
+
+    void TestCaseFilters::addFilter( TestCaseFilter const& filter ) {
+        if( filter.getFilterType() == IfFilterMatches::ExcludeTests )
+            m_exclusionFilters.push_back( filter );
+        else
+            m_inclusionFilters.push_back( filter );
+    }
+
+    void TestCaseFilters::addTags( std::string const& tagPattern ) {
+        TagExpression exp;
+        TagExpressionParser( exp ).parse( tagPattern );
+
+        m_tagExpressions.push_back( exp );
+    }
+
+    bool TestCaseFilters::shouldInclude( TestCase const& testCase ) const {
+        if( !m_tagExpressions.empty() ) {
+            std::vector<TagExpression>::const_iterator it = m_tagExpressions.begin();
+            std::vector<TagExpression>::const_iterator itEnd = m_tagExpressions.end();
+            for(; it != itEnd; ++it )
+                if( it->matches( testCase.getTags() ) )
+                    break;
+            if( it == itEnd )
+                return false;
+        }
+
+        if( !m_inclusionFilters.empty() ) {
+            std::vector<TestCaseFilter>::const_iterator it = m_inclusionFilters.begin();
+            std::vector<TestCaseFilter>::const_iterator itEnd = m_inclusionFilters.end();
+            for(; it != itEnd; ++it )
+                if( it->shouldInclude( testCase ) )
+                    break;
+            if( it == itEnd )
+                return false;
+        }
+        else if( m_exclusionFilters.empty() && m_tagExpressions.empty() ) {
+            return !testCase.isHidden();
+        }
+
+        std::vector<TestCaseFilter>::const_iterator it = m_exclusionFilters.begin();
+        std::vector<TestCaseFilter>::const_iterator itEnd = m_exclusionFilters.end();
+        for(; it != itEnd; ++it )
+            if( !it->shouldInclude( testCase ) )
+                return false;
+        return true;
+    }
+}
+
+#endif // TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp
new file mode 100644
index 0000000..a109d86
--- /dev/null
+++ b/include/reporters/catch_reporter_bases.hpp
@@ -0,0 +1,192 @@
+/*
+ *  Created by Phil on 27/11/2013.
+ *  Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include "../internal/catch_interfaces_reporter.h"
+
+namespace Catch {
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+
+        virtual ~StreamingReporterBase();
+
+        virtual void noMatchingTestCases( std::string const& ) {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
+            currentTestCaseInfo.reset();
+            assert( m_sectionStack.empty() );
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+        friend bool operator == ( Ptr<SectionNode> const& node, SectionInfo const& other ) {
+            return node->stats.sectionInfo.lineInfo == other.lineInfo;
+        }
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+        ~CumulativeReporterBase();
+
+        virtual void testRunStarting( TestRunInfo const& ) {}
+        virtual void testGroupStarting( GroupInfo const& ) {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find( parentNode.childSections.begin(), parentNode.childSections.end(), sectionInfo );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEnded();
+        }
+        virtual void testRunEnded() = 0;
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+
+    };
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp
index 17b07a7..60ada64 100644
--- a/include/reporters/catch_reporter_console.hpp
+++ b/include/reporters/catch_reporter_console.hpp
@@ -8,7 +8,8 @@
 #ifndef TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
 
-#include "../internal/catch_interfaces_reporter.h"
+#include "catch_reporter_bases.hpp"
+
 #include "../internal/catch_reporter_registrars.hpp"
 #include "../internal/catch_console_colour.hpp"
 
diff --git a/include/reporters/catch_reporter_junit.hpp b/include/reporters/catch_reporter_junit.hpp
index c9cf929..db12635 100644
--- a/include/reporters/catch_reporter_junit.hpp
+++ b/include/reporters/catch_reporter_junit.hpp
@@ -8,8 +8,9 @@
 #ifndef TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
 
+#include "catch_reporter_bases.hpp"
+
 #include "../internal/catch_tostring.hpp"
-#include "../internal/catch_interfaces_reporter.h"
 #include "../internal/catch_reporter_registrars.hpp"
 #include "../internal/catch_xmlwriter.hpp"
 
diff --git a/include/reporters/catch_reporter_xml.hpp b/include/reporters/catch_reporter_xml.hpp
index 4c8095e..11ecd91 100644
--- a/include/reporters/catch_reporter_xml.hpp
+++ b/include/reporters/catch_reporter_xml.hpp
@@ -8,8 +8,9 @@
 #ifndef TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
 
+#include "catch_reporter_bases.hpp"
+
 #include "../internal/catch_capture.hpp"
-#include "../internal/catch_interfaces_reporter.h"
 #include "../internal/catch_reporter_registrars.hpp"
 #include "../internal/catch_xmlwriter.hpp"
 
diff --git a/projects/SelfTest/SurrogateCpps/catch_debugger.cpp b/projects/SelfTest/SurrogateCpps/catch_debugger.cpp
index f6b39f5..33f76ae 100644
--- a/projects/SelfTest/SurrogateCpps/catch_debugger.cpp
+++ b/projects/SelfTest/SurrogateCpps/catch_debugger.cpp
@@ -1,2 +1,2 @@
 // This file is only here to verify (to the extent possible) the self sufficiency of the header
-#include "catch_debugger.hpp"
+#include "catch_debugger.h"
diff --git a/projects/SelfTest/SurrogateCpps/catch_stream.cpp b/projects/SelfTest/SurrogateCpps/catch_stream.cpp
index 43458de..9911aec 100644
--- a/projects/SelfTest/SurrogateCpps/catch_stream.cpp
+++ b/projects/SelfTest/SurrogateCpps/catch_stream.cpp
@@ -1,2 +1,2 @@
 // This file is only here to verify (to the extent possible) the self sufficiency of the header
-#include "catch_stream.hpp"
+#include "catch_stream.h"
diff --git a/projects/SelfTest/SurrogateCpps/catch_tags.cpp b/projects/SelfTest/SurrogateCpps/catch_tags.cpp
index 63d1540..36e8789 100644
--- a/projects/SelfTest/SurrogateCpps/catch_tags.cpp
+++ b/projects/SelfTest/SurrogateCpps/catch_tags.cpp
@@ -1,2 +1,2 @@
 // This file is only here to verify (to the extent possible) the self sufficiency of the header
-#include "catch_tags.hpp"
+#include "catch_tags.h"
diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj
index 30b0b29..c6a13fb 100644
--- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj
+++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj
@@ -56,6 +56,14 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		261488FA184C81130041FBEB /* catch_test_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_spec.hpp; sourceTree = "<group>"; };
+		261488FB184C83EA0041FBEB /* catch_tags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_tags.h; sourceTree = "<group>"; };
+		261488FC184D1DC10041FBEB /* catch_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_stream.h; sourceTree = "<group>"; };
+		261488FD184D21290041FBEB /* catch_section_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section_info.h; sourceTree = "<group>"; };
+		261488FE184DC32F0041FBEB /* catch_section.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_section.h; sourceTree = "<group>"; };
+		261488FF184DC4A20041FBEB /* catch_debugger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_debugger.h; sourceTree = "<group>"; };
+		262E7399184673A800CAC268 /* catch_reporter_bases.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_bases.hpp; sourceTree = "<group>"; };
+		262E739A1846759000CAC268 /* catch_common.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_common.hpp; sourceTree = "<group>"; };
 		263FD06017AF8DF200988A20 /* catch_timer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_timer.hpp; sourceTree = "<group>"; };
 		263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = "<group>"; };
 		266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VariadicMacrosTests.cpp; path = ../../../SelfTest/VariadicMacrosTests.cpp; sourceTree = "<group>"; };
@@ -277,6 +285,7 @@
 		4A6D0C65149B3E3D00DB3EAA /* reporters */ = {
 			isa = PBXGroup;
 			children = (
+				262E7399184673A800CAC268 /* catch_reporter_bases.hpp */,
 				4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */,
 				4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */,
 				4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */,
@@ -314,6 +323,7 @@
 		4AC91CB4155B9EBF00DC5117 /* impl */ = {
 			isa = PBXGroup;
 			children = (
+				261488FA184C81130041FBEB /* catch_test_spec.hpp */,
 				263FD06017AF8DF200988A20 /* catch_timer.hpp */,
 				266E9AD117230ACF0061DAB2 /* catch_text.hpp */,
 				4A4B0F9C15CEFA8300AE2392 /* catch_impl.hpp */,
@@ -341,6 +351,7 @@
 				4A6D0C5D149B3E3D00DB3EAA /* catch_assertionresult.h */,
 				4A9D84B315599AC900FBB209 /* catch_expressionresult_builder.h */,
 				4A6D0C5F149B3E3D00DB3EAA /* catch_section.hpp */,
+				261488FE184DC32F0041FBEB /* catch_section.h */,
 				4A3D7DD01503869D005F9203 /* catch_matchers.hpp */,
 				4A9D84B11558FC0400FBB209 /* catch_tostring.hpp */,
 				4A6D0C46149B3E3D00DB3EAA /* catch_approx.hpp */,
@@ -349,6 +360,7 @@
 				4AC91CD0155D8DA600DC5117 /* catch_expression_decomposer.hpp */,
 				4A4B0F9A15CEF84800AE2392 /* catch_notimplemented_exception.h */,
 				26847E5B16BBAB790043B9C1 /* catch_message.h */,
+				261488FD184D21290041FBEB /* catch_section_info.h */,
 			);
 			name = Assertions;
 			sourceTree = "<group>";
@@ -375,6 +387,7 @@
 				4A084F1D15DAD15F0027E631 /* catch_test_spec.h */,
 				4A8E4DCC160A344100194CBD /* catch_tags.hpp */,
 				26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */,
+				261488FB184C83EA0041FBEB /* catch_tags.h */,
 			);
 			name = "Test execution";
 			sourceTree = "<group>";
@@ -411,6 +424,7 @@
 				266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */,
 				4A6D0C49149B3E3D00DB3EAA /* catch_common.h */,
 				4A6D0C4B149B3E3D00DB3EAA /* catch_debugger.hpp */,
+				261488FF184DC4A20041FBEB /* catch_debugger.h */,
 				4A6D0C60149B3E3D00DB3EAA /* catch_stream.hpp */,
 				4A6D0C64149B3E3D00DB3EAA /* catch_xmlwriter.hpp */,
 				4AB1C73714F97C1300F31DF7 /* catch_console_colour.hpp */,
@@ -422,6 +436,8 @@
 				26DACF2F17206D3400A21326 /* catch_text.h */,
 				263FD06117AF8DF200988A20 /* catch_timer.h */,
 				26AEAF1617BEA18E009E32C9 /* catch_platform.h */,
+				262E739A1846759000CAC268 /* catch_common.hpp */,
+				261488FC184D1DC10041FBEB /* catch_stream.h */,
 			);
 			name = Infrastructure;
 			sourceTree = "<group>";
diff --git a/scripts/generateSingleHeader.py b/scripts/generateSingleHeader.py
index ba4c5cd..0f7aa9e 100644
--- a/scripts/generateSingleHeader.py
+++ b/scripts/generateSingleHeader.py
@@ -2,6 +2,7 @@
 import sys
 import re
 import datetime
+import string
 
 from scriptCommon import catchPath
 
@@ -9,6 +10,9 @@
 includesParser = re.compile( r'\s*#include\s*"(.*)"' )
 guardParser = re.compile( r'\s*#.*_INCLUDED')
 defineParser = re.compile( r'\s*#define')
+ifParser = re.compile( r'\s*#if')
+endIfParser = re.compile( r'\s*#endif')
+ifImplParser = re.compile( r'\s*#if.*(CATCH_CONFIG_MAIN|CATCH_CONFIG_RUNNER)')
 commentParser1 = re.compile( r'^\s*/\*')
 commentParser2 = re.compile( r'^\s*\*')
 blankParser = re.compile( r'^\s*$')
@@ -18,21 +22,48 @@
 readmePath = os.path.join( catchPath, "README.md" )
 outputPath = os.path.join( catchPath, 'single_include/catch.hpp' )
 
-bumpVersion = len(sys.argv) < 2 or sys.argv[1] <> "nobump"
+bumpVersion = True
+includeImpl = True
+
+for arg in sys.argv[1:]:
+	arg = string.lower(arg)
+	if arg == "nobump":
+		bumpVersion = False
+		print "Not bumping version number"
+	elif arg == "noimpl":
+		includeImpl = False
+		bumpVersion = False
+		print "Not including impl code (and not bumping version)"
+	else:
+		print "\n** Unrecognised argument: " + arg + " **\n"
+		exit(1)
 
 out = open( outputPath, 'w' )
+ifdefs = 0
+implIfDefs = -1
+
+def write( line ):
+	if includeImpl or implIfDefs == -1:
+		out.write( line )
 
 def parseFile( path, filename ):
+	global ifdefs
+	global implIfDefs
+
 	f = open( path + filename, 'r' )
 	blanks = 0
 	for line in f:
+		if ifParser.match( line ):
+			ifdefs = ifdefs + 1
+		elif endIfParser.match( line ):
+			ifdefs = ifdefs - 1
 		m = includesParser.match( line )
 		if m:
 			header = m.group(1)
 			headerPath, sep, headerFile = header.rpartition( "/" )
 			if not headerFile in seenHeaders:
 				seenHeaders.add( headerFile )
-				out.write( "// #included from: {0}\n".format( header ) )
+				write( "// #included from: {0}\n".format( header ) )
 				if( headerPath == "internal" and path.endswith( "internal/" ) ):
 					headerPath = ""
 					sep = ""
@@ -40,13 +71,15 @@
 					parseFile( path + headerPath + sep, headerFile )
 				else:
 					parseFile( rootPath + headerPath + sep, headerFile )
+		elif ifImplParser.match(line):
+			implIfDefs = ifdefs
 		elif (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ):
 			if blankParser.match( line ):
 				blanks = blanks + 1
 			else:
 				blanks = 0
 			if blanks < 2:
-				out.write( line.rstrip() + "\n" )
+				write( line.rstrip() + "\n" )
 
 class Version:
 	def __init__(self):