diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index d08e7dde6e0e28bcb1fa30d8b0dbdb2d1188266c..9e905b056665086f57191cc2e4ae12be59162d9d 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -5,6 +5,7 @@ global/globals.C /* global/JobInfo/JobInfo.C in globals.C */ global/argList/argList.C global/argList/argListHelp.C +global/argList/argListRedirect.C global/clock/clock.C global/clockValue/clockValue.C global/cpuTime/cpuTimeCxx.C diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C index 6ded4cec85d5268aa737e2b7e7f8c479b6c0a4cd..c0c91d858657dd912c485711226f042717fac542 100644 --- a/src/OpenFOAM/global/argList/argList.C +++ b/src/OpenFOAM/global/argList/argList.C @@ -27,6 +27,7 @@ License \*---------------------------------------------------------------------------*/ #include "argList.H" +#include "argListRedirect.H" #include "OSspecific.H" #include "Switch.H" #include "clock.H" @@ -47,6 +48,7 @@ License #include "stringListOps.H" #include "fileOperation.H" #include "fileOperationInitialise.H" +#include "fstreamPointer.H" #include <cctype> @@ -911,7 +913,9 @@ Foam::argList::argList runControl_(), args_(argc), options_(argc), - libs_() + libs_(), + stdout_(nullptr), + stderr_(nullptr) { // Pre-scan for some options needed for initial setup: // -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 regroupArgv(argc, argv); @@ -1172,6 +1223,8 @@ Foam::argList::argList args_(args.args_), options_(options), libs_(), + stdout_(nullptr), + stderr_(nullptr), executable_(args.executable_), rootPath_(args.rootPath_), globalCase_(args.globalCase_), diff --git a/src/OpenFOAM/global/argList/argList.H b/src/OpenFOAM/global/argList/argList.H index 0b0efa5844b2a103df969c0631b43b0c50d10eca..6ab381ee617ed32c83b0cb8a877890fef3eb4d86 100644 --- a/src/OpenFOAM/global/argList/argList.H +++ b/src/OpenFOAM/global/argList/argList.H @@ -146,6 +146,12 @@ class argList //- Additional libraries 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_; fileName rootPath_; fileName globalCase_; diff --git a/src/OpenFOAM/global/argList/argListHelp.C b/src/OpenFOAM/global/argList/argListHelp.C index 042e4297343dd41c1eb4b5e71436f7141f35a3aa..9bd82f22939cf0539c320a2a5a89d4aff6bb089a 100644 --- a/src/OpenFOAM/global/argList/argListHelp.C +++ b/src/OpenFOAM/global/argList/argListHelp.C @@ -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 printOption("doc", "Display documentation in browser"); diff --git a/src/OpenFOAM/global/argList/argListRedirect.C b/src/OpenFOAM/global/argList/argListRedirect.C new file mode 100644 index 0000000000000000000000000000000000000000..157e04b7332feb208e79a6a4d8531dacf60dd03a --- /dev/null +++ b/src/OpenFOAM/global/argList/argListRedirect.C @@ -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(); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/global/argList/argListRedirect.H b/src/OpenFOAM/global/argList/argListRedirect.H new file mode 100644 index 0000000000000000000000000000000000000000..5c78cd4f532653991911570a3c7d61c8dc00060d --- /dev/null +++ b/src/OpenFOAM/global/argList/argListRedirect.H @@ -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 + +// ************************************************************************* //