/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_commandline
*/
+#include "gmxpre.h"
+
#include "cmdlinemodulemanager.h"
#include <cstdio>
#include <string>
#include <utility>
-#include "gromacs/legacyheaders/copyrite.h"
-#include "gromacs/legacyheaders/network.h"
-
#include "gromacs/commandline/cmdlinehelpcontext.h"
-#include "gromacs/commandline/cmdlinehelpmodule.h"
+#include "gromacs/commandline/cmdlineinit.h"
#include "gromacs/commandline/cmdlinemodule.h"
-#include "gromacs/commandline/cmdlinemodulemanager-impl.h"
#include "gromacs/commandline/cmdlineparser.h"
+#include "gromacs/commandline/cmdlineprogramcontext.h"
+#include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/math/utilities.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
+#include "gromacs/utility/basenetwork.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/futil.h"
#include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/init.h"
-#include "gromacs/utility/programinfo.h"
#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/sysinfo.h"
-// For GMX_BINARY_SUFFIX
-#include "config.h"
+#include "cmdlinehelpmodule.h"
+#include "cmdlinemodulemanager-impl.h"
namespace gmx
{
namespace
{
+//! \addtogroup module_commandline
+//! \{
+
/********************************************************************
* CMainCommandLineModule
*/
-/*! \internal \brief
- * Implements a CommandLineModuleInterface, given a function with C/C++ main()
+/*! \brief
+ * Implements a ICommandLineModule, given a function with C/C++ main()
* signature.
- *
- * \ingroup module_commandline
*/
-class CMainCommandLineModule : public CommandLineModuleInterface
+class CMainCommandLineModule : public ICommandLineModule
{
public:
//! \copydoc gmx::CommandLineModuleManager::CMainFunction
return shortDescription_;
}
+ virtual void init(CommandLineModuleSettings * /*settings*/)
+ {
+ }
virtual int run(int argc, char *argv[])
{
return mainFunction_(argc, argv);
}
virtual void writeHelp(const CommandLineHelpContext &context) const
{
- char *argv[2];
- int argc = 1;
- // TODO: The constness should not be cast away.
- argv[0] = const_cast<char *>(name_);
- argv[1] = NULL;
- GlobalCommandLineHelpContext global(context);
- mainFunction_(argc, argv);
+ writeCommandLineHelpCMain(context, name_, mainFunction_);
}
private:
const char *name_;
const char *shortDescription_;
CMainFunction mainFunction_;
-
};
+//! \}
+
} // namespace
+/********************************************************************
+ * CommandLineCommonOptionsHolder
+ */
+
+CommandLineCommonOptionsHolder::CommandLineCommonOptionsHolder()
+ : options_(NULL, NULL), bHelp_(false), bHidden_(false),
+ bQuiet_(false), bVersion_(false), bCopyright_(true),
+ niceLevel_(19), bNiceSet_(false), bBackup_(true), bFpexcept_(false),
+ debugLevel_(0)
+{
+ binaryInfoSettings_.copyright(true);
+}
+
+CommandLineCommonOptionsHolder::~CommandLineCommonOptionsHolder()
+{
+}
+
+void CommandLineCommonOptionsHolder::initOptions()
+{
+ options_.addOption(BooleanOption("h").store(&bHelp_)
+ .description("Print help and quit"));
+ options_.addOption(BooleanOption("hidden").store(&bHidden_)
+ .hidden()
+ .description("Show hidden options in help"));
+ options_.addOption(BooleanOption("quiet").store(&bQuiet_)
+ .description("Do not print common startup info or quotes"));
+ options_.addOption(BooleanOption("version").store(&bVersion_)
+ .description("Print extended version information and quit"));
+ options_.addOption(BooleanOption("copyright").store(&bCopyright_)
+ .description("Print copyright information on startup"));
+ options_.addOption(IntegerOption("nice").store(&niceLevel_).storeIsSet(&bNiceSet_)
+ .description("Set the nicelevel (default depends on command)"));
+ options_.addOption(BooleanOption("backup").store(&bBackup_)
+ .description("Write backups if output files exist"));
+ options_.addOption(BooleanOption("fpexcept").store(&bFpexcept_)
+ .hidden().description("Enable floating-point exceptions"));
+ options_.addOption(IntegerOption("debug").store(&debugLevel_)
+ .hidden().defaultValueIfSet(1)
+ .description("Write file with debug information, "
+ "1: short (default), 2: also x and f"));
+}
+
+bool CommandLineCommonOptionsHolder::finishOptions()
+{
+ options_.finish();
+ binaryInfoSettings_.extendedInfo(bVersion_);
+ // The latter condition suppresses the copyright with
+ // -quiet -version.
+ binaryInfoSettings_.copyright(bCopyright_ && !bQuiet_);
+ return !bVersion_;
+}
+
+void CommandLineCommonOptionsHolder::adjustFromSettings(
+ const CommandLineModuleSettings &settings)
+{
+ if (!bNiceSet_)
+ {
+ niceLevel_ = settings.defaultNiceLevel();
+ }
+}
+
/********************************************************************
* CommandLineModuleManager::Impl
*/
/*! \brief
* Initializes the implementation class.
*
- * \param[in] binaryName Name of the running binary
+ * \param[in] binaryName Name of the running binary
* (without Gromacs binary suffix or .exe on Windows).
- * \param programInfo Program information for the running binary.
+ * \param programContext Program information for the running binary.
*/
- Impl(const char *binaryName, ProgramInfo *programInfo);
+ Impl(const char *binaryName, CommandLineProgramContext *programContext);
/*! \brief
* Helper method that adds a given module to the module manager.
*/
CommandLineModuleMap::const_iterator
findModuleByName(const std::string &name) const;
- /*! \brief
- * Finds a module that the name of the binary.
- *
- * \param[in] programInfo Program information object to use.
- * \throws std::bad_alloc if out of memory.
- * \returns Iterator to the found module, or
- * \c modules_.end() if not found.
- *
- * Checks whether the program is invoked through a symlink whose name
- * is different from \a binaryName_, and if so, checks
- * if a module name matches the name of the symlink.
- *
- * Note that the \p programInfo parameter is currently not necessary
- * (as the program info object is also contained as a member), but it
- * clarifies the control flow.
- */
- CommandLineModuleMap::const_iterator
- findModuleFromBinaryName(const ProgramInfo &programInfo) const;
/*! \brief
* Processes command-line options for the wrapper binary.
*
- * \param[in,out] argc On input, argc passed to run().
+ * \param[in,out] optionsHolder Common options.
+ * \param[in,out] argc On input, argc passed to run().
* On output, argc to be passed to the module.
- * \param[in,out] argv On input, argv passed to run().
+ * \param[in,out] argv On input, argv passed to run().
* On output, argv to be passed to the module.
* \throws InvalidInputError if there are invalid options.
* \returns The module that should be run.
* options). Also finds the module that should be run and the
* arguments that should be passed to it.
*/
- CommandLineModuleInterface *
- processCommonOptions(int *argc, char ***argv);
+ ICommandLineModule *
+ processCommonOptions(CommandLineCommonOptionsHolder *optionsHolder,
+ int *argc, char ***argv);
/*! \brief
* Maps module names to module objects.
*/
CommandLineModuleGroupList moduleGroups_;
//! Information about the currently running program.
- ProgramInfo &programInfo_;
+ CommandLineProgramContext &programContext_;
//! Name of the binary.
std::string binaryName_;
/*! \brief
* The pointed module is owned by the \a modules_ container.
*/
CommandLineHelpModule *helpModule_;
- //! Settings for what to write in the startup header.
- BinaryInformationSettings binaryInfoSettings_;
//! If non-NULL, run this module in single-module mode.
- CommandLineModuleInterface *singleModule_;
- //! Whether all stderr output should be suppressed.
+ ICommandLineModule *singleModule_;
+ //! Stores the value set with setQuiet().
bool bQuiet_;
- //! Whether to write the startup information to stdout iso stderr.
- bool bStdOutInfo_;
private:
GMX_DISALLOW_COPY_AND_ASSIGN(Impl);
};
-CommandLineModuleManager::Impl::Impl(const char *binaryName,
- ProgramInfo *programInfo)
- : programInfo_(*programInfo),
+CommandLineModuleManager::Impl::Impl(const char *binaryName,
+ CommandLineProgramContext *programContext)
+ : programContext_(*programContext),
binaryName_(binaryName != NULL ? binaryName : ""),
helpModule_(NULL), singleModule_(NULL),
- bQuiet_(false), bStdOutInfo_(false)
+ bQuiet_(false)
{
- binaryInfoSettings_.copyright(true);
+ GMX_RELEASE_ASSERT(binaryName_.find('-') == std::string::npos,
+ "Help export does not currently work with binary names with dashes");
}
void CommandLineModuleManager::Impl::addModule(CommandLineModulePointer module)
HelpTopicPointer helpTopic(helpModule_->createModuleHelpTopic(*module));
modules_.insert(std::make_pair(std::string(module->name()),
move(module)));
- helpModule_->addTopic(move(helpTopic));
+ helpModule_->addTopic(move(helpTopic), false);
}
void CommandLineModuleManager::Impl::ensureHelpModuleExists()
{
if (helpModule_ == NULL)
{
- helpModule_ = new CommandLineHelpModule(programInfo_, binaryName_,
+ helpModule_ = new CommandLineHelpModule(programContext_, binaryName_,
modules_, moduleGroups_);
addModule(CommandLineModulePointer(helpModule_));
}
return modules_.find(name);
}
-CommandLineModuleMap::const_iterator
-CommandLineModuleManager::Impl::findModuleFromBinaryName(
- const ProgramInfo &programInfo) const
-{
- std::string moduleName = programInfo.programName();
-#ifdef GMX_BINARY_SUFFIX
- moduleName = stripSuffixIfPresent(moduleName, GMX_BINARY_SUFFIX);
-#endif
- if (moduleName == binaryName_)
- {
- return modules_.end();
- }
- if (startsWith(moduleName, "g_"))
- {
- moduleName.erase(0, 2);
- }
- if (startsWith(moduleName, "gmx"))
- {
- moduleName.erase(0, 3);
- }
- return findModuleByName(moduleName);
-}
-
-CommandLineModuleInterface *
-CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
+ICommandLineModule *
+CommandLineModuleManager::Impl::processCommonOptions(
+ CommandLineCommonOptionsHolder *optionsHolder, int *argc, char ***argv)
{
// Check if we are directly invoking a certain module.
- CommandLineModuleInterface *module = singleModule_;
- if (module == NULL)
- {
- // Also check for invokation through named symlinks.
- CommandLineModuleMap::const_iterator moduleIter
- = findModuleFromBinaryName(programInfo_);
- if (moduleIter != modules_.end())
- {
- module = moduleIter->second.get();
- }
- }
+ ICommandLineModule *module = singleModule_;
- bool bHelp = false;
- bool bHidden = false;
- bool bVersion = false;
- bool bCopyright = true;
- // TODO: Print the common options into the help.
// TODO: It would be nice to propagate at least the -quiet option to
// the modules so that they can also be quiet in response to this.
- Options options(NULL, NULL);
- options.addOption(BooleanOption("h").store(&bHelp));
- options.addOption(BooleanOption("hidden").store(&bHidden));
- options.addOption(BooleanOption("quiet").store(&bQuiet_));
- options.addOption(BooleanOption("version").store(&bVersion));
- options.addOption(BooleanOption("copyright").store(&bCopyright));
if (module == NULL)
{
}
if (argcForWrapper > 1)
{
- CommandLineParser(&options).parse(&argcForWrapper, *argv);
+ CommandLineParser(optionsHolder->options())
+ .parse(&argcForWrapper, *argv);
}
// If no action requested and there is a module specified, process it.
- if (argcForWrapper < *argc && !bHelp && !bVersion)
+ if (argcForWrapper < *argc && !optionsHolder->shouldIgnoreActualModule())
{
const char *moduleName = (*argv)[argcForWrapper];
CommandLineModuleMap::const_iterator moduleIter
{
if (singleModule_ == NULL)
{
- programInfo_.setDisplayName(binaryName_ + " " + module->name());
+ programContext_.setDisplayName(binaryName_ + " " + module->name());
}
// Recognize the common options also after the module name.
// TODO: It could be nicer to only recognize -h/-hidden if module is not
// null.
- CommandLineParser(&options).skipUnknown(true).parse(argc, *argv);
+ CommandLineParser(optionsHolder->options())
+ .skipUnknown(true).parse(argc, *argv);
}
- options.finish();
- binaryInfoSettings_.extendedInfo(bVersion);
- binaryInfoSettings_.copyright(bCopyright);
- if (bVersion)
+ if (!optionsHolder->finishOptions())
{
- bQuiet_ = false;
- bStdOutInfo_ = true;
return NULL;
}
// If no module specified and no other action, show the help.
// Also explicitly specifying -h for the wrapper binary goes here.
- if (module == NULL || bHelp)
+ if (module == NULL || optionsHolder->shouldShowHelp())
{
ensureHelpModuleExists();
if (module != NULL)
}
if (module == helpModule_)
{
- helpModule_->setShowHidden(bHidden);
+ helpModule_->setShowHidden(optionsHolder->shouldShowHidden());
}
return module;
}
* CommandLineModuleManager
*/
-CommandLineModuleManager::CommandLineModuleManager(const char *binaryName,
- ProgramInfo *programInfo)
- : impl_(new Impl(binaryName, programInfo))
+CommandLineModuleManager::CommandLineModuleManager(
+ const char *binaryName, CommandLineProgramContext *programContext)
+ : impl_(new Impl(binaryName, programContext))
{
}
impl_->bQuiet_ = bQuiet;
}
-void CommandLineModuleManager::setSingleModule(CommandLineModuleInterface *module)
+void CommandLineModuleManager::setOutputRedirector(
+ IFileOutputRedirector *output)
+{
+ impl_->ensureHelpModuleExists();
+ impl_->helpModule_->setOutputRedirector(output);
+}
+
+void CommandLineModuleManager::setSingleModule(ICommandLineModule *module)
{
impl_->singleModule_ = module;
}
void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
{
impl_->ensureHelpModuleExists();
- impl_->helpModule_->addTopic(move(topic));
+ impl_->helpModule_->addTopic(move(topic), true);
}
int CommandLineModuleManager::run(int argc, char *argv[])
{
- CommandLineModuleInterface *module;
- const bool bMaster = (!gmx_mpi_initialized() || gmx_node_rank() == 0);
+ ICommandLineModule *module;
+ const bool bMaster = (gmx_node_rank() == 0);
+ bool bQuiet = impl_->bQuiet_ || !bMaster;
+ CommandLineCommonOptionsHolder optionsHolder;
try
{
- module = impl_->processCommonOptions(&argc, &argv);
+ optionsHolder.initOptions();
+ module = impl_->processCommonOptions(&optionsHolder, &argc, &argv);
}
catch (const std::exception &)
{
- if (bMaster && !impl_->bQuiet_)
+ bQuiet |= optionsHolder.shouldBeQuiet();
+ if (!bQuiet)
{
- printBinaryInformation(stderr, impl_->programInfo_,
- impl_->binaryInfoSettings_);
+ printBinaryInformation(stderr, impl_->programContext_,
+ optionsHolder.binaryInfoSettings());
}
throw;
}
- if (!bMaster)
- {
- impl_->bQuiet_ = true;
- }
- if (!impl_->bQuiet_)
+ bQuiet |= optionsHolder.shouldBeQuiet();
+ if (!bQuiet)
{
- FILE *out = (impl_->bStdOutInfo_ ? stdout : stderr);
- printBinaryInformation(out, impl_->programInfo_,
- impl_->binaryInfoSettings_);
+ FILE *out = optionsHolder.startupInfoFile();
+ printBinaryInformation(out, impl_->programContext_,
+ optionsHolder.binaryInfoSettings());
fprintf(out, "\n");
}
if (module == NULL)
{
return 0;
}
- int rc = module->run(argc, argv);
- if (!impl_->bQuiet_)
+
+ CommandLineModuleSettings settings;
+ module->init(&settings);
+ optionsHolder.adjustFromSettings(settings);
+
+ gmx_set_max_backup_count(optionsHolder.shouldBackup() ? -1 : 0);
+
+ // Open the debug file.
+ if (optionsHolder.debugLevel() > 0)
+ {
+ std::string filename(impl_->programContext_.programName());
+ if (gmx_node_num() > 1)
+ {
+ filename.append(formatString("%d", gmx_node_rank()));
+ }
+ filename.append(".debug");
+
+ fprintf(stderr, "Will write debug log file: %s\n", filename.c_str());
+ gmx_init_debug(optionsHolder.debugLevel(), filename.c_str());
+ }
+ // Set the nice level unless disabled in the configuration.
+ if (optionsHolder.niceLevel() != 0)
+ {
+ static bool bNiceSet = false; // Only set it once.
+ if (!bNiceSet)
+ {
+ // TODO: Diagnostic if this fails and the user explicitly requested it.
+ gmx_set_nice(optionsHolder.niceLevel());
+ bNiceSet = true;
+ }
+ }
+ if (optionsHolder.enableFPExceptions())
+ {
+ //TODO: currently it is always enabled for mdrun (verlet) and tests.
+ gmx_feenableexcept();
+ }
+
+ int rc = 0;
+ if (!(module == impl_->helpModule_ && !bMaster))
+ {
+ rc = module->run(argc, argv);
+ }
+ if (!bQuiet)
{
gmx_thanx(stderr);
}
// static
int CommandLineModuleManager::runAsMainSingleModule(
- int argc, char *argv[], CommandLineModuleInterface *module)
+ int argc, char *argv[], ICommandLineModule *module)
{
- ProgramInfo &programInfo = gmx::init(&argc, &argv);
+ CommandLineProgramContext &programContext = gmx::initForCommandLine(&argc, &argv);
try
{
- CommandLineModuleManager manager(NULL, &programInfo);
+ CommandLineModuleManager manager(NULL, &programContext);
manager.setSingleModule(module);
int rc = manager.run(argc, argv);
- gmx::finalize();
+ gmx::finalizeForCommandLine();
return rc;
}
catch (const std::exception &ex)
{
printFatalErrorMessage(stderr, ex);
- return processExceptionAtExit(ex);
+ return processExceptionAtExitForCommandLine(ex);
}
}