stdout: never write to std::cout directly (MB #5041)

Cmdline and SyncContext standard output should always go
through a variable that can be pointed towards the actual
output channel.

Cmdline already had m_out for that, but it wasn't used
everywhere. Fixed.

SyncContext now has setOutput()/getOutput() and that is
used in SyncContext.cpp. It is not set anywhere yet.

To catch incorrect use of cout or cerr inside SyncEvolution,
the SyncEvo namespace defines its own cout and cerr which cannot
be used like std::cout/cerr, thus triggering compiler
errors. Use "std::cout/cerr" when necessary.
This commit is contained in:
Patrick Ohly 2010-03-26 09:53:27 +01:00
parent c2633cf5d2
commit c7aa99e5b2
6 changed files with 61 additions and 26 deletions

View file

@ -604,13 +604,13 @@ bool Cmdline::run() {
if (first) {
first = false;
} else if(!m_quiet) {
cout << endl;
m_out << endl;
}
cout << dir << endl;
m_out << dir << endl;
if (!m_quiet) {
SyncReport report;
context->readSessionInfo(dir, report);
cout << report;
m_out << report;
}
}
} else if (!m_restore.empty()) {
@ -2516,7 +2516,7 @@ private:
success = m_cmdline->parse() &&
m_cmdline->run();
if (m_err.str().size()) {
cout << endl << m_err.str();
m_out << endl << m_err.str();
}
CPPUNIT_ASSERT(success);
}

View file

@ -147,8 +147,14 @@ SyncContext::SyncContext(const string &server,
m_doLogging = doLogging;
}
void SyncContext::setOutput(ostream *out)
{
m_out = out ? out : &std::cout;
}
void SyncContext::init()
{
m_out = &std::cout;
m_doLogging = false;
m_quiet = false;
m_dryrun = false;
@ -1174,6 +1180,7 @@ public:
m_logdir.previousLogdirs(dirs);
}
ostream &out = m_client.getOutput();
BOOST_FOREACH(SyncSource *source, *this) {
if ((!excludeSource.empty() && excludeSource != source->getName()) ||
(newSuffix == "after" && m_prepared.find(source->getName()) == m_prepared.end())) {
@ -1182,7 +1189,7 @@ public:
// dump only if not done before or changed
if (m_intro != intro) {
cout << intro;
m_client.getOutput() << intro;
m_intro = intro;
}
@ -1209,22 +1216,22 @@ public:
oldDir = databaseName(*source, oldSuffix, oldSession);
}
string newDir = databaseName(*source, newSuffix);
cout << "*** " << source->getName() << " ***\n" << flush;
out << "*** " << source->getName() << " ***\n" << flush;
string cmd = string("env CLIENT_TEST_COMPARISON_FAILED=10 " + config + " synccompare 2>/dev/null '" ) +
oldDir + "' '" + newDir + "'";
int ret = system(cmd.c_str());
switch (ret == -1 ? ret : WEXITSTATUS(ret)) {
case 0:
cout << "no changes\n";
out << "no changes\n";
break;
case 10:
break;
default:
cout << "Comparison was impossible.\n";
out << "Comparison was impossible.\n";
break;
}
}
cout << "\n";
out << "\n";
return true;
}
@ -1276,28 +1283,28 @@ public:
m_reportTodo = false;
string logfile = m_logdir.getLogfile();
cout << flush;
cerr << flush;
cout << "\n";
ostream &out = m_client.getOutput();
out << flush;
out << "\n";
if (status == STATUS_OK) {
cout << "Synchronization successful.\n";
out << "Synchronization successful.\n";
} else if (logfile.size()) {
cout << "Synchronization failed, see "
<< logfile
<< " for details.\n";
out << "Synchronization failed, see "
<< logfile
<< " for details.\n";
} else {
cout << "Synchronization failed.\n";
out << "Synchronization failed.\n";
}
// pretty-print report
if (m_logLevel > LOGGING_QUIET) {
cout << "\nChanges applied during synchronization:\n";
out << "\nChanges applied during synchronization:\n";
}
if (m_logLevel > LOGGING_QUIET && report) {
cout << *report;
out << *report;
std::string slowSync = report->slowSyncExplanation(m_client.getPeer());
if (!slowSync.empty()) {
cout << endl << slowSync;
out << endl << slowSync;
}
}
@ -3575,9 +3582,10 @@ void SyncContext::status()
Exception::handle();
}
} else {
cout << "Previous log directory not found.\n";
ostream &out = getOutput();
out << "Previous log directory not found.\n";
if (!getLogDir() || !getLogDir()[0]) {
cout << "Enable the 'logdir' option and synchronize to use this feature.\n";
out << "Enable the 'logdir' option and synchronize to use this feature.\n";
}
}
}

View file

@ -178,6 +178,13 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
bool doLogging = false);
~SyncContext();
/**
* Output channel to be used by this context. NULL means "use std::cout", the default.
* Owned by caller, must remain valid as long as SyncContext exists.
*/
void setOutput(ostream *out);
ostream &getOutput() const { return *m_out; }
bool getQuiet() { return m_quiet; }
void setQuiet(bool quiet) { m_quiet = quiet; }
@ -733,6 +740,9 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
//It can be used to report infomation about a sync is successfully started.
bool m_firstSourceAccess;
// output stream to be used by this context, never NULL (uses cout as fallback)
ostream *m_out;
public:
static bool transport_cb (void *data);
void setTransportCallback(int seconds);

View file

@ -28,4 +28,21 @@
#define SE_BEGIN_CXX namespace SyncEvo {
#define SE_END_CXX }
SE_BEGIN_CXX
/*
* SyncEvolution should never use standard IO directly. Either use the
* logging facilities or use variables that point towards the real
* output channels. In particular the command line code then can be
* run as pointing towards real std::cout, a string stream, or redirected
* via D-Bus.
*
* These dummy declarations trip up code inside SyncEvo namespace or using it
* which use plain "cout << something" after a "using namespace std".
* They don't help catching code which references std::cout.
*/
struct DontUseStandardIO;
extern DontUseStandardIO *cout;
extern DontUseStandardIO *cerr;
SE_END_CXX
#endif /** INCL_DECLARATIONS */

View file

@ -138,7 +138,7 @@ int main( int argc, char **argv )
* libs, therefore it would get suppressed (logged at
* level DEVELOPER, while output is at most INFO)
*/
KeyringSyncCmdline cmdline(argc, argv, cout, cout);
KeyringSyncCmdline cmdline(argc, argv, std::cout, std::cout);
if (cmdline.parse() &&
cmdline.run()) {
return 0;

View file

@ -125,7 +125,7 @@ public:
void startTest (CppUnit::Test *test) {
m_currentTest = test->getName();
cerr << m_currentTest;
std::cerr << m_currentTest;
string logfile = m_currentTest + ".log";
simplifyFilename(logfile);
m_logger.reset(new LoggerStdout(logfile));
@ -190,9 +190,9 @@ public:
}
}
cerr << " " << result << "\n";
std::cerr << " " << result << "\n";
if (!failure.empty()) {
cerr << failure << "\n";
std::cerr << failure << "\n";
}
}