2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013, by the GROMACS development team, led by
5 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6 * others, as listed in the AUTHORS file in the top-level source
7 * directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Implements gmx::CommandLineModuleManager.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
42 #include "cmdlinemodulemanager.h"
51 #include <boost/scoped_ptr.hpp>
53 #include "gromacs/legacyheaders/copyrite.h"
54 #include "gromacs/legacyheaders/network.h"
55 #include "gromacs/legacyheaders/smalloc.h"
57 #include "gromacs/commandline/cmdlinehelpcontext.h"
58 #include "gromacs/commandline/cmdlinemodule.h"
59 #include "gromacs/commandline/cmdlineparser.h"
60 #include "gromacs/fileio/futil.h"
61 #include "gromacs/onlinehelp/helpformat.h"
62 #include "gromacs/onlinehelp/helpmanager.h"
63 #include "gromacs/onlinehelp/helptopic.h"
64 #include "gromacs/onlinehelp/helpwritercontext.h"
65 #include "gromacs/options/basicoptions.h"
66 #include "gromacs/options/options.h"
67 #include "gromacs/utility/exceptions.h"
68 #include "gromacs/utility/file.h"
69 #include "gromacs/utility/gmxassert.h"
70 #include "gromacs/utility/init.h"
71 #include "gromacs/utility/programinfo.h"
72 #include "gromacs/utility/stringutil.h"
77 //! Container type for mapping module names to module objects.
78 typedef std::map<std::string, CommandLineModulePointer> CommandLineModuleMap;
80 class CommandLineHelpModule;
85 /********************************************************************
91 static const char name[];
92 static const char title[];
93 static const char *const text[];
96 // The first two are not used.
97 const char RootHelpText::name[] = "";
98 const char RootHelpText::title[] = "";
99 const char *const RootHelpText::text[] = {
100 "Usage: [PROGRAM] <command> [<args>]",
104 * Help topic that forms the root of the help tree for the help subcommand.
106 * \ingroup module_commandline
108 class RootHelpTopic : public CompositeHelpTopic<RootHelpText>
112 * Creates a root help topic.
114 * \param[in] modules List of modules for to use for module listings.
118 explicit RootHelpTopic(const CommandLineModuleMap &modules)
123 virtual void writeHelp(const HelpWriterContext &context) const;
126 void printModuleList(const HelpWriterContext &context) const;
128 const CommandLineModuleMap &modules_;
130 GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
133 void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
135 if (context.outputFormat() != eHelpOutputFormat_Console)
137 // TODO: Implement once the situation with Redmine issue #969 is more
139 GMX_THROW(NotImplementedError(
140 "Root help is not implemented for this output format"));
142 writeBasicHelpTopic(context, *this, helpText());
143 // TODO: If/when this list becomes long, it may be better to only print
144 // "common" commands here, and have a separate topic (e.g.,
145 // "help commands") that prints the full list.
146 printModuleList(context);
147 context.writeTextBlock(
148 "For additional help on a command, use '[PROGRAM] help <command>'");
149 writeSubTopicList(context,
150 "\nAdditional help is available on the following topics:");
151 context.writeTextBlock(
152 "To access the help, use '[PROGRAM] help <topic>'.");
155 void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
157 if (context.outputFormat() != eHelpOutputFormat_Console)
159 // TODO: Implement once the situation with Redmine issue #969 is more
161 GMX_THROW(NotImplementedError(
162 "Module list is not implemented for this output format"));
164 int maxNameLength = 0;
165 CommandLineModuleMap::const_iterator module;
166 for (module = modules_.begin(); module != modules_.end(); ++module)
168 int nameLength = static_cast<int>(module->first.length());
169 if (module->second->shortDescription() != NULL
170 && nameLength > maxNameLength)
172 maxNameLength = nameLength;
175 File &file = context.outputFile();
176 TextTableFormatter formatter;
177 formatter.addColumn(NULL, maxNameLength + 1, false);
178 formatter.addColumn(NULL, 72 - maxNameLength, true);
179 formatter.setFirstColumnIndent(4);
181 file.writeLine("Available commands:");
182 for (module = modules_.begin(); module != modules_.end(); ++module)
184 const char *name = module->first.c_str();
185 const char *description = module->second->shortDescription();
186 if (description != NULL)
189 formatter.addColumnLine(0, name);
190 formatter.addColumnLine(1, description);
191 file.writeString(formatter.formatRow());
196 /********************************************************************
197 * ModuleHelpTopic declaration
201 * Help topic wrapper for a command-line module.
203 * This class implements HelpTopicInterface such that it wraps a
204 * CommandLineModuleInterface, allowing subcommand "help <command>"
205 * to produce the help for "<command>".
207 * \ingroup module_commandline
209 class ModuleHelpTopic : public HelpTopicInterface
212 //! Constructs a help topic for a specific module.
213 ModuleHelpTopic(const CommandLineModuleInterface &module,
214 const CommandLineHelpModule &helpModule)
215 : module_(module), helpModule_(helpModule)
219 virtual const char *name() const { return module_.name(); }
220 virtual const char *title() const { return NULL; }
221 virtual bool hasSubTopics() const { return false; }
222 virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
226 virtual void writeHelp(const HelpWriterContext &context) const;
229 const CommandLineModuleInterface &module_;
230 const CommandLineHelpModule &helpModule_;
232 GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
235 /********************************************************************
236 * HelpExportInterface
240 * Callbacks for exporting help information for command-line modules.
242 * \ingroup module_commandline
244 class HelpExportInterface
247 virtual ~HelpExportInterface() {};
250 * Called once before exporting individual modules.
252 * Can, e.g., open shared output files (e.g., if the output is written
253 * into a single file, or if a separate index is required) and write
256 virtual void startModuleExport() = 0;
258 * Called to export the help for each module.
260 * \param[in] tag Unique tag for the module (gmx-something).
261 * \param[in] module Module for which the help should be exported.
263 virtual void exportModuleHelp(const std::string &tag,
264 const CommandLineModuleInterface &module) = 0;
266 * Called after all modules have been exported.
268 * Can close files opened in startModuleExport(), write footers to them
271 virtual void finishModuleExport() = 0;
274 /********************************************************************
279 * Implements export for man pages.
281 * \ingroup module_commandline
283 class HelpExportMan : public HelpExportInterface
286 virtual void startModuleExport() {}
287 virtual void exportModuleHelp(const std::string &tag,
288 const CommandLineModuleInterface &module);
289 virtual void finishModuleExport() {}
292 void HelpExportMan::exportModuleHelp(const std::string &tag,
293 const CommandLineModuleInterface &module)
295 File file("man1/" + tag + ".1", "w");
297 // TODO: It would be nice to remove the VERSION prefix from the version
298 // string to make it shorter.
299 file.writeLine(formatString(".TH %s 1 \"\" \"%s\" \"GROMACS Manual\"\n",
302 file.writeLine(".SH NAME");
303 file.writeLine(formatString("%s - %s", tag.c_str(),
304 module.shortDescription()));
307 CommandLineHelpContext context(&file, eHelpOutputFormat_Man);
308 std::string displayName(tag);
309 std::replace(displayName.begin(), displayName.end(), '-', ' ');
310 context.setModuleDisplayName(displayName);
311 module.writeHelp(context);
313 file.writeLine(".SH SEE ALSO");
314 file.writeLine(".BR gromacs(7)");
316 file.writeLine("More information about \\fBGROMACS\\fR is available at <\\fIhttp://www.gromacs.org/\\fR>.");
319 /********************************************************************
324 * Implements export for HTML help.
326 * \ingroup module_commandline
328 class HelpExportHtml : public HelpExportInterface
333 virtual void startModuleExport();
334 virtual void exportModuleHelp(const std::string &tag,
335 const CommandLineModuleInterface &module);
336 virtual void finishModuleExport();
339 void writeHtmlHeader(File *file, const std::string &title) const;
340 void writeHtmlFooter(File *file) const;
342 boost::scoped_ptr<File> byNameFile_;
346 HelpExportHtml::HelpExportHtml()
348 char *linksFilename = low_gmxlibfn("links.dat", FALSE, FALSE);
349 if (linksFilename != NULL)
351 scoped_ptr_sfree guard(linksFilename);
352 File linksFile(linksFilename, "r");
354 while (linksFile.readLine(&line))
356 links_.addLink(line, "../online/" + line);
361 void HelpExportHtml::startModuleExport()
363 byNameFile_.reset(new File("byname.html", "w"));
364 writeHtmlHeader(byNameFile_.get(), "GROMACS Programs by Name");
365 byNameFile_->writeLine("<H3>GROMACS Programs Alphabetically</H3>");
368 void HelpExportHtml::exportModuleHelp(const std::string &tag,
369 const CommandLineModuleInterface &module)
371 File file(tag + ".html", "w");
372 writeHtmlHeader(&file, tag);
374 CommandLineHelpContext context(&file, eHelpOutputFormat_Html);
375 std::string displayName(tag);
376 std::replace(displayName.begin(), displayName.end(), '-', ' ');
377 context.setModuleDisplayName(displayName);
378 context.setLinks(links_);
379 module.writeHelp(context);
381 writeHtmlFooter(&file);
384 byNameFile_->writeLine(formatString("<a href=\"%s.html\">%s</a> - %s<br>",
385 tag.c_str(), displayName.c_str(),
386 module.shortDescription()));
389 void HelpExportHtml::finishModuleExport()
391 writeHtmlFooter(byNameFile_.get());
392 byNameFile_->close();
395 void HelpExportHtml::writeHtmlHeader(File *file, const std::string &title) const
397 file->writeLine("<HTML>");
398 file->writeLine("<HEAD>");
399 file->writeLine(formatString("<TITLE>%s</TITLE>", title.c_str()));
400 file->writeLine("<LINK rel=stylesheet href=\"../online/style.css\" type=\"text/css\">");
401 file->writeLine("<BODY text=\"#000000\" bgcolor=\"#FFFFFF\" link=\"#0000FF\" vlink=\"#990000\" alink=\"#FF0000\">");
402 file->writeLine("<TABLE WIDTH=\"98%%\" NOBORDER><TR>");
403 file->writeLine("<TD WIDTH=400><TABLE WIDTH=400 NOBORDER>");
404 file->writeLine("<TD WIDTH=116>");
405 file->writeLine("<A HREF=\"http://www.gromacs.org/\">"
406 "<IMG SRC=\"../images/gmxlogo_small.jpg\" BORDER=0>"
408 file->writeLine("</TD>");
409 file->writeLine(formatString("<TD ALIGN=LEFT VALIGN=TOP WIDTH=280>"
410 "<BR><H2>%s</H2>", title.c_str()));
411 file->writeLine("<FONT SIZE=-1><A HREF=\"../online.html\">Main Table of Contents</A></FONT>");
412 file->writeLine("</TD>");
413 file->writeLine("</TABLE></TD>");
414 file->writeLine("<TD WIDTH=\"*\" ALIGN=RIGHT VALIGN=BOTTOM>");
415 file->writeLine(formatString("<P><B>%s</B>", GromacsVersion()));
416 file->writeLine("</TD>");
417 file->writeLine("</TR></TABLE>");
418 file->writeLine("<HR>");
421 void HelpExportHtml::writeHtmlFooter(File *file) const
423 file->writeLine("<P>");
424 file->writeLine("<HR>");
425 file->writeLine("<DIV ALIGN=RIGHT><FONT SIZE=\"-1\">");
426 file->writeLine("<A HREF=\"http://www.gromacs.org\">http://www.gromacs.org</A><BR>");
427 file->writeLine("</FONT></DIV>");
428 file->writeLine("</BODY>");
429 file->writeLine("</HTML>");
434 /********************************************************************
435 * CommandLineHelpModule
440 * Command-line module for producing help.
442 * This module implements the 'help' subcommand that is automatically added by
443 * CommandLineModuleManager.
445 * \ingroup module_commandline
447 class CommandLineHelpModule : public CommandLineModuleInterface
451 * Creates a command-line help module.
453 * \param[in] modules List of modules for to use for module listings.
454 * \throws std::bad_alloc if out of memory.
456 explicit CommandLineHelpModule(const CommandLineModuleMap &modules);
459 * Adds a top-level help topic.
461 * \param[in] topic Help topic to add.
462 * \throws std::bad_alloc if out of memory.
464 void addTopic(HelpTopicPointer topic);
465 //! Sets whether hidden options will be shown in help.
466 void setShowHidden(bool bHidden) { bHidden_ = bHidden; }
468 * Sets an override to show the help for the given module.
470 * If called, the help module directly prints the help for the given
471 * module when called, skipping any other processing.
473 void setModuleOverride(const CommandLineModuleInterface &module)
475 moduleOverride_ = &module;
478 //! Returns the context object for help output.
479 const CommandLineHelpContext &context() const
484 virtual const char *name() const { return "help"; }
485 virtual const char *shortDescription() const
487 return "Print help information";
490 virtual int run(int argc, char *argv[]);
491 virtual void writeHelp(const CommandLineHelpContext &context) const;
494 void exportHelp(HelpExportInterface *exporter) const;
496 boost::scoped_ptr<RootHelpTopic> rootTopic_;
497 const CommandLineModuleMap &modules_;
499 CommandLineHelpContext *context_;
500 const CommandLineModuleInterface *moduleOverride_;
503 GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModule);
506 CommandLineHelpModule::CommandLineHelpModule(const CommandLineModuleMap &modules)
507 : rootTopic_(new RootHelpTopic(modules)), modules_(modules),
508 context_(NULL), moduleOverride_(NULL), bHidden_(false)
512 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
514 rootTopic_->addSubTopic(move(topic));
517 int CommandLineHelpModule::run(int argc, char *argv[])
519 const char *const exportFormats[] = { "man", "html", "completion" };
520 std::string exportFormat;
521 Options options(NULL, NULL);
522 options.addOption(StringOption("export").store(&exportFormat)
523 .enumValue(exportFormats));
524 CommandLineParser(&options).parse(&argc, argv);
525 if (!exportFormat.empty())
527 boost::scoped_ptr<HelpExportInterface> exporter;
528 if (exportFormat == "man")
530 exporter.reset(new HelpExportMan);
532 else if (exportFormat == "html")
534 exporter.reset(new HelpExportHtml);
538 GMX_THROW(NotImplementedError("This help format is not implemented"));
540 exportHelp(exporter.get());
544 boost::scoped_ptr<CommandLineHelpContext> context(
545 new CommandLineHelpContext(&File::standardOutput(),
546 eHelpOutputFormat_Console));
547 context->setShowHidden(bHidden_);
548 context_ = context.get();
549 if (moduleOverride_ != NULL)
551 ModuleHelpTopic(*moduleOverride_, *this).writeHelp(context->writerContext());
555 HelpManager helpManager(*rootTopic_, context->writerContext());
558 for (int i = 1; i < argc; ++i)
560 helpManager.enterTopic(argv[i]);
563 catch (const InvalidInputError &ex)
565 fprintf(stderr, "%s\n", ex.what());
568 helpManager.writeCurrentTopic();
572 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
574 const HelpWriterContext &writerContext = context.writerContext();
576 if (writerContext.outputFormat() != eHelpOutputFormat_Console)
580 writerContext.writeTextBlock(
581 "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
582 // TODO: More information.
585 void CommandLineHelpModule::exportHelp(HelpExportInterface *exporter) const
587 // TODO: Would be nicer to have the file names supplied by the build system
588 // and/or export a list of files from here.
589 const char *const program =
590 ProgramInfo::getInstance().invariantProgramName().c_str();
592 exporter->startModuleExport();
593 CommandLineModuleMap::const_iterator module;
594 for (module = modules_.begin(); module != modules_.end(); ++module)
596 if (module->second->shortDescription() != NULL)
598 const char *const moduleName = module->first.c_str();
599 std::string tag(formatString("%s-%s", program, moduleName));
600 exporter->exportModuleHelp(tag, *module->second);
603 exporter->finishModuleExport();
609 /********************************************************************
610 * ModuleHelpTopic implementation
613 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
615 module_.writeHelp(helpModule_.context());
618 /********************************************************************
619 * CMainCommandLineModule
623 * Implements a CommandLineModuleInterface, given a function with C/C++ main()
626 * \ingroup module_commandline
628 class CMainCommandLineModule : public CommandLineModuleInterface
631 //! \copydoc gmx::CommandLineModuleManager::CMainFunction
632 typedef CommandLineModuleManager::CMainFunction CMainFunction;
635 * Creates a wrapper module for the given main function.
637 * \param[in] name Name for the module.
638 * \param[in] shortDescription One-line description for the module.
639 * \param[in] mainFunction Main function to wrap.
641 * Does not throw. This is essential for correct implementation of
642 * CommandLineModuleManager::runAsMainCMain().
644 CMainCommandLineModule(const char *name, const char *shortDescription,
645 CMainFunction mainFunction)
646 : name_(name), shortDescription_(shortDescription),
647 mainFunction_(mainFunction)
651 virtual const char *name() const
655 virtual const char *shortDescription() const
657 return shortDescription_;
660 virtual int run(int argc, char *argv[])
662 return mainFunction_(argc, argv);
664 virtual void writeHelp(const CommandLineHelpContext &context) const
666 const HelpOutputFormat format = context.writerContext().outputFormat();
670 case eHelpOutputFormat_Console:
673 case eHelpOutputFormat_Man:
676 case eHelpOutputFormat_Html:
680 GMX_THROW(NotImplementedError(
681 "Command-line help is not implemented for this output format"));
685 // TODO: The constness should not be cast away.
686 argv[0] = const_cast<char *>(name_);
687 argv[1] = const_cast<char *>("-man");
688 argv[2] = const_cast<char *>(type);
690 GlobalCommandLineHelpContext global(context);
691 mainFunction_(argc, argv);
696 const char *shortDescription_;
697 CMainFunction mainFunction_;
703 /********************************************************************
704 * CommandLineModuleManager::Impl
708 * Private implementation class for CommandLineModuleManager.
710 * \ingroup module_commandline
712 class CommandLineModuleManager::Impl
716 * Initializes the implementation class.
718 * \param programInfo Program information for the running binary.
720 explicit Impl(ProgramInfo *programInfo);
723 * Helper method that adds a given module to the module manager.
725 * \throws std::bad_alloc if out of memory.
727 void addModule(CommandLineModulePointer module);
729 * Creates the help module if it does not yet exist.
731 * \throws std::bad_alloc if out of memory.
733 * This method should be called before accessing \a helpModule_.
735 void ensureHelpModuleExists();
738 * Finds a module that matches a name.
740 * \param[in] name Module name to find.
741 * \returns Iterator to the found module, or
742 * \c modules_.end() if not found.
746 CommandLineModuleMap::const_iterator
747 findModuleByName(const std::string &name) const;
749 * Finds a module that the name of the binary.
751 * \param[in] programInfo Program information object to use.
752 * \throws std::bad_alloc if out of memory.
753 * \returns Iterator to the found module, or
754 * \c modules_.end() if not found.
756 * Checks whether the program is invoked through a symlink whose name
757 * is different from ProgramInfo::realBinaryName(), and if so, checks
758 * if a module name matches the name of the symlink.
760 * Note that the \p programInfo parameter is currently not necessary
761 * (as the program info object is also contained as a member), but it
762 * clarifies the control flow.
764 CommandLineModuleMap::const_iterator
765 findModuleFromBinaryName(const ProgramInfo &programInfo) const;
768 * Processes command-line options for the wrapper binary.
770 * \param[in,out] argc On input, argc passed to run().
771 * On output, argc to be passed to the module.
772 * \param[in,out] argv On input, argv passed to run().
773 * On output, argv to be passed to the module.
774 * \throws InvalidInputError if there are invalid options.
775 * \returns The module that should be run.
777 * Handles command-line options that affect the wrapper binary
778 * (potentially changing the members of \c this in response to the
779 * options). Also finds the module that should be run and the
780 * arguments that should be passed to it.
782 CommandLineModuleInterface *
783 processCommonOptions(int *argc, char ***argv);
786 * Maps module names to module objects.
788 * Owns the contained modules.
790 CommandLineModuleMap modules_;
791 //! Information about the currently running program.
792 ProgramInfo &programInfo_;
794 * Module that implements help for the binary.
796 * The pointed module is owned by the \a modules_ container.
798 CommandLineHelpModule *helpModule_;
799 //! Settings for what to write in the startup header.
800 BinaryInformationSettings binaryInfoSettings_;
801 //! If non-NULL, run this module in single-module mode.
802 CommandLineModuleInterface *singleModule_;
803 //! Whether all stderr output should be suppressed.
805 //! Whether to write the startup information to stdout iso stderr.
809 GMX_DISALLOW_COPY_AND_ASSIGN(Impl);
812 CommandLineModuleManager::Impl::Impl(ProgramInfo *programInfo)
813 : programInfo_(*programInfo), helpModule_(NULL), singleModule_(NULL),
814 bQuiet_(false), bStdOutInfo_(false)
816 binaryInfoSettings_.copyright(true);
819 void CommandLineModuleManager::Impl::addModule(CommandLineModulePointer module)
821 GMX_ASSERT(modules_.find(module->name()) == modules_.end(),
822 "Attempted to register a duplicate module name");
823 ensureHelpModuleExists();
824 HelpTopicPointer helpTopic(new ModuleHelpTopic(*module, *helpModule_));
825 modules_.insert(std::make_pair(std::string(module->name()),
827 helpModule_->addTopic(move(helpTopic));
830 void CommandLineModuleManager::Impl::ensureHelpModuleExists()
832 if (helpModule_ == NULL)
834 helpModule_ = new CommandLineHelpModule(modules_);
835 addModule(CommandLineModulePointer(helpModule_));
839 CommandLineModuleMap::const_iterator
840 CommandLineModuleManager::Impl::findModuleByName(const std::string &name) const
842 // TODO: Accept unambiguous prefixes?
843 return modules_.find(name);
846 CommandLineModuleMap::const_iterator
847 CommandLineModuleManager::Impl::findModuleFromBinaryName(
848 const ProgramInfo &programInfo) const
850 std::string binaryName = programInfo.invariantProgramName();
851 if (binaryName == programInfo.realBinaryName())
853 return modules_.end();
855 if (binaryName.compare(0, 2, "g_") == 0)
857 binaryName.erase(0, 2);
859 if (binaryName.compare(0, 3, "gmx") == 0)
861 binaryName.erase(0, 3);
863 return findModuleByName(binaryName);
866 CommandLineModuleInterface *
867 CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
869 // Check if we are directly invoking a certain module.
870 CommandLineModuleInterface *module = singleModule_;
873 // Also check for invokation through named symlinks.
874 CommandLineModuleMap::const_iterator moduleIter
875 = findModuleFromBinaryName(programInfo_);
876 if (moduleIter != modules_.end())
878 module = moduleIter->second.get();
883 bool bHidden = false;
884 bool bVersion = false;
885 bool bCopyright = true;
886 // TODO: Print the common options into the help.
887 // TODO: It would be nice to propagate at least the -quiet option to
888 // the modules so that they can also be quiet in response to this.
889 Options options(NULL, NULL);
890 options.addOption(BooleanOption("h").store(&bHelp));
891 options.addOption(BooleanOption("hidden").store(&bHidden));
892 options.addOption(BooleanOption("quiet").store(&bQuiet_));
893 options.addOption(BooleanOption("version").store(&bVersion));
894 options.addOption(BooleanOption("copyright").store(&bCopyright));
898 // If not in single-module mode, process options to the wrapper binary.
899 // TODO: Ideally, this could be done by CommandLineParser.
900 int argcForWrapper = 1;
901 while (argcForWrapper < *argc && (*argv)[argcForWrapper][0] == '-')
905 if (argcForWrapper > 1)
907 CommandLineParser(&options).parse(&argcForWrapper, *argv);
909 // If no action requested and there is a module specified, process it.
910 if (argcForWrapper < *argc && !bHelp && !bVersion)
912 const char *moduleName = (*argv)[argcForWrapper];
913 CommandLineModuleMap::const_iterator moduleIter
914 = findModuleByName(moduleName);
915 if (moduleIter == modules_.end())
917 std::string message =
918 formatString("'%s' is not a GROMACS command.", moduleName);
919 GMX_THROW(InvalidInputError(message));
921 module = moduleIter->second.get();
922 programInfo_.setDisplayName(
923 programInfo_.realBinaryName() + "-" + moduleIter->first);
924 *argc -= argcForWrapper;
925 *argv += argcForWrapper;
926 // After this point, argc and argv are the same independent of
927 // which path is taken: (*argv)[0] is the module name.
932 // Recognize the common options also after the module name.
933 // TODO: It could be nicer to only recognize -h/-hidden if module is not
935 CommandLineParser(&options).skipUnknown(true).parse(argc, *argv);
938 binaryInfoSettings_.extendedInfo(bVersion);
939 binaryInfoSettings_.copyright(bCopyright);
946 // If no module specified and no other action, show the help.
947 // Also explicitly specifying -h for the wrapper binary goes here.
948 if (module == NULL || bHelp)
950 ensureHelpModuleExists();
953 helpModule_->setModuleOverride(*module);
956 module = helpModule_;
958 if (module == helpModule_)
960 helpModule_->setShowHidden(bHidden);
965 /********************************************************************
966 * CommandLineModuleManager
969 CommandLineModuleManager::CommandLineModuleManager(ProgramInfo *programInfo)
970 : impl_(new Impl(programInfo))
974 CommandLineModuleManager::~CommandLineModuleManager()
978 void CommandLineModuleManager::setQuiet(bool bQuiet)
980 impl_->bQuiet_ = bQuiet;
983 void CommandLineModuleManager::addModule(CommandLineModulePointer module)
985 impl_->addModule(move(module));
988 void CommandLineModuleManager::addModuleCMain(
989 const char *name, const char *shortDescription,
990 CMainFunction mainFunction)
992 CommandLineModulePointer module(
993 new CMainCommandLineModule(name, shortDescription, mainFunction));
994 addModule(move(module));
997 void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
999 impl_->ensureHelpModuleExists();
1000 impl_->helpModule_->addTopic(move(topic));
1003 int CommandLineModuleManager::run(int argc, char *argv[])
1005 CommandLineModuleInterface *module;
1006 const bool bMaster = (!gmx_mpi_initialized() || gmx_node_rank() == 0);
1009 module = impl_->processCommonOptions(&argc, &argv);
1011 catch (const std::exception &)
1013 if (bMaster && !impl_->bQuiet_)
1015 printBinaryInformation(stderr, impl_->programInfo_,
1016 impl_->binaryInfoSettings_);
1022 impl_->bQuiet_ = true;
1024 if (!impl_->bQuiet_)
1026 FILE *out = (impl_->bStdOutInfo_ ? stdout : stderr);
1027 printBinaryInformation(out, impl_->programInfo_,
1028 impl_->binaryInfoSettings_);
1035 int rc = module->run(argc, argv);
1036 if (!impl_->bQuiet_)
1044 int CommandLineModuleManager::runAsMainSingleModule(
1045 int argc, char *argv[], CommandLineModuleInterface *module)
1047 ProgramInfo &programInfo = gmx::init(&argc, &argv);
1050 CommandLineModuleManager manager(&programInfo);
1051 manager.impl_->singleModule_ = module;
1052 int rc = manager.run(argc, argv);
1056 catch (const std::exception &ex)
1058 printFatalErrorMessage(stderr, ex);
1059 return processExceptionAtExit(ex);
1064 int CommandLineModuleManager::runAsMainCMain(
1065 int argc, char *argv[], CMainFunction mainFunction)
1067 CMainCommandLineModule module(argv[0], NULL, mainFunction);
1068 return runAsMainSingleModule(argc, argv, &module);