From 0e62b10875c595864aa5b01f744a1e87fb5f704f Mon Sep 17 00:00:00 2001 From: alef Date: Sun, 29 Dec 2024 17:38:19 +0100 Subject: [PATCH 01/19] Convert PATH_INFO::debug to a cata_path --- src/debug.cpp | 21 ++++++++++----------- src/path_info.cpp | 4 ++-- src/path_info.h | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index fc1d9d53879dd..ed3d974e2eeb1 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -636,14 +636,14 @@ static time_info get_time() noexcept struct DebugFile { DebugFile(); ~DebugFile(); - void init( DebugOutput, const std::string &filename ); + void init( DebugOutput, const cata_path &filename ); void deinit(); std::ostream &get_file(); // Using shared_ptr for the type-erased deleter support, not because // it needs to be shared. std::shared_ptr file; - std::string filename; + cata_path filename; }; // DebugFile OStream Wrapper {{{2 @@ -686,7 +686,7 @@ std::ostream &DebugFile::get_file() return *file; } -void DebugFile::init( DebugOutput output_mode, const std::string &filename ) +void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) { std::shared_ptr str_buffer = std::dynamic_pointer_cast ( file ); @@ -697,17 +697,16 @@ void DebugFile::init( DebugOutput output_mode, const std::string &filename ) break; case DebugOutput::file: { this->filename = filename; - const std::string oldfile = filename + ".prev"; + const cata_path oldfile = filename + ".prev"; bool rename_failed = false; - struct stat buffer; - if( stat( filename.c_str(), &buffer ) == 0 ) { - // Continue with the old log file if it's smaller than 1 MiB - if( buffer.st_size >= 1024 * 1024 ) { - rename_failed = !rename_file( filename, oldfile ); - } + // Continue with the old log file if it's smaller than 1 MiB + if (fs::file_size(fs::path(filename)) >= 1024 * 1024) { + std::error_code ec; + fs::rename(fs::path(filename), fs::path(oldfile), ec); + rename_failed = bool(ec); } file = std::make_shared( - std::filesystem::u8path( filename ), std::ios::out | std::ios::app ); + filename.generic_u8string(), std::ios::out | std::ios::app ); *file << "\n\n-----------------------------------------\n"; *file << get_time() << " : Starting log."; DebugLog( D_INFO, D_MAIN ) << "Cataclysm DDA version " << getVersionString(); diff --git a/src/path_info.cpp b/src/path_info.cpp index c3fb4e62ec30d..db8c64d220ee9 100644 --- a/src/path_info.cpp +++ b/src/path_info.cpp @@ -263,9 +263,9 @@ cata_path PATH_INFO::datadir_path() { return datadir_path_value; } -std::string PATH_INFO::debug() +cata_path PATH_INFO::debug() { - return config_dir_value + "debug.log"; + return config_dir_path_value / "debug.log"; } cata_path PATH_INFO::defaultsounddir() { diff --git a/src/path_info.h b/src/path_info.h index 3fb46268b3f66..dc573eb1b47ec 100644 --- a/src/path_info.h +++ b/src/path_info.h @@ -25,7 +25,6 @@ void set_standard_filenames(); std::string cache_dir(); std::string config_dir(); std::string datadir(); -std::string debug(); std::string defaulttilejson(); std::string defaultlayeringjson(); std::string defaulttilepng(); @@ -62,6 +61,7 @@ cata_path config_dir_path(); cata_path custom_colors(); cata_path data_sound(); cata_path datadir_path(); +cata_path debug(); cata_path defaultsounddir(); cata_path fontdata(); cata_path gfxdir(); From d0b84436d7f3403d7b730ce90c2bce47f36fbc5b Mon Sep 17 00:00:00 2001 From: alef Date: Sun, 29 Dec 2024 17:42:11 +0100 Subject: [PATCH 02/19] Add classes to write both ostream and Windows debugger DebugFile hosts the ostream as a singleton. This is fine because debugFile() does the same. Maybe move it into DebugFile::init to capture the start. --- src/debug.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index ed3d974e2eeb1..1cfa8402c7ed8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -633,6 +633,49 @@ static time_info get_time() noexcept } #endif +#if defined(_WIN32) +// Send the DebugLog stream to Windows' debug facility +struct OutputDebugStreamA : public std::ostream { + + // Use the file buffer from DebugFile + OutputDebugStreamA(const std::ostream& fileStream) + : std::ostream(&buf), buf(fileStream.rdbuf()) {} + + // Intercept stream operations + struct _Buf : public std::streambuf { + _Buf(std::streambuf* buf) : buf(buf) { + output_string.reserve(max); + } + protected: + virtual int overflow(int c) override { + if (EOF != c) { + int rc = buf->sputc(c); + output_string.push_back(c); + OutputDebugString(c); + } + return c; + } + virtual std::streamsize xsputn(const char* s, std::streamsize n) override { + std::streamsize rc = buf->sputn(s, n); + output_string.append(s, n); + OutputDebugString(); + return rc; + } + private: + // If `c` is not EOF then it must have been called by overflow + void OutputDebugString(int c = EOF) { + if (output_string.size() >= max || c == '\n' || c == '\r') { + ::OutputDebugStringA(output_string.c_str()); + output_string.clear(); + } + } + static constexpr std::streamsize max = 1024; + std::string output_string; + std::streambuf* buf; + } buf; +}; +#endif + struct DebugFile { DebugFile(); ~DebugFile(); @@ -1447,7 +1490,12 @@ std::ostream &DebugLog( DebugLevel lev, DebugClass cl ) // Error are always logged, they are important, // Messages from D_MAIN come from debugmsg and are equally important. if( ( lev & debugLevel && cl & debugClass ) || lev & D_ERROR || cl & D_MAIN ) { - std::ostream &out = debugFile().get_file(); +#if defined(_WIN32) + // Additionally send it to Windows' debugger or Dbgview + static OutputDebugStreamA out(debugFile().get_file()); +#else + std::ostream& out = debugFile().get_file(); +#endif output_repetitions( out ); From 525a9aaa7f60257f5f944c432120f3f32645df52 Mon Sep 17 00:00:00 2001 From: alef Date: Sun, 29 Dec 2024 18:13:14 +0100 Subject: [PATCH 03/19] Obey astyle --- src/debug.cpp | 82 +++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 1cfa8402c7ed8..69ba6aa69d6cc 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -637,42 +637,42 @@ static time_info get_time() noexcept // Send the DebugLog stream to Windows' debug facility struct OutputDebugStreamA : public std::ostream { - // Use the file buffer from DebugFile - OutputDebugStreamA(const std::ostream& fileStream) - : std::ostream(&buf), buf(fileStream.rdbuf()) {} - - // Intercept stream operations - struct _Buf : public std::streambuf { - _Buf(std::streambuf* buf) : buf(buf) { - output_string.reserve(max); - } - protected: - virtual int overflow(int c) override { - if (EOF != c) { - int rc = buf->sputc(c); - output_string.push_back(c); - OutputDebugString(c); - } - return c; - } - virtual std::streamsize xsputn(const char* s, std::streamsize n) override { - std::streamsize rc = buf->sputn(s, n); - output_string.append(s, n); - OutputDebugString(); - return rc; - } - private: - // If `c` is not EOF then it must have been called by overflow - void OutputDebugString(int c = EOF) { - if (output_string.size() >= max || c == '\n' || c == '\r') { - ::OutputDebugStringA(output_string.c_str()); - output_string.clear(); - } - } - static constexpr std::streamsize max = 1024; - std::string output_string; - std::streambuf* buf; - } buf; + // Use the file buffer from DebugFile + OutputDebugStreamA( const std::ostream &fileStream ) + : std::ostream( &buf ), buf( fileStream.rdbuf() ) {} + + // Intercept stream operations + struct _Buf : public std::streambuf { + _Buf( std::streambuf *buf ) : buf( buf ) { + output_string.reserve( max ); + } + protected: + virtual int overflow( int c ) override { + if( EOF != c ) { + int rc = buf->sputc( c ); + output_string.push_back( c ); + OutputDebugString( c ); + } + return c; + } + virtual std::streamsize xsputn( const char *s, std::streamsize n ) override { + std::streamsize rc = buf->sputn( s, n ); + output_string.append( s, n ); + OutputDebugString(); + return rc; + } + private: + // If `c` is not EOF then it must have been called by overflow + void OutputDebugString( int c = EOF ) { + if( output_string.size() >= max || c == '\n' || c == '\r' ) { + ::OutputDebugStringA( output_string.c_str() ); + output_string.clear(); + } + } + static constexpr std::streamsize max = 1024; + std::string output_string; + std::streambuf *buf; + } buf; }; #endif @@ -743,10 +743,10 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) const cata_path oldfile = filename + ".prev"; bool rename_failed = false; // Continue with the old log file if it's smaller than 1 MiB - if (fs::file_size(fs::path(filename)) >= 1024 * 1024) { + if( fs::file_size( fs::path( filename ) ) >= 1024 * 1024 ) { std::error_code ec; - fs::rename(fs::path(filename), fs::path(oldfile), ec); - rename_failed = bool(ec); + fs::rename( fs::path( filename ), fs::path( oldfile ), ec ); + rename_failed = bool( ec ); } file = std::make_shared( filename.generic_u8string(), std::ios::out | std::ios::app ); @@ -1492,9 +1492,9 @@ std::ostream &DebugLog( DebugLevel lev, DebugClass cl ) if( ( lev & debugLevel && cl & debugClass ) || lev & D_ERROR || cl & D_MAIN ) { #if defined(_WIN32) // Additionally send it to Windows' debugger or Dbgview - static OutputDebugStreamA out(debugFile().get_file()); + static OutputDebugStreamA out( debugFile().get_file() ); #else - std::ostream& out = debugFile().get_file(); + std::ostream &out = debugFile().get_file(); #endif output_repetitions( out ); From 58fded1348b6fcc54378d1d82fb7dafe4f59df6f Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:41:51 +0100 Subject: [PATCH 04/19] Move the singleton into its struct --- src/debug.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 69ba6aa69d6cc..e05c225b8699f 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -682,6 +682,10 @@ struct DebugFile { void init( DebugOutput, const cata_path &filename ); void deinit(); std::ostream &get_file(); + static DebugFile& instance() { + static DebugFile instance; + return instance; + }; // Using shared_ptr for the type-erased deleter support, not because // it needs to be shared. @@ -692,16 +696,6 @@ struct DebugFile { // DebugFile OStream Wrapper {{{2 // --------------------------------------------------------------------- -// needs to be inside the method to ensure it's initialized (and only once) -// NOTE: using non-local static variables (defined at top level in cpp file) here is wrong, -// because DebugLog (that uses them) might be called from the constructor of some non-local static entity -// during dynamic initialization phase, when non-local static variables here are -// only zero-initialized -static DebugFile &debugFile() -{ - static DebugFile debugFile; - return debugFile; -} DebugFile::DebugFile() = default; From c974bd50cd04ba3874fe4f0358869a78e61e7f9e Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:42:35 +0100 Subject: [PATCH 05/19] Move deinit() into the destructor --- src/debug.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index e05c225b8699f..63672fc13cd35 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -680,7 +680,6 @@ struct DebugFile { DebugFile(); ~DebugFile(); void init( DebugOutput, const cata_path &filename ); - void deinit(); std::ostream &get_file(); static DebugFile& instance() { static DebugFile instance; @@ -700,11 +699,6 @@ struct DebugFile { DebugFile::DebugFile() = default; DebugFile::~DebugFile() -{ - deinit(); -} - -void DebugFile::deinit() { if( file && file.get() != &std::cerr ) { output_repetitions( *file ); @@ -818,7 +812,7 @@ void setupDebug( DebugOutput output_mode ) void deinitDebug() { - debugFile().deinit(); + DebugFile::instance().~DebugFile(); } // OStream Operators {{{2 From e44c0b9e1deadf28cdaa380f16c368bc8b087dd9 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:43:17 +0100 Subject: [PATCH 06/19] Remove default constructor --- src/debug.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 63672fc13cd35..bc58ef22f516c 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -677,7 +677,6 @@ struct OutputDebugStreamA : public std::ostream { #endif struct DebugFile { - DebugFile(); ~DebugFile(); void init( DebugOutput, const cata_path &filename ); std::ostream &get_file(); @@ -695,9 +694,6 @@ struct DebugFile { // DebugFile OStream Wrapper {{{2 // --------------------------------------------------------------------- - -DebugFile::DebugFile() = default; - DebugFile::~DebugFile() { if( file && file.get() != &std::cerr ) { From 7ef5fa9f6d2070a7032951dfff23f2e912dd4994 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:44:00 +0100 Subject: [PATCH 07/19] Initialize `file` in the declaration --- src/debug.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index bc58ef22f516c..4ff9b8a6f34af 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -687,7 +687,7 @@ struct DebugFile { // Using shared_ptr for the type-erased deleter support, not because // it needs to be shared. - std::shared_ptr file; + std::shared_ptr file = std::make_shared(); cata_path filename; }; @@ -707,9 +707,6 @@ DebugFile::~DebugFile() std::ostream &DebugFile::get_file() { - if( !file ) { - file = std::make_shared(); - } return *file; } From 1d489028c2202605530a1f7525239cfa217a6810 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:45:00 +0100 Subject: [PATCH 08/19] Call instance() to get the singleton --- src/debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 4ff9b8a6f34af..ba8cb2c30588e 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -800,7 +800,7 @@ void setupDebug( DebugOutput output_mode ) limitDebugClass( cl ); } - debugFile().init( output_mode, PATH_INFO::debug() ); + DebugFile::instance().init( output_mode, PATH_INFO::debug() ); } void deinitDebug() @@ -1471,11 +1471,11 @@ std::ostream &DebugLog( DebugLevel lev, DebugClass cl ) // Error are always logged, they are important, // Messages from D_MAIN come from debugmsg and are equally important. if( ( lev & debugLevel && cl & debugClass ) || lev & D_ERROR || cl & D_MAIN ) { + std::ostream &out = DebugFile::instance().get_file(); #if defined(_WIN32) // Additionally send it to Windows' debugger or Dbgview static OutputDebugStreamA out( debugFile().get_file() ); #else - std::ostream &out = debugFile().get_file(); #endif output_repetitions( out ); From 674ccfc636a12f1d84646876f05e54dc562d32d4 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:46:31 +0100 Subject: [PATCH 09/19] Rename because it could be stderr --- src/debug.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index ba8cb2c30588e..acf7583db4764 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -638,8 +638,8 @@ static time_info get_time() noexcept struct OutputDebugStreamA : public std::ostream { // Use the file buffer from DebugFile - OutputDebugStreamA( const std::ostream &fileStream ) - : std::ostream( &buf ), buf( fileStream.rdbuf() ) {} + OutputDebugStreamA( const std::shared_ptr& stream ) + : std::ostream( &buf ), buf( stream->rdbuf() ) {} // Intercept stream operations struct _Buf : public std::streambuf { From 5e008458aef461ecea1dffd6b1acba88aa422c71 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:49:12 +0100 Subject: [PATCH 10/19] Move file logic outside the DebugOutput::file case Needed to not loose the initial message and to be able to use stderr in the tests. --- src/debug.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index acf7583db4764..dec490a13cf4d 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -715,14 +715,14 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) std::shared_ptr str_buffer = std::dynamic_pointer_cast ( file ); + bool rename_failed = false; + const cata_path oldfile = filename + ".prev"; switch( output_mode ) { case DebugOutput::std_err: file = std::shared_ptr( &std::cerr, null_deleter() ); break; case DebugOutput::file: { this->filename = filename; - const cata_path oldfile = filename + ".prev"; - bool rename_failed = false; // Continue with the old log file if it's smaller than 1 MiB if( fs::file_size( fs::path( filename ) ) >= 1024 * 1024 ) { std::error_code ec; @@ -731,16 +731,6 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) } file = std::make_shared( filename.generic_u8string(), std::ios::out | std::ios::app ); - *file << "\n\n-----------------------------------------\n"; - *file << get_time() << " : Starting log."; - DebugLog( D_INFO, D_MAIN ) << "Cataclysm DDA version " << getVersionString(); - if( rename_failed ) { - DebugLog( D_ERROR, DC_ALL ) << "Moving the previous log file to " - << oldfile << " failed.\n" - << "Check the file permissions. This " - "program will continue to use the " - "previous log file."; - } } break; default: @@ -749,6 +739,16 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) return; } + *file << "\n\n-----------------------------------------\n"; + *file << get_time() << " : Starting log."; + DebugLog( D_INFO, D_MAIN ) << "Cataclysm DDA version " << getVersionString(); + if( rename_failed ) { + DebugLog( D_ERROR, DC_ALL ) << "Moving the previous log file to " + << oldfile << " failed.\n" + << "Check the file permissions. This " + "program will continue to use the " + "previous log file."; + } if( str_buffer && file ) { *file << str_buffer->str(); } From 28866d9c533943ee745254286432f177c7d5cc43 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:50:10 +0100 Subject: [PATCH 11/19] Move OutputDebugStreamA instantiation into init() --- src/debug.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index dec490a13cf4d..7d37c3dcd33b0 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -738,7 +738,10 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) << std::endl; return; } - +#ifdef _WIN32 + static auto keep_shared_ptr = file; + file = std::make_shared( file ); +#endif *file << "\n\n-----------------------------------------\n"; *file << get_time() << " : Starting log."; DebugLog( D_INFO, D_MAIN ) << "Cataclysm DDA version " << getVersionString(); @@ -1472,11 +1475,6 @@ std::ostream &DebugLog( DebugLevel lev, DebugClass cl ) // Messages from D_MAIN come from debugmsg and are equally important. if( ( lev & debugLevel && cl & debugClass ) || lev & D_ERROR || cl & D_MAIN ) { std::ostream &out = DebugFile::instance().get_file(); -#if defined(_WIN32) - // Additionally send it to Windows' debugger or Dbgview - static OutputDebugStreamA out( debugFile().get_file() ); -#else -#endif output_repetitions( out ); From 4443fc3d71e05bfc8a8234ce5d19c7facebecb7e Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:51:07 +0100 Subject: [PATCH 12/19] Initialize member in declaration. Increase max buffer --- src/debug.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 7d37c3dcd33b0..5b85294936b10 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -669,9 +669,9 @@ struct OutputDebugStreamA : public std::ostream { output_string.clear(); } } - static constexpr std::streamsize max = 1024; - std::string output_string; - std::streambuf *buf; + static constexpr std::streamsize max = 4096; + std::string output_string{}; + std::streambuf *buf = nullptr; } buf; }; #endif From a80a8b0539a6b177cd9159d6f0e541fdc60a1e66 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:51:47 +0100 Subject: [PATCH 13/19] Rename to send() and change the logic --- src/debug.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 5b85294936b10..900792750a224 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -650,8 +650,16 @@ struct OutputDebugStreamA : public std::ostream { virtual int overflow( int c ) override { if( EOF != c ) { int rc = buf->sputc( c ); - output_string.push_back( c ); - OutputDebugString( c ); + if ( std::iscntrl(c) ) { + send(); + } else { + output_string.push_back( c ); + if (output_string.size() >= max) { + send(); + } + } + } else { + send(); } return c; } @@ -662,11 +670,12 @@ struct OutputDebugStreamA : public std::ostream { return rc; } private: - // If `c` is not EOF then it must have been called by overflow - void OutputDebugString( int c = EOF ) { - if( output_string.size() >= max || c == '\n' || c == '\r' ) { + void send(const char *s = nullptr) { + if (s == nullptr) { ::OutputDebugStringA( output_string.c_str() ); output_string.clear(); + } else { + ::OutputDebugStringA( s ); } } static constexpr std::streamsize max = 4096; From 2b8925ed49ea5931a9c59293c8ba08326be9f629 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:53:34 +0100 Subject: [PATCH 14/19] Avoid sending newlines & co. to DebugView DebugView will show newlines as additional empty lines, while the vscode debugger output will print them correctly. --- src/debug.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 900792750a224..0d546c1ee08c8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -664,9 +664,26 @@ struct OutputDebugStreamA : public std::ostream { return c; } virtual std::streamsize xsputn( const char *s, std::streamsize n ) override { - std::streamsize rc = buf->sputn( s, n ); - output_string.append( s, n ); - OutputDebugString(); + std::streamsize rc = buf->sputn( s, n ), last = 0, i = 0; + for(; i < n; ++i) { + if( std::iscntrl(s[i]) ) { + if(i == last+1) { // Skip multiple empty lines + last = i; + continue; + } + const std::string sv(s + last, i - last); + last = i; + send(sv.c_str()); + } + } + std::string append( s + last, n - last ); + // Skip if only made of multiple newlines + if (none_of( append.begin(), append.end(), [](int c) { return std::iscntrl(c); })) { + output_string.append( s + last, n - last ); + } + if (output_string.size() >= max) { + send(); + } return rc; } private: From fbbd1a300daf98d8248bd61ce99a63d1a5e01369 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:54:10 +0100 Subject: [PATCH 15/19] Sync `debug.log` every time we call OutputDebugStringA --- src/debug.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debug.cpp b/src/debug.cpp index 0d546c1ee08c8..4dbd66a758636 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -694,6 +694,7 @@ struct OutputDebugStreamA : public std::ostream { } else { ::OutputDebugStringA( s ); } + buf->pubsync(); } static constexpr std::streamsize max = 4096; std::string output_string{}; From e8372f2dfa5ac93915dcb330bd18dfbb457095e8 Mon Sep 17 00:00:00 2001 From: alef Date: Tue, 31 Dec 2024 17:55:18 +0100 Subject: [PATCH 16/19] Obey astyle --- src/debug.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 4dbd66a758636..a3d10adc70ca8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -638,7 +638,7 @@ static time_info get_time() noexcept struct OutputDebugStreamA : public std::ostream { // Use the file buffer from DebugFile - OutputDebugStreamA( const std::shared_ptr& stream ) + OutputDebugStreamA( const std::shared_ptr &stream ) : std::ostream( &buf ), buf( stream->rdbuf() ) {} // Intercept stream operations @@ -650,11 +650,11 @@ struct OutputDebugStreamA : public std::ostream { virtual int overflow( int c ) override { if( EOF != c ) { int rc = buf->sputc( c ); - if ( std::iscntrl(c) ) { + if( std::iscntrl( c ) ) { send(); } else { output_string.push_back( c ); - if (output_string.size() >= max) { + if( output_string.size() >= max ) { send(); } } @@ -665,30 +665,32 @@ struct OutputDebugStreamA : public std::ostream { } virtual std::streamsize xsputn( const char *s, std::streamsize n ) override { std::streamsize rc = buf->sputn( s, n ), last = 0, i = 0; - for(; i < n; ++i) { - if( std::iscntrl(s[i]) ) { - if(i == last+1) { // Skip multiple empty lines + for( ; i < n; ++i ) { + if( std::iscntrl( s[i] ) ) { + if( i == last + 1 ) { // Skip multiple empty lines last = i; continue; } - const std::string sv(s + last, i - last); + const std::string sv( s + last, i - last ); last = i; - send(sv.c_str()); + send( sv.c_str() ); } } std::string append( s + last, n - last ); // Skip if only made of multiple newlines - if (none_of( append.begin(), append.end(), [](int c) { return std::iscntrl(c); })) { + if( none_of( append.begin(), append.end(), []( int c ) { + return std::iscntrl( c ); + } ) ) { output_string.append( s + last, n - last ); } - if (output_string.size() >= max) { + if( output_string.size() >= max ) { send(); } return rc; } private: - void send(const char *s = nullptr) { - if (s == nullptr) { + void send( const char *s = nullptr ) { + if( s == nullptr ) { ::OutputDebugStringA( output_string.c_str() ); output_string.clear(); } else { @@ -707,11 +709,10 @@ struct DebugFile { ~DebugFile(); void init( DebugOutput, const cata_path &filename ); std::ostream &get_file(); - static DebugFile& instance() { + static DebugFile &instance() { static DebugFile instance; return instance; }; - // Using shared_ptr for the type-erased deleter support, not because // it needs to be shared. std::shared_ptr file = std::make_shared(); From 9a845684154f58ee21ff612fc00e574b8b488720 Mon Sep 17 00:00:00 2001 From: alef Date: Thu, 2 Jan 2025 20:10:29 +0100 Subject: [PATCH 17/19] Remove unused variable --- src/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.cpp b/src/debug.cpp index a3d10adc70ca8..3020927b54cf8 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -649,7 +649,7 @@ struct OutputDebugStreamA : public std::ostream { protected: virtual int overflow( int c ) override { if( EOF != c ) { - int rc = buf->sputc( c ); + buf->sputc( c ); if( std::iscntrl( c ) ) { send(); } else { From e85438c85a70ac6a1c008111880e3e4d45c91bf2 Mon Sep 17 00:00:00 2001 From: alef Date: Thu, 2 Jan 2025 20:13:00 +0100 Subject: [PATCH 18/19] Remove access specifiers and reformat --- src/debug.cpp | 96 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 3020927b54cf8..3e1a700627bf3 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -643,64 +643,62 @@ struct OutputDebugStreamA : public std::ostream { // Intercept stream operations struct _Buf : public std::streambuf { - _Buf( std::streambuf *buf ) : buf( buf ) { - output_string.reserve( max ); - } - protected: - virtual int overflow( int c ) override { - if( EOF != c ) { - buf->sputc( c ); - if( std::iscntrl( c ) ) { + _Buf( std::streambuf *buf ) : buf( buf ) { + output_string.reserve( max ); + } + virtual int overflow( int c ) override { + if( EOF != c ) { + buf->sputc( c ); + if( std::iscntrl( c ) ) { + send(); + } else { + output_string.push_back( c ); + if( output_string.size() >= max ) { send(); - } else { - output_string.push_back( c ); - if( output_string.size() >= max ) { - send(); - } } - } else { - send(); } - return c; + } else { + send(); } - virtual std::streamsize xsputn( const char *s, std::streamsize n ) override { - std::streamsize rc = buf->sputn( s, n ), last = 0, i = 0; - for( ; i < n; ++i ) { - if( std::iscntrl( s[i] ) ) { - if( i == last + 1 ) { // Skip multiple empty lines - last = i; - continue; - } - const std::string sv( s + last, i - last ); + return c; + } + virtual std::streamsize xsputn( const char *s, std::streamsize n ) override { + std::streamsize rc = buf->sputn( s, n ), last = 0, i = 0; + for( ; i < n; ++i ) { + if( std::iscntrl( s[i] ) ) { + if( i == last + 1 ) { // Skip multiple empty lines last = i; - send( sv.c_str() ); + continue; } + const std::string sv( s + last, i - last ); + last = i; + send( sv.c_str() ); } - std::string append( s + last, n - last ); - // Skip if only made of multiple newlines - if( none_of( append.begin(), append.end(), []( int c ) { - return std::iscntrl( c ); - } ) ) { - output_string.append( s + last, n - last ); - } - if( output_string.size() >= max ) { - send(); - } - return rc; } - private: - void send( const char *s = nullptr ) { - if( s == nullptr ) { - ::OutputDebugStringA( output_string.c_str() ); - output_string.clear(); - } else { - ::OutputDebugStringA( s ); - } - buf->pubsync(); + std::string append( s + last, n - last ); + // Skip if only made of multiple newlines + if( none_of( append.begin(), append.end(), []( int c ) { + return std::iscntrl( c ); + } ) ) { + output_string.append( s + last, n - last ); + } + if( output_string.size() >= max ) { + send(); } - static constexpr std::streamsize max = 4096; - std::string output_string{}; - std::streambuf *buf = nullptr; + return rc; + } + void send( const char *s = nullptr ) { + if( s == nullptr ) { + ::OutputDebugStringA( output_string.c_str() ); + output_string.clear(); + } else { + ::OutputDebugStringA( s ); + } + buf->pubsync(); + } + static constexpr std::streamsize max = 4096; + std::string output_string{}; + std::streambuf *buf = nullptr; } buf; }; #endif From f9619cb57899627fe00dd1fd1dd4c4db021ca4ff Mon Sep 17 00:00:00 2001 From: alef Date: Wed, 29 Jan 2025 23:17:55 +0100 Subject: [PATCH 19/19] Use std::filesystem --- src/debug.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debug.cpp b/src/debug.cpp index 3e1a700627bf3..7783b226174e5 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -750,6 +750,7 @@ void DebugFile::init( DebugOutput output_mode, const cata_path &filename ) case DebugOutput::file: { this->filename = filename; // Continue with the old log file if it's smaller than 1 MiB + namespace fs = std::filesystem; if( fs::file_size( fs::path( filename ) ) >= 1024 * 1024 ) { std::error_code ec; fs::rename( fs::path( filename ), fs::path( oldfile ), ec );