From 1000fb9948e1fdeb56ae68271d8f299565958669 Mon Sep 17 00:00:00 2001 From: anutosh491 Date: Thu, 6 Nov 2025 18:37:23 +0530 Subject: [PATCH 1/3] Fix missing C stderr output (fprintf(stderr, ...) not shown) --- src/xinterpreter.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index 14972324..843424e5 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -56,15 +56,17 @@ using namespace std::placeholders; namespace xcpp { struct StreamRedirectRAII { + std::string &out; std::string &err; - StreamRedirectRAII(std::string &e) : err(e) { - Cpp::BeginStdStreamCapture(Cpp::kStdErr); + StreamRedirectRAII(std::string &o, std::string &e) + : out(o), err(e) + { Cpp::BeginStdStreamCapture(Cpp::kStdOut); + Cpp::BeginStdStreamCapture(Cpp::kStdErr); } ~StreamRedirectRAII() { - std::string out = Cpp::EndStdStreamCapture(); err = Cpp::EndStdStreamCapture(); - std::cout << out; + out = Cpp::EndStdStreamCapture(); } }; @@ -163,11 +165,12 @@ __get_cxx_version () } std::string err; + std::string out; // Attempt normal evaluation try { - StreamRedirectRAII R(err); + StreamRedirectRAII R(out, err); compilation_result = Cpp::Process(code.c_str()); } catch (std::exception& e) @@ -182,13 +185,8 @@ __get_cxx_version () ename = "Error: "; } - if (compilation_result) - { - errorlevel = 1; - ename = "Error: "; - evalue = "Compilation error! " + err; - std::cerr << err; - } + if (!out.empty()) std::cout << out; + if (!err.empty()) std::cerr << err; // Flush streams std::cout << std::flush; @@ -201,6 +199,13 @@ __get_cxx_version () std::cerr.rdbuf(cerr_strbuf); } + if (compilation_result) + { + errorlevel = 1; + ename = "Error: "; + evalue = "Compilation error! " + err; + } + // Depending of error level, publish execution result or execution // error, and compose execute_reply message. if (errorlevel) From 7af61ac4cd0dfe6084e6d639cc04ffec17dc0ef0 Mon Sep 17 00:00:00 2001 From: anutosh491 Date: Fri, 7 Nov 2025 15:47:25 +0530 Subject: [PATCH 2/3] Add tests --- test/test_interpreter.cpp | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/test_interpreter.cpp b/test/test_interpreter.cpp index cfb0d7d5..5ce9d540 100644 --- a/test/test_interpreter.cpp +++ b/test/test_interpreter.cpp @@ -1094,3 +1094,45 @@ TEST_SUITE("mime_bundle_repr") REQUIRE(res == expected); } } + +TEST_CASE("C and C++ stdout/stderr capture") +{ + std::vector Args = {}; + xcpp::interpreter interpreter((int)Args.size(), Args.data()); + + xeus::execute_request_config config; + config.silent = false; + config.store_history = false; + config.allow_stdin = false; + + nl::json header = nl::json::object(); + xeus::xrequest_context::guid_list id = {}; + xeus::xrequest_context context(header, id); + + std::promise promise; + auto callback = [&promise](nl::json result) { promise.set_value(result); }; + + // Redirect std::cout and std::cerr + StreamRedirectRAII cout_redirect(std::cout); + StreamRedirectRAII cerr_redirect(std::cerr); + + std::string code = R"( + #include + #include + printf("C stdout\n"); + fprintf(stderr, "C stderr\n"); + std::cout << "C++ stdout\n"; + std::cerr << "C++ stderr\n"; + )"; + + interpreter.execute_request(context, callback, code, config, nl::json::object()); + (void)promise.get_future().get(); // wait for result + + std::string captured_out = cout_redirect.getCaptured(); + std::string captured_err = cerr_redirect.getCaptured(); + + REQUIRE(captured_out.find("C stdout") != std::string::npos); + REQUIRE(captured_out.find("C++ stdout") != std::string::npos); + REQUIRE(captured_err.find("C stderr") != std::string::npos); + REQUIRE(captured_err.find("C++ stderr") != std::string::npos); +} From 10d66935a0f131003ba71c97c89d0f3c89bc0708 Mon Sep 17 00:00:00 2001 From: anutosh491 Date: Fri, 7 Nov 2025 15:52:59 +0530 Subject: [PATCH 3/3] satisfy clang format --- src/xinterpreter.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index 843424e5..15d6861b 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -56,18 +56,22 @@ using namespace std::placeholders; namespace xcpp { struct StreamRedirectRAII { - std::string &out; - std::string &err; - StreamRedirectRAII(std::string &o, std::string &e) - : out(o), err(e) - { - Cpp::BeginStdStreamCapture(Cpp::kStdOut); - Cpp::BeginStdStreamCapture(Cpp::kStdErr); - } - ~StreamRedirectRAII() { - err = Cpp::EndStdStreamCapture(); - out = Cpp::EndStdStreamCapture(); - } + std::string& out; + std::string& err; + + StreamRedirectRAII(std::string& o, std::string& e) + : out(o) + , err(e) + { + Cpp::BeginStdStreamCapture(Cpp::kStdOut); + Cpp::BeginStdStreamCapture(Cpp::kStdErr); + } + + ~StreamRedirectRAII() + { + err = Cpp::EndStdStreamCapture(); + out = Cpp::EndStdStreamCapture(); + } }; void interpreter::configure_impl() @@ -185,8 +189,14 @@ __get_cxx_version () ename = "Error: "; } - if (!out.empty()) std::cout << out; - if (!err.empty()) std::cerr << err; + if (!out.empty()) + { + std::cout << out; + } + if (!err.empty()) + { + std::cerr << err; + } // Flush streams std::cout << std::flush;