Compare commits

...

2 Commits

Author SHA1 Message Date
798a9dd9b1 WIP: support command-line redirection of stdout/stderr 2023-08-29 13:06:46 +02:00
fe1e056196 ENH: support change of stream for ISstream, OSstream (#1880)
- allows, for example, rebinding of the output stream to a file
2023-08-29 13:06:43 +02:00
15 changed files with 468 additions and 76 deletions

View File

@ -5,6 +5,7 @@ global/globals.C
/* global/JobInfo/JobInfo.C in globals.C */ /* global/JobInfo/JobInfo.C in globals.C */
global/argList/argList.C global/argList/argList.C
global/argList/argListHelp.C global/argList/argListHelp.C
global/argList/argListRedirect.C
global/clock/clock.C global/clock/clock.C
global/clockValue/clockValue.C global/clockValue/clockValue.C
global/cpuTime/cpuTimeCxx.C global/cpuTime/cpuTimeCxx.C

View File

@ -35,6 +35,27 @@ License
Foam::fileName Foam::IOstream::staticName_("stream"); Foam::fileName Foam::IOstream::staticName_("stream");
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::IOstream::attach(const std::ios& s)
{
labelByteSize_ = sizeof(label);
scalarByteSize_ = sizeof(scalar);
lineNumber_ = 0;
if (s.good())
{
setOpened();
setGood();
}
else
{
setClosed();
setState(s.rdstate());
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::fileName& Foam::IOstream::name() const const Foam::fileName& Foam::IOstream::name() const

View File

@ -157,6 +157,9 @@ protected:
ioState_ = std::ios_base::goodbit; ioState_ = std::ios_base::goodbit;
} }
//- Adjustments when attaching a new stream
void attach(const std::ios& s);
public: public:

View File

@ -723,7 +723,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
// readScalar determine the validity // readScalar determine the validity
while while
( (
is_.get(c) is_->get(c)
&& ( && (
isdigit(c) isdigit(c)
|| c == '+' || c == '+'
@ -758,13 +758,13 @@ Foam::Istream& Foam::ISstream::read(token& t)
syncState(); syncState();
if (is_.bad()) if (is_->bad())
{ {
t.setBad(); t.setBad();
} }
else else
{ {
is_.putback(c); is_->putback(c);
if (nChar == 1 && buf[0] == '-') if (nChar == 1 && buf[0] == '-')
{ {
@ -1009,7 +1009,7 @@ Foam::Istream& Foam::ISstream::read(string& str)
Foam::Istream& Foam::ISstream::read(label& val) Foam::Istream& Foam::ISstream::read(label& val)
{ {
is_ >> val; (*is_) >> val;
syncState(); syncState();
return *this; return *this;
} }
@ -1017,7 +1017,7 @@ Foam::Istream& Foam::ISstream::read(label& val)
Foam::Istream& Foam::ISstream::read(float& val) Foam::Istream& Foam::ISstream::read(float& val)
{ {
is_ >> val; (*is_) >> val;
syncState(); syncState();
return *this; return *this;
} }
@ -1025,7 +1025,7 @@ Foam::Istream& Foam::ISstream::read(float& val)
Foam::Istream& Foam::ISstream::read(double& val) Foam::Istream& Foam::ISstream::read(double& val)
{ {
is_ >> val; (*is_) >> val;
syncState(); syncState();
return *this; return *this;
} }
@ -1047,24 +1047,11 @@ Foam::Istream& Foam::ISstream::readRaw(char* data, std::streamsize count)
{ {
if (data) if (data)
{ {
is_.read(data, count); is_->read(data, count);
} }
else else
{ {
// Forward seek is_->ignore(count);
// - use absolute positioning (see C++ notes about std::ifstream)
is_.seekg(is_.tellg() + std::istream::pos_type(count));
// Not sure if this is needed (as per rewind)
// some documentation indicates that ifstream needs
// seekg with values from a tellg
//
// stdStream().rdbuf()->pubseekpos
// (
// count,
// std::ios_base::seekdir::cur,
// std::ios_base::in
// );
} }
} }
syncState(); syncState();
@ -1083,7 +1070,7 @@ bool Foam::ISstream::beginRawRead()
readBegin("binaryBlock"); readBegin("binaryBlock");
syncState(); syncState();
return is_.good(); return is_->good();
} }
@ -1091,7 +1078,7 @@ bool Foam::ISstream::endRawRead()
{ {
readEnd("binaryBlock"); readEnd("binaryBlock");
syncState(); syncState();
return is_.good(); return is_->good();
} }

View File

@ -61,7 +61,7 @@ class ISstream
fileName name_; fileName name_;
std::istream& is_; std::istream* is_;
// Private Member Functions // Private Member Functions
@ -135,10 +135,10 @@ public:
// STL stream // STL stream
//- Const access to underlying std::istream //- Const access to underlying std::istream
virtual const std::istream& stdStream() const { return is_; } virtual const std::istream& stdStream() const { return *is_; }
//- Access to underlying std::istream //- Access to underlying std::istream
virtual std::istream& stdStream() { return is_; } virtual std::istream& stdStream() { return *is_; }
// Stream State // Stream State
@ -146,19 +146,19 @@ public:
//- Return flags of output stream //- Return flags of output stream
virtual ios_base::fmtflags flags() const virtual ios_base::fmtflags flags() const
{ {
return is_.flags(); return is_->flags();
} }
//- Set stream flags //- Set stream flags
virtual ios_base::fmtflags flags(const ios_base::fmtflags f) virtual ios_base::fmtflags flags(const ios_base::fmtflags f)
{ {
return is_.flags(f); return is_->flags(f);
} }
//- Set stream state to match that of the std::istream //- Set stream state to match that of the std::istream
void syncState() void syncState()
{ {
setState(is_.rdstate()); setState(is_->rdstate());
} }
@ -180,6 +180,10 @@ public:
const bool stripComments = true const bool stripComments = true
); );
//- Associate a different std::istream with the ISstream
// \return the previously attached stream
inline std::istream& attach(std::istream& is);
// Read Functions // Read Functions

View File

@ -37,9 +37,9 @@ inline Foam::ISstream::ISstream
: :
Istream(streamOpt), Istream(streamOpt),
name_(streamName), name_(streamName),
is_(is) is_(&is)
{ {
if (is_.good()) if (is_->good())
{ {
setOpened(); setOpened();
setGood(); setGood();
@ -53,9 +53,20 @@ inline Foam::ISstream::ISstream
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
inline std::istream& Foam::ISstream::attach(std::istream& is)
{
std::istream* old = is_;
is_ = &is;
IOstream::attach(*is_);
return *old;
}
inline Foam::ISstream& Foam::ISstream::get(char& c) inline Foam::ISstream& Foam::ISstream::get(char& c)
{ {
is_.get(c); is_->get(c);
syncState(); syncState();
if (c == '\n' && good()) if (c == '\n' && good())
@ -69,13 +80,13 @@ inline Foam::ISstream& Foam::ISstream::get(char& c)
inline int Foam::ISstream::peek() inline int Foam::ISstream::peek()
{ {
return is_.peek(); return is_->peek();
} }
inline Foam::ISstream& Foam::ISstream::getLine(std::string& str, char delim) inline Foam::ISstream& Foam::ISstream::getLine(std::string& str, char delim)
{ {
std::getline(is_, str, delim); std::getline(*is_, str, delim);
syncState(); syncState();
if (delim == '\n') if (delim == '\n')
@ -89,10 +100,10 @@ inline Foam::ISstream& Foam::ISstream::getLine(std::string& str, char delim)
inline std::streamsize Foam::ISstream::getLine(std::nullptr_t, char delim) inline std::streamsize Foam::ISstream::getLine(std::nullptr_t, char delim)
{ {
is_.ignore(std::numeric_limits<std::streamsize>::max(), delim); is_->ignore(std::numeric_limits<std::streamsize>::max(), delim);
syncState(); syncState();
std::streamsize count = is_.gcount(); std::streamsize count = is_->gcount();
if (delim == '\n' && count) if (delim == '\n' && count)
{ {
@ -110,7 +121,7 @@ inline Foam::ISstream& Foam::ISstream::putback(const char c)
--lineNumber_; --lineNumber_;
} }
if (!is_.putback(c)) if (!is_->putback(c))
{ {
setBad(); setBad();
} }

View File

@ -88,7 +88,7 @@ bool Foam::OSstream::write(const token& tok)
Foam::Ostream& Foam::OSstream::write(const char c) Foam::Ostream& Foam::OSstream::write(const char c)
{ {
os_ << c; (*os_) << c;
if (c == token::NL) if (c == token::NL)
{ {
++lineNumber_; ++lineNumber_;
@ -101,7 +101,7 @@ Foam::Ostream& Foam::OSstream::write(const char c)
Foam::Ostream& Foam::OSstream::write(const char* str) Foam::Ostream& Foam::OSstream::write(const char* str)
{ {
lineNumber_ += stringOps::count(str, token::NL); lineNumber_ += stringOps::count(str, token::NL);
os_ << str; (*os_) << str;
syncState(); syncState();
return *this; return *this;
} }
@ -109,7 +109,7 @@ Foam::Ostream& Foam::OSstream::write(const char* str)
Foam::Ostream& Foam::OSstream::write(const word& str) Foam::Ostream& Foam::OSstream::write(const word& str)
{ {
os_ << str; (*os_) << str;
syncState(); syncState();
return *this; return *this;
} }
@ -125,7 +125,7 @@ Foam::Ostream& Foam::OSstream::writeQuoted
{ {
// Output unquoted, only advance line number on newline // Output unquoted, only advance line number on newline
lineNumber_ += stringOps::count(str, token::NL); lineNumber_ += stringOps::count(str, token::NL);
os_ << str; (*os_) << str;
syncState(); syncState();
return *this; return *this;
@ -133,7 +133,7 @@ Foam::Ostream& Foam::OSstream::writeQuoted
// Output with surrounding quotes and backslash escaping // Output with surrounding quotes and backslash escaping
os_ << token::DQUOTE; (*os_) << token::DQUOTE;
unsigned backslash = 0; unsigned backslash = 0;
for (auto iter = str.cbegin(); iter != str.cend(); ++iter) for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
@ -158,16 +158,16 @@ Foam::Ostream& Foam::OSstream::writeQuoted
// output all pending backslashes // output all pending backslashes
while (backslash) while (backslash)
{ {
os_ << '\\'; (*os_) << '\\';
--backslash; --backslash;
} }
os_ << c; (*os_) << c;
} }
// silently drop any trailing backslashes // silently drop any trailing backslashes
// they would otherwise appear like an escaped end-quote // they would otherwise appear like an escaped end-quote
os_ << token::DQUOTE; (*os_) << token::DQUOTE;
syncState(); syncState();
return *this; return *this;
@ -182,7 +182,7 @@ Foam::Ostream& Foam::OSstream::write(const string& str)
Foam::Ostream& Foam::OSstream::write(const int32_t val) Foam::Ostream& Foam::OSstream::write(const int32_t val)
{ {
os_ << val; (*os_) << val;
syncState(); syncState();
return *this; return *this;
} }
@ -190,7 +190,7 @@ Foam::Ostream& Foam::OSstream::write(const int32_t val)
Foam::Ostream& Foam::OSstream::write(const int64_t val) Foam::Ostream& Foam::OSstream::write(const int64_t val)
{ {
os_ << val; (*os_) << val;
syncState(); syncState();
return *this; return *this;
} }
@ -198,7 +198,7 @@ Foam::Ostream& Foam::OSstream::write(const int64_t val)
Foam::Ostream& Foam::OSstream::write(const float val) Foam::Ostream& Foam::OSstream::write(const float val)
{ {
os_ << val; (*os_) << val;
syncState(); syncState();
return *this; return *this;
} }
@ -206,7 +206,7 @@ Foam::Ostream& Foam::OSstream::write(const float val)
Foam::Ostream& Foam::OSstream::write(const double val) Foam::Ostream& Foam::OSstream::write(const double val)
{ {
os_ << val; (*os_) << val;
syncState(); syncState();
return *this; return *this;
} }
@ -231,17 +231,18 @@ bool Foam::OSstream::beginRawWrite(std::streamsize count)
<< abort(FatalIOError); << abort(FatalIOError);
} }
os_ << token::BEGIN_LIST; (*os_) << token::BEGIN_LIST;
syncState(); syncState();
return os_.good();
return os_->good();
} }
bool Foam::OSstream::endRawWrite() bool Foam::OSstream::endRawWrite()
{ {
os_ << token::END_LIST; (*os_) << token::END_LIST;
syncState(); syncState();
return os_.good(); return os_->good();
} }
@ -254,8 +255,9 @@ Foam::Ostream& Foam::OSstream::writeRaw
// No check for IOstreamOption::BINARY since this is either done in the // No check for IOstreamOption::BINARY since this is either done in the
// beginRawWrite() method, or the caller knows what they are doing. // beginRawWrite() method, or the caller knows what they are doing.
os_.write(data, count); os_->write(data, count);
syncState(); syncState();
return *this; return *this;
} }
@ -264,7 +266,7 @@ void Foam::OSstream::indent()
{ {
for (unsigned short i = 0; i < indentLevel_*indentSize_; ++i) for (unsigned short i = 0; i < indentLevel_*indentSize_; ++i)
{ {
os_ << ' '; (*os_) << ' ';
} }
syncState(); syncState();
} }
@ -272,14 +274,14 @@ void Foam::OSstream::indent()
void Foam::OSstream::flush() void Foam::OSstream::flush()
{ {
os_.flush(); os_->flush();
} }
void Foam::OSstream::endl() void Foam::OSstream::endl()
{ {
write('\n'); write('\n');
os_.flush(); os_->flush();
} }
@ -287,37 +289,37 @@ void Foam::OSstream::endl()
char Foam::OSstream::fill() const char Foam::OSstream::fill() const
{ {
return os_.fill(); return os_->fill();
} }
char Foam::OSstream::fill(const char fillch) char Foam::OSstream::fill(const char fillch)
{ {
return os_.fill(fillch); return os_->fill(fillch);
} }
int Foam::OSstream::width() const int Foam::OSstream::width() const
{ {
return os_.width(); return os_->width();
} }
int Foam::OSstream::width(const int w) int Foam::OSstream::width(const int w)
{ {
return os_.width(w); return os_->width(w);
} }
int Foam::OSstream::precision() const int Foam::OSstream::precision() const
{ {
return os_.precision(); return os_->precision();
} }
int Foam::OSstream::precision(const int p) int Foam::OSstream::precision(const int p)
{ {
return os_.precision(p); return os_->precision(p);
} }

View File

@ -60,7 +60,7 @@ class OSstream
fileName name_; fileName name_;
std::ostream& os_; std::ostream* os_;
public: public:
@ -123,10 +123,10 @@ public:
// STL stream // STL stream
//- Const access to underlying std::ostream //- Const access to underlying std::ostream
virtual const std::ostream& stdStream() const { return os_; } virtual const std::ostream& stdStream() const { return *os_; }
//- Access to underlying std::ostream //- Access to underlying std::ostream
virtual std::ostream& stdStream() { return os_; } virtual std::ostream& stdStream() { return *os_; }
// Stream State // Stream State
@ -134,21 +134,25 @@ public:
//- Get stream flags //- Get stream flags
virtual ios_base::fmtflags flags() const virtual ios_base::fmtflags flags() const
{ {
return os_.flags(); return os_->flags();
} }
//- Set stream flags //- Set stream flags
virtual ios_base::fmtflags flags(const ios_base::fmtflags f) virtual ios_base::fmtflags flags(const ios_base::fmtflags f)
{ {
return os_.flags(f); return os_->flags(f);
} }
//- Set stream state to match that of the std::ostream //- Set stream state to match that of the std::ostream
void syncState() void syncState()
{ {
setState(os_.rdstate()); setState(os_->rdstate());
} }
//- Associate a different std::ostream with the OSstream
// \return the previously attached stream
inline std::ostream& attach(std::ostream& os);
// Write Functions // Write Functions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2020-2022 OpenCFD Ltd. Copyright (C) 2020-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -39,13 +39,13 @@ inline Foam::OSstream::OSstream
: :
Ostream(streamOpt), Ostream(streamOpt),
name_(streamName), name_(streamName),
os_(os) os_(&os)
{ {
if (os_.good()) if (os_->good())
{ {
setOpened(); setOpened();
setGood(); setGood();
os_.precision(precision_); os_->precision(precision_);
} }
else else
{ {
@ -54,4 +54,18 @@ inline Foam::OSstream::OSstream
} }
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline std::ostream& Foam::OSstream::attach(std::ostream& os)
{
std::ostream* old = os_;
os_ = &os;
IOstream::attach(*os_);
// Leave precision untouched
return *old;
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2020-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -38,7 +39,14 @@ void Foam::ISstream::print(Ostream& os) const
os << "ISstream: " << name().c_str() << ' '; os << "ISstream: " << name().c_str() << ' ';
IOstream::print(os); IOstream::print(os);
IOstream::print(os, is_.rdstate()); if (is_)
{
IOstream::print(os, is_->rdstate());
}
else
{
os << "std::stream not attached" << endl;
}
} }
@ -47,7 +55,14 @@ void Foam::OSstream::print(Ostream& os) const
os << "OSstream: " << name().c_str() << ' '; os << "OSstream: " << name().c_str() << ' ';
IOstream::print(os); IOstream::print(os);
IOstream::print(os, os_.rdstate()); if (os_)
{
IOstream::print(os, os_->rdstate());
}
else
{
os << "std::stream not attached" << endl;
}
} }

View File

@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "argList.H" #include "argList.H"
#include "argListRedirect.H"
#include "OSspecific.H" #include "OSspecific.H"
#include "Switch.H" #include "Switch.H"
#include "clock.H" #include "clock.H"
@ -47,6 +48,7 @@ License
#include "stringListOps.H" #include "stringListOps.H"
#include "fileOperation.H" #include "fileOperation.H"
#include "fileOperationInitialise.H" #include "fileOperationInitialise.H"
#include "fstreamPointer.H"
#include <cctype> #include <cctype>
@ -911,7 +913,9 @@ Foam::argList::argList
runControl_(), runControl_(),
args_(argc), args_(argc),
options_(argc), options_(argc),
libs_() libs_(),
stdout_(nullptr),
stderr_(nullptr)
{ {
// Pre-scan for some options needed for initial setup: // Pre-scan for some options needed for initial setup:
// -fileHandler (takes an argument) // -fileHandler (takes an argument)
@ -1018,6 +1022,53 @@ Foam::argList::argList
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Capture stdout/stderr redirection names. Filters argv
Detail::redirectOutputs redirects(argc, argv);
// Perform output redirection
if (redirects.active())
{
word suffix;
if (redirects.ranks_ && parRunControl_.parRun())
{
suffix = Foam::name(Pstream::myProcNo());
}
if (!redirects.stdout_.empty())
{
fileName file(fileName::validate(redirects.stdout_));
file.ext(suffix);
stdout_.reset(ofstreamPointer(file).release());
}
if (!redirects.stderr_.empty())
{
fileName file(fileName::validate(redirects.stderr_));
file.ext(suffix);
stderr_.reset(ofstreamPointer(file).release());
}
if (stdout_)
{
Sout.attach(*stdout_);
Pout.attach(*stdout_);
}
if (stderr_)
{
Serr.attach(*stderr_);
Perr.attach(*stderr_);
}
else if (redirects.join_)
{
Serr.attach(Sout.stdStream());
Perr.attach(Sout.stdStream());
}
}
// Convert argv -> args_ and capture ( ... ) lists // Convert argv -> args_ and capture ( ... ) lists
regroupArgv(argc, argv); regroupArgv(argc, argv);
@ -1172,6 +1223,8 @@ Foam::argList::argList
args_(args.args_), args_(args.args_),
options_(options), options_(options),
libs_(), libs_(),
stdout_(nullptr),
stderr_(nullptr),
executable_(args.executable_), executable_(args.executable_),
rootPath_(args.rootPath_), rootPath_(args.rootPath_),
globalCase_(args.globalCase_), globalCase_(args.globalCase_),

View File

@ -146,6 +146,12 @@ class argList
//- Additional libraries //- Additional libraries
mutable dlLibraryTable libs_; mutable dlLibraryTable libs_;
//- File redirection for stdout (Sout, Pout)
std::unique_ptr<std::ostream> stdout_;
//- File redirection for stderr (Serr, Perr)
std::unique_ptr<std::ostream> stderr_;
word executable_; word executable_;
fileName rootPath_; fileName rootPath_;
fileName globalCase_; fileName globalCase_;

View File

@ -425,6 +425,16 @@ void Foam::argList::printUsage(bool full) const
} }
// Redirections
if (full)
{
printOption("stdout <file>", "Redirect stdout to file");
printOption("stderr <file>", "Redirect stderr to file");
printOption("join-stderr", "Join stderr to stdout");
printOption("append-rank", "Append stdout/stderr files with MPI-rank");
}
// Place documentation/help options at the end // Place documentation/help options at the end
printOption("doc", "Display documentation in browser"); printOption("doc", "Display documentation in browser");

View File

@ -0,0 +1,175 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "argListRedirect.H"
#include "IOstreams.H"
#include "boolList.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace
{
inline bool opt_join(const char* optName)
{
return strcmp(optName, "join-stderr") == 0;
}
inline bool opt_rank(const char* optName)
{
return strcmp(optName, "append-rank") == 0;
}
inline bool opt_stderr(const char* optName)
{
return strcmp(optName, "stderr") == 0;
}
inline bool opt_stdout(const char* optName)
{
return strcmp(optName, "stdout") == 0;
}
} // End anonymous namespace
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::Detail::redirectOutputs::redirectOutputs(int& argc, char**& argv)
:
stdout_(),
stderr_(),
join_(false),
ranks_(false)
{
List<bool> skip(label(argc), false);
bool filter = false;
for (int argi = 1; argi < argc-1; ++argi)
{
if (argv[argi][0] == '-')
{
const char *optName = &argv[argi][1];
if (opt_join(optName))
{
join_ = true;
filter = true;
skip[argi] = true;
}
else if (opt_rank(optName))
{
ranks_ = true;
filter = true;
skip[argi] = true;
}
else if (opt_stdout(optName))
{
stdout_ = argv[argi+1];
filter = true;
skip[argi] = true;
skip[argi+1] = true;
++argi;
}
else if (opt_stderr(optName))
{
stderr_ = argv[argi+1];
filter = true;
skip[argi] = true;
skip[argi+1] = true;
++argi;
}
}
}
// Test final arg separately
{
const int argi = argc-1;
if (argi > 0 && argv[argi][0] == '-')
{
const char *optName = &argv[argi][1];
if (opt_join(optName))
{
join_ = true;
filter = true;
skip[argi] = true;
}
else if (opt_rank(optName))
{
ranks_ = true;
filter = true;
skip[argi] = true;
}
}
}
if (filter)
{
int nArgs = 1;
for (int argi = 1; argi < argc; ++argi)
{
if (!skip[argi])
{
argv[nArgs] = argv[argi];
++nArgs;
}
}
argc = nArgs;
}
// Resolve potential conflicts
if (!stderr_.empty())
{
if (stdout_.empty())
{
join_ = false;
}
else if (stdout_ == stderr_)
{
join_ = true;
stderr_.clear();
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::Detail::redirectOutputs::active() const
{
return join_ || !stdout_.empty() || !stderr_.empty();
}
// ************************************************************************* //

View File

@ -0,0 +1,86 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::Detail::redirectOutputs
Description
Helper class for redirecting outputs from within argList.
Handles the following options:
\verbatim
-stdout <file>
-stderr <file>
-join-stderr
-append-rank
\endverbatim
Note
Not intended for general use
SourceFiles
argListRedirect.C
\*---------------------------------------------------------------------------*/
#ifndef argListRedirect_H
#define argListRedirect_H
#include "string.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class redirectOutputs Declaration
\*---------------------------------------------------------------------------*/
struct redirectOutputs
{
string stdout_;
string stderr_;
bool join_;
bool ranks_;
redirectOutputs(int& argc, char**& argv);
bool active() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Detail
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //