Include bind in ndnboost.
diff --git a/ndnboost/test/impl/debug.ipp b/ndnboost/test/impl/debug.ipp
new file mode 100644
index 0000000..bf23f2e
--- /dev/null
+++ b/ndnboost/test/impl/debug.ipp
@@ -0,0 +1,970 @@
+// (C) Copyright Gennadiy Rozental 2006-2008.
+// Use, modification, and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+// File : $RCSfile$
+//
+// Version : $Revision: 57992 $
+//
+// Description : debug interfaces implementation
+// ***************************************************************************
+
+#ifndef BOOST_TEST_DEBUG_API_IPP_112006GER
+#define BOOST_TEST_DEBUG_API_IPP_112006GER
+
+// Boost.Test
+#include <ndnboost/test/detail/config.hpp>
+#include <ndnboost/test/detail/workaround.hpp>
+#include <ndnboost/test/detail/global_typedef.hpp>
+
+#include <ndnboost/test/debug.hpp>
+#include <ndnboost/test/debug_config.hpp>
+
+// Implementation on Windows
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32
+
+# define BOOST_WIN32_BASED_DEBUG
+
+// SYSTEM API
+# include <windows.h>
+# include <winreg.h>
+# include <cstdio>
+# include <cstring>
+
+# if !defined(NDEBUG) && defined(_MSC_VER)
+# define BOOST_MS_CRT_BASED_DEBUG
+# include <crtdbg.h>
+# endif
+
+
+# if BOOST_WORKAROUND( BOOST_MSVC, <1300)
+# define snprintf _snprintf
+# endif
+
+# ifdef BOOST_NO_STDC_NAMESPACE
+namespace std { using ::memset; using ::sprintf; }
+# endif
+
+#elif defined(unix) || defined(__unix) // ********************* UNIX
+
+# define BOOST_UNIX_BASED_DEBUG
+
+// Boost.Test
+#include <ndnboost/test/utils/class_properties.hpp>
+#include <ndnboost/test/utils/algorithm.hpp>
+
+// STL
+#include <cstring> // std::memcpy
+#include <map>
+#include <cstdio>
+#include <stdarg.h> // !! ?? cstdarg
+
+// SYSTEM API
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/wait.h>
+# include <sys/time.h>
+# include <stdio.h>
+# include <stdlib.h>
+
+# if defined(sun) || defined(__sun)
+
+# define BOOST_SUN_BASED_DEBUG
+
+# ifndef BOOST_TEST_DBG_LIST
+# define BOOST_TEST_DBG_LIST dbx;gdb
+# endif
+
+# define BOOST_TEST_CNL_DBG dbx
+# define BOOST_TEST_GUI_DBG dbx-ddd
+
+# include <procfs.h>
+
+# elif defined(linux) || defined(__linux)
+
+# define BOOST_LINUX_BASED_DEBUG
+
+# include <sys/ptrace.h>
+
+# ifndef BOOST_TEST_STAT_LINE_MAX
+# define BOOST_TEST_STAT_LINE_MAX 500
+# endif
+
+# ifndef BOOST_TEST_DBG_LIST
+# define BOOST_TEST_DBG_LIST gdb
+# endif
+
+# define BOOST_TEST_CNL_DBG gdb
+# define BOOST_TEST_GUI_DBG gdb-xterm
+
+# endif
+
+#endif
+
+#include <ndnboost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace ndnboost {
+
+namespace debug {
+
+using unit_test::const_string;
+
+// ************************************************************************** //
+// ************** debug::info_t ************** //
+// ************************************************************************** //
+
+namespace {
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+template<typename T>
+inline void
+dyn_symbol( T& res, char const* module_name, char const* symbol_name )
+{
+ HMODULE m = ::GetModuleHandleA( module_name );
+
+ if( !m )
+ m = ::LoadLibraryA( module_name );
+
+ res = reinterpret_cast<T>( ::GetProcAddress( m, symbol_name ) );
+}
+
+//____________________________________________________________________________//
+
+static struct info_t {
+ typedef BOOL (WINAPI* IsDebuggerPresentT)();
+ typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* /*LPTSTR*/, LPDWORD, LPDWORD, LPBYTE, LPDWORD );
+ typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* /*LPCTSTR*/, PHKEY );
+ typedef LONG (WINAPI* RegCloseKeyT)( HKEY );
+
+ info_t();
+
+ IsDebuggerPresentT m_is_debugger_present;
+ RegOpenKeyT m_reg_open_key;
+ RegQueryValueExT m_reg_query_value;
+ RegCloseKeyT m_reg_close_key;
+
+} s_info;
+
+//____________________________________________________________________________//
+
+info_t::info_t()
+{
+ dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" );
+ dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" );
+ dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" );
+ dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" );
+}
+
+//____________________________________________________________________________//
+
+#elif defined(BOOST_UNIX_BASED_DEBUG)
+
+// ************************************************************************** //
+// ************** fd_holder ************** //
+// ************************************************************************** //
+
+struct fd_holder {
+ explicit fd_holder( int fd ) : m_fd( fd ) {}
+ ~fd_holder()
+ {
+ if( m_fd != -1 )
+ ::close( m_fd );
+ }
+
+ operator int() { return m_fd; }
+
+private:
+ // Data members
+ int m_fd;
+};
+
+
+// ************************************************************************** //
+// ************** process_info ************** //
+// ************************************************************************** //
+
+struct process_info {
+ // Constructor
+ explicit process_info( int pid );
+
+ // access methods
+ int parent_pid() const { return m_parent_pid; }
+ const_string binary_name() const { return m_binary_name; }
+ const_string binary_path() const { return m_binary_path; }
+
+private:
+ // Data members
+ int m_parent_pid;
+ const_string m_binary_name;
+ const_string m_binary_path;
+
+#if defined(BOOST_SUN_BASED_DEBUG)
+ struct psinfo m_psi;
+#elif defined(BOOST_LINUX_BASED_DEBUG)
+ char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1];
+#endif
+ char m_binary_path_buff[500+1]; // !! ??
+};
+
+//____________________________________________________________________________//
+
+process_info::process_info( int pid )
+: m_parent_pid( 0 )
+{
+#if defined(BOOST_SUN_BASED_DEBUG)
+ char fname_buff[30];
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid );
+
+ fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
+
+ if( psinfo_fd == -1 )
+ return;
+
+ if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 )
+ return;
+
+ m_parent_pid = m_psi.pr_ppid;
+
+ m_binary_name.assign( m_psi.pr_fname );
+
+ //-------------------------- //
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid );
+
+ fd_holder as_fd( ::open( fname_buff, O_RDONLY ) );
+ uintptr_t binary_name_pos;
+
+ // !! ?? could we avoid reading whole m_binary_path_buff?
+ if( as_fd == -1 ||
+ ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 ||
+ ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 ||
+ ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 ||
+ ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 )
+ return;
+
+ m_binary_path.assign( m_binary_path_buff );
+
+#elif defined(BOOST_LINUX_BASED_DEBUG)
+ char fname_buff[30];
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid );
+
+ fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) );
+
+ if( psinfo_fd == -1 )
+ return;
+
+ ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 );
+ if( num_read == -1 )
+ return;
+
+ m_stat_line[num_read] = 0;
+
+ char const* name_beg = m_stat_line;
+ while( *name_beg && *name_beg != '(' )
+ ++name_beg;
+
+ char const* name_end = name_beg+1;
+ while( *name_end && *name_end != ')' )
+ ++name_end;
+
+ std::sscanf( name_end+1, "%*s%d", &m_parent_pid );
+
+ m_binary_name.assign( name_beg+1, name_end );
+
+ ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid );
+ num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 );
+
+ if( num_read == -1 )
+ return;
+
+ m_binary_path_buff[num_read] = 0;
+ m_binary_path.assign( m_binary_path_buff, num_read );
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** prepare_window_title ************** //
+// ************************************************************************** //
+
+static char*
+prepare_window_title( dbg_startup_info const& dsi )
+{
+ typedef unit_test::const_string str_t;
+
+ static char title_str[50];
+
+ str_t path_sep( "\\/" );
+
+ str_t::iterator it = unit_test::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(),
+ path_sep.begin(), path_sep.end() );
+
+ if( it == dsi.binary_path.end() )
+ it = dsi.binary_path.begin();
+ else
+ ++it;
+
+ ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid );
+
+ return title_str;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** save_execlp ************** //
+// ************************************************************************** //
+
+typedef unit_test::basic_cstring<char> mbuffer;
+
+inline char*
+copy_arg( mbuffer& dest, const_string arg )
+{
+ if( dest.size() < arg.size()+1 )
+ return 0;
+
+ char* res = dest.begin();
+
+ std::memcpy( res, arg.begin(), arg.size()+1 );
+
+ dest.trim_left( arg.size()+1 );
+
+ return res;
+}
+
+//____________________________________________________________________________//
+
+bool
+safe_execlp( char const* file, ... )
+{
+ static char* argv_buff[200];
+
+ va_list args;
+ char const* arg;
+
+ // first calculate actual number of arguments
+ int num_args = 2; // file name and 0 at least
+
+ va_start( args, file );
+ while( !!(arg = va_arg( args, char const* )) )
+ num_args++;
+ va_end( args );
+
+ // reserve space for the argument pointers array
+ char** argv_it = argv_buff;
+ mbuffer work_buff( reinterpret_cast<char*>(argv_buff), sizeof(argv_buff) );
+ work_buff.trim_left( num_args * sizeof(char*) );
+
+ // copy all the argument values into local storage
+ if( !(*argv_it++ = copy_arg( work_buff, file )) )
+ return false;
+
+ printf( "!! %s\n", file );
+
+ va_start( args, file );
+ while( !!(arg = va_arg( args, char const* )) ) {
+ printf( "!! %s\n", arg );
+ if( !(*argv_it++ = copy_arg( work_buff, arg )) )
+ return false;
+ }
+ va_end( args );
+
+ *argv_it = 0;
+
+ return ::execvp( file, argv_buff ) != -1;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** start_debugger_in_emacs ************** //
+// ************************************************************************** //
+
+static void
+start_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command )
+{
+ char const* title = prepare_window_title( dsi );
+
+ if( !title )
+ return;
+
+ dsi.display.is_empty()
+ ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 )
+ : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** gdb starters ************** //
+// ************************************************************************** //
+
+static char const*
+prepare_gdb_cmnd_file( dbg_startup_info const& dsi )
+{
+ // prepare pid value
+ char pid_buff[16];
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+ unit_test::const_string pid_str( pid_buff );
+
+ static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX"; // !! ??
+
+ // prepare commands
+ fd_holder cmd_fd( ::mkstemp( cmd_file_name ) );
+
+ if( cmd_fd == -1 )
+ return 0;
+
+#define WRITE_STR( str ) if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0;
+#define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0;
+
+ WRITE_CSTR( "file " );
+ WRITE_STR( dsi.binary_path );
+ WRITE_CSTR( "\nattach " );
+ WRITE_STR( pid_str );
+ WRITE_CSTR( "\nshell unlink " );
+ WRITE_STR( dsi.init_done_lock );
+ WRITE_CSTR( "\ncont" );
+ if( dsi.break_or_continue )
+ WRITE_CSTR( "\nup 4" );
+
+ WRITE_CSTR( "\necho \\n" ); // !! ??
+ WRITE_CSTR( "\nlist -" );
+ WRITE_CSTR( "\nlist" );
+ WRITE_CSTR( "\nshell unlink " );
+ WRITE_CSTR( cmd_file_name );
+
+ return cmd_file_name;
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_console( dbg_startup_info const& dsi )
+{
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+
+ if( !cmnd_file_name )
+ return;
+
+ safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_xterm( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+
+ if( !title || !cmnd_file_name )
+ return;
+
+ safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
+ "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
+ "gdb", "-q", "-x", cmnd_file_name, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_emacs( dbg_startup_info const& dsi )
+{
+ char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi );
+ if( !cmnd_file_name )
+ return;
+
+ char dbg_cmd_buff[500]; // !! ??
+ ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (gdb \"gdb -q -x %s\"))", cmnd_file_name );
+
+ start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_gdb_in_xemacs( dbg_startup_info const& )
+{
+ // !! ??
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** dbx starters ************** //
+// ************************************************************************** //
+
+static char const*
+prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true )
+{
+ static char cmd_line_buff[500]; // !! ??
+
+ ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s",
+ dsi.init_done_lock.begin(),
+ dsi.break_or_continue ? "up 2;": "",
+ list_source ? "echo \" \";list -w3;" : "" );
+
+ return cmd_line_buff;
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_console( dbg_startup_info const& dsi )
+{
+ char pid_buff[16];
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_xterm( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ if( !title )
+ return;
+
+ char pid_buff[16]; // !! ??
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(),
+ "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e",
+ "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_emacs( dbg_startup_info const& /*dsi*/ )
+{
+// char dbg_cmd_buff[500]; // !! ??
+//
+// ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (dbx \"dbx -q -c cont %s %ld\"))", dsi.binary_path.begin(), dsi.pid );
+
+// start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff );
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_xemacs( dbg_startup_info const& )
+{
+ // !! ??
+}
+
+//____________________________________________________________________________//
+
+static void
+start_dbx_in_ddd( dbg_startup_info const& dsi )
+{
+ char const* title = prepare_window_title( dsi );
+ if( !title )
+ return;
+
+ char pid_buff[16]; // !! ??
+ ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid );
+
+ safe_execlp( "ddd", "-display", dsi.display.begin(),
+ "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 );
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** debug::info_t ************** //
+// ************************************************************************** //
+
+static struct info_t {
+ // Constructor
+ info_t();
+
+ // Public properties
+ unit_test::readwrite_property<std::string> p_dbg;
+
+ // Data members
+ std::map<std::string,dbg_starter> m_dbg_starter_reg;
+} s_info;
+
+//____________________________________________________________________________//
+
+info_t::info_t()
+{
+ p_dbg.value = ::getenv( "DISPLAY" )
+ ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) )
+ : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) );
+
+ m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console;
+ m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs;
+ m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm;
+ m_dbg_starter_reg[std::string("gdb-xemacs")] = &start_gdb_in_xemacs;
+
+ m_dbg_starter_reg[std::string("dbx")] = &start_dbx_in_console;
+ m_dbg_starter_reg[std::string("dbx-emacs")] = &start_dbx_in_emacs;
+ m_dbg_starter_reg[std::string("dbx-xterm")] = &start_dbx_in_xterm;
+ m_dbg_starter_reg[std::string("dbx-xemacs")] = &start_dbx_in_xemacs;
+ m_dbg_starter_reg[std::string("dbx-ddd")] = &start_dbx_in_ddd;
+}
+
+//____________________________________________________________________________//
+
+#endif
+
+} // local namespace
+
+// ************************************************************************** //
+// ************** check if program is running under debugger ************** //
+// ************************************************************************** //
+
+bool
+under_debugger()
+{
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+ return !!s_info.m_is_debugger_present && s_info.m_is_debugger_present();
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ // !! ?? could/should we cache the result somehow?
+ const_string dbg_list = BOOST_TEST_STRINGIZE( BOOST_TEST_DBG_LIST );
+
+ pid_t pid = ::getpid();
+
+ while( pid != 0 ) {
+ process_info pi( pid );
+
+ // !! ?? should we use tokenizer here instead?
+ if( dbg_list.find( pi.binary_name() ) != const_string::npos )
+ return true;
+
+ pid = (pi.parent_pid() == pid ? 0 : pi.parent_pid());
+ }
+
+ return false;
+
+#else // ****************************************************** default
+
+ return false;
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** cause program to break execution ************** //
+// ************** in debugger at call point ************** //
+// ************************************************************************** //
+
+void
+debugger_break()
+{
+ // !! ?? auto-start debugger?
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1300) || \
+ BOOST_WORKAROUND(__GNUC__, >= 3) && !defined(__MINGW32__) || \
+ defined(__INTEL_COMPILER)
+# define BOOST_DEBUG_BREAK __debugbreak
+#else
+# define BOOST_DEBUG_BREAK DebugBreak
+#endif
+
+#ifndef __MINGW32__
+ if( !under_debugger() ) {
+ __try {
+ __try {
+ BOOST_DEBUG_BREAK();
+ }
+ __except( UnhandledExceptionFilter(GetExceptionInformation()) )
+ {
+ // User opted to ignore the breakpoint
+ return;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // If we got here, the user has pushed Debug. Debugger is already attached to our process and we
+ // continue to let the another BOOST_DEBUG_BREAK to be called.
+ }
+ }
+#endif
+
+ BOOST_DEBUG_BREAK();
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ ::kill( ::getpid(), SIGTRAP );
+
+#else // ****************************************************** default
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** console debugger setup ************** //
+// ************************************************************************** //
+
+#if defined(BOOST_UNIX_BASED_DEBUG) // ************************ UNIX
+
+std::string
+set_debugger( unit_test::const_string dbg_id, dbg_starter s )
+{
+ std::string old = s_info.p_dbg;
+
+ assign_op( s_info.p_dbg.value, dbg_id, 0 );
+
+ if( !!s )
+ s_info.m_dbg_starter_reg[s_info.p_dbg] = s;
+
+ return old;
+}
+
+#else // ***************************************************** default
+
+std::string
+set_debugger( unit_test::const_string, dbg_starter )
+{
+ return std::string();
+}
+
+#endif
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** attach debugger to the current process ************** //
+// ************************************************************************** //
+
+bool
+attach_debugger( bool break_or_continue )
+{
+ if( under_debugger() )
+ return false;
+
+#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32
+
+ const int MAX_CMD_LINE = 200;
+
+ // *************************************************** //
+ // Debugger "ready" event
+
+ SECURITY_ATTRIBUTES attr;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = true;
+
+ // manual resettable, initially non signaled, unnamed event,
+ // that will signal me that debugger initialization is done
+ HANDLE dbg_init_done_ev = ::CreateEvent(
+ &attr, // pointer to security attributes
+ true, // flag for manual-reset event
+ false, // flag for initial state
+ NULL // pointer to event-object name
+ );
+
+ if( !dbg_init_done_ev )
+ return false;
+
+ // *************************************************** //
+ // Debugger command line format
+
+ HKEY reg_key;
+
+ if( !s_info.m_reg_open_key || (*s_info.m_reg_open_key)(
+ HKEY_LOCAL_MACHINE, // handle of open key
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", // name of subkey to open
+ ®_key ) != ERROR_SUCCESS ) // address of handle of open key
+ return false;
+
+ char format[MAX_CMD_LINE];
+ DWORD format_size = MAX_CMD_LINE;
+ DWORD type = REG_SZ;
+
+ if( !s_info.m_reg_query_value || (*s_info.m_reg_query_value)(
+ reg_key, // handle of open key
+ "Debugger", // name of subkey to query
+ 0, // reserved
+ &type, // value type
+ (LPBYTE)format, // buffer for returned string
+ &format_size ) != ERROR_SUCCESS ) // in: buffer size; out: actual size of returned string
+ return false;
+
+ if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS )
+ return false;
+
+ // *************************************************** //
+ // Debugger command line
+
+ char cmd_line[MAX_CMD_LINE];
+ std::sprintf( cmd_line, format, ::GetCurrentProcessId(), dbg_init_done_ev );
+
+ // *************************************************** //
+ // Debugger window parameters
+
+ STARTUPINFOA startup_info;
+ std::memset( &startup_info, 0, sizeof(startup_info) );
+
+ startup_info.cb = sizeof(startup_info);
+ startup_info.dwFlags = STARTF_USESHOWWINDOW;
+ startup_info.wShowWindow = SW_SHOWNORMAL;
+
+ // debugger process s_info
+ PROCESS_INFORMATION debugger_info;
+
+ bool created = !!::CreateProcessA(
+ NULL, // pointer to name of executable module; NULL - use the one in command line
+ cmd_line, // pointer to command line string
+ NULL, // pointer to process security attributes; NULL - debugger's handle can't be inherited
+ NULL, // pointer to thread security attributes; NULL - debugger's handle can't be inherited
+ true, // debugger inherit opened handles
+ 0, // priority flags; 0 - normal priority
+ NULL, // pointer to new environment block; NULL - use this process environment
+ NULL, // pointer to current directory name; NULL - use this process correct directory
+ &startup_info, // pointer to STARTUPINFO that specifies main window appearance
+ &debugger_info // pointer to PROCESS_INFORMATION that will contain the new process identification
+ );
+
+ if( created )
+ ::WaitForSingleObject( dbg_init_done_ev, INFINITE );
+
+ ::CloseHandle( dbg_init_done_ev );
+
+ if( !created )
+ return false;
+
+ if( break_or_continue )
+ debugger_break();
+
+ return true;
+
+#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX
+
+ char init_done_lock_fn[] = "/tmp/btl_dbg_init_done_XXXXXX";
+ fd_holder init_done_lock_fd( ::mkstemp( init_done_lock_fn ) );
+
+ if( init_done_lock_fd == -1 )
+ return false;
+
+ pid_t child_pid = fork();
+
+ if( child_pid == -1 )
+ return false;
+
+ if( child_pid != 0 ) { // parent process - here we will start the debugger
+ dbg_startup_info dsi;
+
+ process_info pi( child_pid );
+ if( pi.binary_path().is_empty() )
+ ::exit( -1 );
+
+ dsi.pid = child_pid;
+ dsi.break_or_continue = break_or_continue;
+ dsi.binary_path = pi.binary_path();
+ dsi.display = ::getenv( "DISPLAY" );
+ dsi.init_done_lock = init_done_lock_fn;
+
+ dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg];
+ if( !!starter )
+ starter( dsi );
+
+ ::perror( "Boost.Test execution monitor failed to start a debugger:" );
+
+ ::exit( -1 );
+ }
+
+ // child process - here we will continue our test module execution ; // !! ?? should it be vice versa
+
+ while( ::access( init_done_lock_fn, F_OK ) == 0 ) {
+ struct timeval to = { 0, 100 };
+
+ ::select( 0, 0, 0, 0, &to );
+ }
+
+// char dummy;
+// while( ::read( init_done_lock_fd, &dummy, sizeof(char) ) == 0 );
+
+ if( break_or_continue )
+ debugger_break();
+
+ return true;
+
+#else // ****************************************************** default
+
+ return false;
+
+#endif
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** switch on/off detect memory leaks feature ************** //
+// ************************************************************************** //
+
+void
+detect_memory_leaks( bool on_off )
+{
+ unit_test::ut_detail::ignore_unused_variable_warning( on_off );
+
+#ifdef BOOST_MS_CRT_BASED_DEBUG
+ int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
+
+ if( !on_off )
+ flags &= ~_CRTDBG_LEAK_CHECK_DF;
+ else {
+ flags |= _CRTDBG_LEAK_CHECK_DF;
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
+ }
+
+ _CrtSetDbgFlag ( flags );
+#endif // BOOST_MS_CRT_BASED_DEBUG
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** cause program to break execution in ************** //
+// ************** debugger at specific allocation point ************** //
+// ************************************************************************** //
+
+void
+break_memory_alloc( long mem_alloc_order_num )
+{
+ unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num );
+
+#ifdef BOOST_MS_CRT_BASED_DEBUG
+ _CrtSetBreakAlloc( mem_alloc_order_num );
+#endif // BOOST_MS_CRT_BASED_DEBUG
+}
+
+} // namespace debug
+
+} // namespace ndnboost
+
+//____________________________________________________________________________//
+
+#include <ndnboost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_DEBUG_API_IPP_112006GER
+