Skip to content

Commit 5860e95

Browse files
authored
Fix missing C stderr output (fprintf(stderr, ...) not shown) (#402)
1 parent 9a4af34 commit 5860e95

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

src/xinterpreter.cpp

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,22 @@ using namespace std::placeholders;
5656
namespace xcpp
5757
{
5858
struct StreamRedirectRAII {
59-
std::string &err;
60-
StreamRedirectRAII(std::string &e) : err(e) {
61-
Cpp::BeginStdStreamCapture(Cpp::kStdErr);
62-
Cpp::BeginStdStreamCapture(Cpp::kStdOut);
63-
}
64-
~StreamRedirectRAII() {
65-
std::string out = Cpp::EndStdStreamCapture();
66-
err = Cpp::EndStdStreamCapture();
67-
std::cout << out;
68-
}
59+
std::string& out;
60+
std::string& err;
61+
62+
StreamRedirectRAII(std::string& o, std::string& e)
63+
: out(o)
64+
, err(e)
65+
{
66+
Cpp::BeginStdStreamCapture(Cpp::kStdOut);
67+
Cpp::BeginStdStreamCapture(Cpp::kStdErr);
68+
}
69+
70+
~StreamRedirectRAII()
71+
{
72+
err = Cpp::EndStdStreamCapture();
73+
out = Cpp::EndStdStreamCapture();
74+
}
6975
};
7076

7177
void interpreter::configure_impl()
@@ -163,11 +169,12 @@ __get_cxx_version ()
163169
}
164170

165171
std::string err;
172+
std::string out;
166173

167174
// Attempt normal evaluation
168175
try
169176
{
170-
StreamRedirectRAII R(err);
177+
StreamRedirectRAII R(out, err);
171178
compilation_result = Cpp::Process(code.c_str());
172179
}
173180
catch (std::exception& e)
@@ -182,11 +189,12 @@ __get_cxx_version ()
182189
ename = "Error: ";
183190
}
184191

185-
if (compilation_result)
192+
if (!out.empty())
193+
{
194+
std::cout << out;
195+
}
196+
if (!err.empty())
186197
{
187-
errorlevel = 1;
188-
ename = "Error: ";
189-
evalue = "Compilation error! " + err;
190198
std::cerr << err;
191199
}
192200

@@ -201,6 +209,13 @@ __get_cxx_version ()
201209
std::cerr.rdbuf(cerr_strbuf);
202210
}
203211

212+
if (compilation_result)
213+
{
214+
errorlevel = 1;
215+
ename = "Error: ";
216+
evalue = "Compilation error! " + err;
217+
}
218+
204219
// Depending of error level, publish execution result or execution
205220
// error, and compose execute_reply message.
206221
if (errorlevel)

test/test_interpreter.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,3 +1094,45 @@ TEST_SUITE("mime_bundle_repr")
10941094
REQUIRE(res == expected);
10951095
}
10961096
}
1097+
1098+
TEST_CASE("C and C++ stdout/stderr capture")
1099+
{
1100+
std::vector<const char*> Args = {};
1101+
xcpp::interpreter interpreter((int)Args.size(), Args.data());
1102+
1103+
xeus::execute_request_config config;
1104+
config.silent = false;
1105+
config.store_history = false;
1106+
config.allow_stdin = false;
1107+
1108+
nl::json header = nl::json::object();
1109+
xeus::xrequest_context::guid_list id = {};
1110+
xeus::xrequest_context context(header, id);
1111+
1112+
std::promise<nl::json> promise;
1113+
auto callback = [&promise](nl::json result) { promise.set_value(result); };
1114+
1115+
// Redirect std::cout and std::cerr
1116+
StreamRedirectRAII cout_redirect(std::cout);
1117+
StreamRedirectRAII cerr_redirect(std::cerr);
1118+
1119+
std::string code = R"(
1120+
#include <stdio.h>
1121+
#include <iostream>
1122+
printf("C stdout\n");
1123+
fprintf(stderr, "C stderr\n");
1124+
std::cout << "C++ stdout\n";
1125+
std::cerr << "C++ stderr\n";
1126+
)";
1127+
1128+
interpreter.execute_request(context, callback, code, config, nl::json::object());
1129+
(void)promise.get_future().get(); // wait for result
1130+
1131+
std::string captured_out = cout_redirect.getCaptured();
1132+
std::string captured_err = cerr_redirect.getCaptured();
1133+
1134+
REQUIRE(captured_out.find("C stdout") != std::string::npos);
1135+
REQUIRE(captured_out.find("C++ stdout") != std::string::npos);
1136+
REQUIRE(captured_err.find("C stderr") != std::string::npos);
1137+
REQUIRE(captured_err.find("C++ stderr") != std::string::npos);
1138+
}

0 commit comments

Comments
 (0)