Change name of gmxdump to dump and gmxcheck to check
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlinemodulemanager.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements gmx::CommandLineModuleManager.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_commandline
41  */
42 #include "cmdlinemodulemanager.h"
43
44 #include <cstdio>
45
46 #include <map>
47 #include <string>
48 #include <utility>
49
50 #include <boost/scoped_ptr.hpp>
51
52 #include "gromacs/legacyheaders/copyrite.h"
53 #include "gromacs/legacyheaders/network.h"
54
55 #include "gromacs/commandline/cmdlinehelpcontext.h"
56 #include "gromacs/commandline/cmdlinemodule.h"
57 #include "gromacs/commandline/cmdlineparser.h"
58 #include "gromacs/onlinehelp/helpformat.h"
59 #include "gromacs/onlinehelp/helpmanager.h"
60 #include "gromacs/onlinehelp/helptopic.h"
61 #include "gromacs/onlinehelp/helpwritercontext.h"
62 #include "gromacs/options/basicoptions.h"
63 #include "gromacs/options/options.h"
64 #include "gromacs/utility/exceptions.h"
65 #include "gromacs/utility/file.h"
66 #include "gromacs/utility/gmxassert.h"
67 #include "gromacs/utility/init.h"
68 #include "gromacs/utility/programinfo.h"
69 #include "gromacs/utility/stringutil.h"
70
71 namespace gmx
72 {
73
74 //! Container type for mapping module names to module objects.
75 typedef std::map<std::string, CommandLineModulePointer> CommandLineModuleMap;
76
77 class CommandLineHelpModule;
78
79 namespace
80 {
81
82 /********************************************************************
83  * RootHelpTopic
84  */
85
86 struct RootHelpText
87 {
88     static const char        name[];
89     static const char        title[];
90     static const char *const text[];
91 };
92
93 // The first two are not used.
94 const char        RootHelpText::name[]  = "";
95 const char        RootHelpText::title[] = "";
96 const char *const RootHelpText::text[]  = {
97     "Usage: [PROGRAM] <command> [<args>]",
98 };
99
100 /*! \internal \brief
101  * Help topic that forms the root of the help tree for the help subcommand.
102  *
103  * \ingroup module_commandline
104  */
105 class RootHelpTopic : public CompositeHelpTopic<RootHelpText>
106 {
107     public:
108         /*! \brief
109          * Creates a root help topic.
110          *
111          * \param[in] modules  List of modules for to use for module listings.
112          *
113          * Does not throw.
114          */
115         explicit RootHelpTopic(const CommandLineModuleMap &modules)
116             : modules_(modules)
117         {
118         }
119
120         virtual void writeHelp(const HelpWriterContext &context) const;
121
122     private:
123         void printModuleList(const HelpWriterContext &context) const;
124
125         const CommandLineModuleMap &modules_;
126
127         GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
128 };
129
130 void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
131 {
132     if (context.outputFormat() != eHelpOutputFormat_Console)
133     {
134         // TODO: Implement once the situation with Redmine issue #969 is more
135         // clear.
136         GMX_THROW(NotImplementedError(
137                           "Root help is not implemented for this output format"));
138     }
139     writeBasicHelpTopic(context, *this, helpText());
140     // TODO: If/when this list becomes long, it may be better to only print
141     // "common" commands here, and have a separate topic (e.g.,
142     // "help commands") that prints the full list.
143     printModuleList(context);
144     context.writeTextBlock(
145             "For additional help on a command, use '[PROGRAM] help <command>'");
146     writeSubTopicList(context,
147                       "\nAdditional help is available on the following topics:");
148     context.writeTextBlock(
149             "To access the help, use '[PROGRAM] help <topic>'.");
150 }
151
152 void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
153 {
154     if (context.outputFormat() != eHelpOutputFormat_Console)
155     {
156         // TODO: Implement once the situation with Redmine issue #969 is more
157         // clear.
158         GMX_THROW(NotImplementedError(
159                           "Module list is not implemented for this output format"));
160     }
161     int maxNameLength = 0;
162     CommandLineModuleMap::const_iterator module;
163     for (module = modules_.begin(); module != modules_.end(); ++module)
164     {
165         int nameLength = static_cast<int>(module->first.length());
166         if (module->second->shortDescription() != NULL
167             && nameLength > maxNameLength)
168         {
169             maxNameLength = nameLength;
170         }
171     }
172     File              &file = context.outputFile();
173     TextTableFormatter formatter;
174     formatter.addColumn(NULL, maxNameLength + 1, false);
175     formatter.addColumn(NULL, 72 - maxNameLength, true);
176     formatter.setFirstColumnIndent(4);
177     file.writeLine();
178     file.writeLine("Available commands:");
179     for (module = modules_.begin(); module != modules_.end(); ++module)
180     {
181         const char *name        = module->first.c_str();
182         const char *description = module->second->shortDescription();
183         if (description != NULL)
184         {
185             formatter.clear();
186             formatter.addColumnLine(0, name);
187             formatter.addColumnLine(1, description);
188             file.writeString(formatter.formatRow());
189         }
190     }
191 }
192
193 /********************************************************************
194  * ModuleHelpTopic declaration
195  */
196
197 /*! \internal \brief
198  * Help topic wrapper for a command-line module.
199  *
200  * This class implements HelpTopicInterface such that it wraps a
201  * CommandLineModuleInterface, allowing subcommand "help <command>"
202  * to produce the help for "<command>".
203  *
204  * \ingroup module_commandline
205  */
206 class ModuleHelpTopic : public HelpTopicInterface
207 {
208     public:
209         //! Constructs a help topic for a specific module.
210         ModuleHelpTopic(const CommandLineModuleInterface &module,
211                         const CommandLineHelpModule      &helpModule)
212             : module_(module), helpModule_(helpModule)
213         {
214         }
215
216         virtual const char *name() const { return module_.name(); }
217         virtual const char *title() const { return NULL; }
218         virtual bool hasSubTopics() const { return false; }
219         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
220         {
221             return NULL;
222         }
223         virtual void writeHelp(const HelpWriterContext &context) const;
224
225     private:
226         const CommandLineModuleInterface &module_;
227         const CommandLineHelpModule      &helpModule_;
228
229         GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
230 };
231
232 /********************************************************************
233  * HelpExportInterface
234  */
235
236 /*! \internal \brief
237  * Callbacks for exporting help information for command-line modules.
238  *
239  * \ingroup module_commandline
240  */
241 class HelpExportInterface
242 {
243     public:
244         virtual ~HelpExportInterface() {};
245
246         /*! \brief
247          * Called to export the help for each module.
248          *
249          * \param[in] tag     Unique tag for the module (gmx-something).
250          * \param[in] module  Module for which the help should be exported.
251          */
252         virtual void exportModuleHelp(const std::string                &tag,
253                                       const CommandLineModuleInterface &module) = 0;
254 };
255
256 }   // namespace
257
258 /********************************************************************
259  * CommandLineHelpModule
260  */
261
262 /*! \internal \brief
263  * Command-line module for producing help.
264  *
265  * This module implements the 'help' subcommand that is automatically added by
266  * CommandLineModuleManager.
267  *
268  * \ingroup module_commandline
269  */
270 class CommandLineHelpModule : public CommandLineModuleInterface
271 {
272     public:
273         /*! \brief
274          * Creates a command-line help module.
275          *
276          * \param[in] modules  List of modules for to use for module listings.
277          * \throws    std::bad_alloc if out of memory.
278          */
279         explicit CommandLineHelpModule(const CommandLineModuleMap &modules);
280
281         /*! \brief
282          * Adds a top-level help topic.
283          *
284          * \param[in] topic  Help topic to add.
285          * \throws    std::bad_alloc if out of memory.
286          */
287         void addTopic(HelpTopicPointer topic);
288         //! Sets whether hidden options will be shown in help.
289         void setShowHidden(bool bHidden) { bHidden_ = bHidden; }
290         /*! \brief
291          * Sets an override to show the help for the given module.
292          *
293          * If called, the help module directly prints the help for the given
294          * module when called, skipping any other processing.
295          */
296         void setModuleOverride(const CommandLineModuleInterface &module)
297         {
298             moduleOverride_ = &module;
299         }
300
301         //! Returns the context object for help output.
302         const CommandLineHelpContext &context() const
303         {
304             return *context_;
305         }
306
307         virtual const char *name() const { return "help"; }
308         virtual const char *shortDescription() const
309         {
310             return "Print help information";
311         }
312
313         virtual int run(int argc, char *argv[]);
314         virtual void writeHelp(const CommandLineHelpContext &context) const;
315
316     private:
317         void exportHelp(HelpExportInterface *exporter) const;
318
319         boost::scoped_ptr<RootHelpTopic>  rootTopic_;
320         const CommandLineModuleMap       &modules_;
321
322         CommandLineHelpContext           *context_;
323         const CommandLineModuleInterface *moduleOverride_;
324         bool                              bHidden_;
325
326         GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModule);
327 };
328
329 CommandLineHelpModule::CommandLineHelpModule(const CommandLineModuleMap &modules)
330     : rootTopic_(new RootHelpTopic(modules)), modules_(modules),
331       context_(NULL), moduleOverride_(NULL), bHidden_(false)
332 {
333 }
334
335 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
336 {
337     rootTopic_->addSubTopic(move(topic));
338 }
339
340 int CommandLineHelpModule::run(int argc, char *argv[])
341 {
342     const char *const exportFormats[] = { "man", "html", "completion" };
343     std::string       exportFormat;
344     Options           options(NULL, NULL);
345     options.addOption(StringOption("export").store(&exportFormat)
346                           .enumValue(exportFormats));
347     CommandLineParser(&options).parse(&argc, argv);
348     if (!exportFormat.empty())
349     {
350         boost::scoped_ptr<HelpExportInterface> exporter;
351         {
352             GMX_THROW(NotImplementedError("This help format is not implemented"));
353         }
354         exportHelp(exporter.get());
355         return 0;
356     }
357
358     boost::scoped_ptr<CommandLineHelpContext> context(
359             new CommandLineHelpContext(&File::standardOutput(),
360                                        eHelpOutputFormat_Console));
361     context->setShowHidden(bHidden_);
362     context_ = context.get();
363     if (moduleOverride_ != NULL)
364     {
365         ModuleHelpTopic(*moduleOverride_, *this).writeHelp(context->writerContext());
366         return 0;
367     }
368
369     HelpManager       helpManager(*rootTopic_, context->writerContext());
370     try
371     {
372         for (int i = 1; i < argc; ++i)
373         {
374             helpManager.enterTopic(argv[i]);
375         }
376     }
377     catch (const InvalidInputError &ex)
378     {
379         fprintf(stderr, "%s\n", ex.what());
380         return 2;
381     }
382     helpManager.writeCurrentTopic();
383     return 0;
384 }
385
386 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
387 {
388     const HelpWriterContext &writerContext = context.writerContext();
389     // TODO: Implement.
390     if (writerContext.outputFormat() != eHelpOutputFormat_Console)
391     {
392         return;
393     }
394     writerContext.writeTextBlock(
395             "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
396     // TODO: More information.
397 }
398
399 void CommandLineHelpModule::exportHelp(HelpExportInterface *exporter) const
400 {
401     // TODO: Would be nicer to have the file names supplied by the build system
402     // and/or export a list of files from here.
403     const char *const program =
404         ProgramInfo::getInstance().invariantProgramName().c_str();
405
406     CommandLineModuleMap::const_iterator module;
407     for (module = modules_.begin(); module != modules_.end(); ++module)
408     {
409         if (module->second->shortDescription() != NULL)
410         {
411             const char *const moduleName = module->first.c_str();
412             std::string       tag(formatString("%s-%s", program, moduleName));
413             exporter->exportModuleHelp(tag, *module->second);
414         }
415     }
416 }
417
418 namespace
419 {
420
421 /********************************************************************
422  * ModuleHelpTopic implementation
423  */
424
425 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
426 {
427     module_.writeHelp(helpModule_.context());
428 }
429
430 /********************************************************************
431  * CMainCommandLineModule
432  */
433
434 /*! \internal \brief
435  * Implements a CommandLineModuleInterface, given a function with C/C++ main()
436  * signature.
437  *
438  * \ingroup module_commandline
439  */
440 class CMainCommandLineModule : public CommandLineModuleInterface
441 {
442     public:
443         //! \copydoc gmx::CommandLineModuleManager::CMainFunction
444         typedef CommandLineModuleManager::CMainFunction CMainFunction;
445
446         /*! \brief
447          * Creates a wrapper module for the given main function.
448          *
449          * \param[in] name             Name for the module.
450          * \param[in] shortDescription One-line description for the module.
451          * \param[in] mainFunction     Main function to wrap.
452          *
453          * Does not throw.  This is essential for correct implementation of
454          * CommandLineModuleManager::runAsMainCMain().
455          */
456         CMainCommandLineModule(const char *name, const char *shortDescription,
457                                CMainFunction mainFunction)
458             : name_(name), shortDescription_(shortDescription),
459               mainFunction_(mainFunction)
460         {
461         }
462
463         virtual const char *name() const
464         {
465             return name_;
466         }
467         virtual const char *shortDescription() const
468         {
469             return shortDescription_;
470         }
471
472         virtual int run(int argc, char *argv[])
473         {
474             return mainFunction_(argc, argv);
475         }
476         virtual void writeHelp(const CommandLineHelpContext &context) const
477         {
478             const HelpOutputFormat format = context.writerContext().outputFormat();
479             const char            *type;
480             switch (format)
481             {
482                 case eHelpOutputFormat_Console:
483                     type = "help";
484                     break;
485                 default:
486                     GMX_THROW(NotImplementedError(
487                                       "Command-line help is not implemented for this output format"));
488             }
489             char *argv[4];
490             int   argc = 3;
491             // TODO: The constness should not be cast away.
492             argv[0] = const_cast<char *>(name_);
493             argv[1] = const_cast<char *>("-man");
494             argv[2] = const_cast<char *>(type);
495             argv[3] = NULL;
496             GlobalCommandLineHelpContext global(context);
497             mainFunction_(argc, argv);
498         }
499
500     private:
501         const char             *name_;
502         const char             *shortDescription_;
503         CMainFunction           mainFunction_;
504
505 };
506
507 }   // namespace
508
509 /********************************************************************
510  * CommandLineModuleManager::Impl
511  */
512
513 /*! \internal \brief
514  * Private implementation class for CommandLineModuleManager.
515  *
516  * \ingroup module_commandline
517  */
518 class CommandLineModuleManager::Impl
519 {
520     public:
521         /*! \brief
522          * Initializes the implementation class.
523          *
524          * \param     programInfo  Program information for the running binary.
525          */
526         explicit Impl(ProgramInfo *programInfo);
527
528         /*! \brief
529          * Helper method that adds a given module to the module manager.
530          *
531          * \throws    std::bad_alloc if out of memory.
532          */
533         void addModule(CommandLineModulePointer module);
534         /*! \brief
535          * Creates the help module if it does not yet exist.
536          *
537          * \throws    std::bad_alloc if out of memory.
538          *
539          * This method should be called before accessing \a helpModule_.
540          */
541         void ensureHelpModuleExists();
542
543         /*! \brief
544          * Finds a module that matches a name.
545          *
546          * \param[in] name  Module name to find.
547          * \returns   Iterator to the found module, or
548          *      \c modules_.end() if not found.
549          *
550          * Does not throw.
551          */
552         CommandLineModuleMap::const_iterator
553         findModuleByName(const std::string &name) const;
554         /*! \brief
555          * Finds a module that the name of the binary.
556          *
557          * \param[in] programInfo  Program information object to use.
558          * \throws    std::bad_alloc if out of memory.
559          * \returns   Iterator to the found module, or
560          *      \c modules_.end() if not found.
561          *
562          * Checks whether the program is invoked through a symlink whose name
563          * is different from ProgramInfo::realBinaryName(), and if so, checks
564          * if a module name matches the name of the symlink.
565          *
566          * Note that the \p programInfo parameter is currently not necessary
567          * (as the program info object is also contained as a member), but it
568          * clarifies the control flow.
569          */
570         CommandLineModuleMap::const_iterator
571         findModuleFromBinaryName(const ProgramInfo &programInfo) const;
572
573         /*! \brief
574          * Processes command-line options for the wrapper binary.
575          *
576          * \param[in,out] argc On input, argc passed to run().
577          *     On output, argc to be passed to the module.
578          * \param[in,out] argv On input, argv passed to run().
579          *     On output, argv to be passed to the module.
580          * \throws    InvalidInputError if there are invalid options.
581          * \returns   The module that should be run.
582          *
583          * Handles command-line options that affect the wrapper binary
584          * (potentially changing the members of \c this in response to the
585          * options).  Also finds the module that should be run and the
586          * arguments that should be passed to it.
587          */
588         CommandLineModuleInterface *
589         processCommonOptions(int *argc, char ***argv);
590
591         /*! \brief
592          * Maps module names to module objects.
593          *
594          * Owns the contained modules.
595          */
596         CommandLineModuleMap         modules_;
597         //! Information about the currently running program.
598         ProgramInfo                 &programInfo_;
599         /*! \brief
600          * Module that implements help for the binary.
601          *
602          * The pointed module is owned by the \a modules_ container.
603          */
604         CommandLineHelpModule       *helpModule_;
605         //! Settings for what to write in the startup header.
606         BinaryInformationSettings    binaryInfoSettings_;
607         //! If non-NULL, run this module in single-module mode.
608         CommandLineModuleInterface  *singleModule_;
609         //! Whether all stderr output should be suppressed.
610         bool                         bQuiet_;
611         //! Whether to write the startup information to stdout iso stderr.
612         bool                         bStdOutInfo_;
613
614     private:
615         GMX_DISALLOW_COPY_AND_ASSIGN(Impl);
616 };
617
618 CommandLineModuleManager::Impl::Impl(ProgramInfo *programInfo)
619     : programInfo_(*programInfo), helpModule_(NULL), singleModule_(NULL),
620       bQuiet_(false), bStdOutInfo_(false)
621 {
622     binaryInfoSettings_.copyright(true);
623 }
624
625 void CommandLineModuleManager::Impl::addModule(CommandLineModulePointer module)
626 {
627     GMX_ASSERT(modules_.find(module->name()) == modules_.end(),
628                "Attempted to register a duplicate module name");
629     ensureHelpModuleExists();
630     HelpTopicPointer helpTopic(new ModuleHelpTopic(*module, *helpModule_));
631     modules_.insert(std::make_pair(std::string(module->name()),
632                                    move(module)));
633     helpModule_->addTopic(move(helpTopic));
634 }
635
636 void CommandLineModuleManager::Impl::ensureHelpModuleExists()
637 {
638     if (helpModule_ == NULL)
639     {
640         helpModule_ = new CommandLineHelpModule(modules_);
641         addModule(CommandLineModulePointer(helpModule_));
642     }
643 }
644
645 CommandLineModuleMap::const_iterator
646 CommandLineModuleManager::Impl::findModuleByName(const std::string &name) const
647 {
648     // TODO: Accept unambiguous prefixes?
649     return modules_.find(name);
650 }
651
652 CommandLineModuleMap::const_iterator
653 CommandLineModuleManager::Impl::findModuleFromBinaryName(
654         const ProgramInfo &programInfo) const
655 {
656     std::string binaryName = programInfo.invariantProgramName();
657     if (binaryName == programInfo.realBinaryName())
658     {
659         return modules_.end();
660     }
661     if (binaryName.compare(0, 2, "g_") == 0)
662     {
663         binaryName.erase(0, 2);
664     }
665     if (binaryName.compare(0, 3, "gmx") == 0)
666     {
667         binaryName.erase(0, 3);
668     }
669     return findModuleByName(binaryName);
670 }
671
672 CommandLineModuleInterface *
673 CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
674 {
675     // Check if we are directly invoking a certain module.
676     CommandLineModuleInterface *module = singleModule_;
677     if (module == NULL)
678     {
679         // Also check for invokation through named symlinks.
680         CommandLineModuleMap::const_iterator moduleIter
681             = findModuleFromBinaryName(programInfo_);
682         if (moduleIter != modules_.end())
683         {
684             module = moduleIter->second.get();
685         }
686     }
687
688     bool bHelp      = false;
689     bool bHidden    = false;
690     bool bVersion   = false;
691     bool bCopyright = true;
692     // TODO: Print the common options into the help.
693     // TODO: It would be nice to propagate at least the -quiet option to
694     // the modules so that they can also be quiet in response to this.
695     Options options(NULL, NULL);
696     options.addOption(BooleanOption("h").store(&bHelp));
697     options.addOption(BooleanOption("hidden").store(&bHidden));
698     options.addOption(BooleanOption("quiet").store(&bQuiet_));
699     options.addOption(BooleanOption("version").store(&bVersion));
700     options.addOption(BooleanOption("copyright").store(&bCopyright));
701
702     if (module == NULL)
703     {
704         // If not in single-module mode, process options to the wrapper binary.
705         // TODO: Ideally, this could be done by CommandLineParser.
706         int argcForWrapper = 1;
707         while (argcForWrapper < *argc && (*argv)[argcForWrapper][0] == '-')
708         {
709             ++argcForWrapper;
710         }
711         if (argcForWrapper > 1)
712         {
713             CommandLineParser(&options).parse(&argcForWrapper, *argv);
714         }
715         // If no action requested and there is a module specified, process it.
716         if (argcForWrapper < *argc && !bHelp && !bVersion)
717         {
718             const char *moduleName = (*argv)[argcForWrapper];
719             CommandLineModuleMap::const_iterator moduleIter
720                 = findModuleByName(moduleName);
721             if (moduleIter == modules_.end())
722             {
723                 std::string message =
724                     formatString("'%s' is not a GROMACS command.", moduleName);
725                 GMX_THROW(InvalidInputError(message));
726             }
727             module = moduleIter->second.get();
728             programInfo_.setDisplayName(
729                     programInfo_.realBinaryName() + "-" + moduleIter->first);
730             *argc -= argcForWrapper;
731             *argv += argcForWrapper;
732             // After this point, argc and argv are the same independent of
733             // which path is taken: (*argv)[0] is the module name.
734         }
735     }
736     if (module != NULL)
737     {
738         // Recognize the common options also after the module name.
739         // TODO: It could be nicer to only recognize -h/-hidden if module is not
740         // null.
741         CommandLineParser(&options).skipUnknown(true).parse(argc, *argv);
742     }
743     options.finish();
744     binaryInfoSettings_.extendedInfo(bVersion);
745     binaryInfoSettings_.copyright(bCopyright);
746     if (bVersion)
747     {
748         bQuiet_      = false;
749         bStdOutInfo_ = true;
750         return NULL;
751     }
752     // If no module specified and no other action, show the help.
753     // Also explicitly specifying -h for the wrapper binary goes here.
754     if (module == NULL || bHelp)
755     {
756         ensureHelpModuleExists();
757         if (module != NULL)
758         {
759             helpModule_->setModuleOverride(*module);
760         }
761         *argc  = 1;
762         module = helpModule_;
763     }
764     if (module == helpModule_)
765     {
766         helpModule_->setShowHidden(bHidden);
767     }
768     return module;
769 }
770
771 /********************************************************************
772  * CommandLineModuleManager
773  */
774
775 CommandLineModuleManager::CommandLineModuleManager(ProgramInfo *programInfo)
776     : impl_(new Impl(programInfo))
777 {
778 }
779
780 CommandLineModuleManager::~CommandLineModuleManager()
781 {
782 }
783
784 void CommandLineModuleManager::setQuiet(bool bQuiet)
785 {
786     impl_->bQuiet_ = bQuiet;
787 }
788
789 void CommandLineModuleManager::addModule(CommandLineModulePointer module)
790 {
791     impl_->addModule(move(module));
792 }
793
794 void CommandLineModuleManager::addModuleCMain(
795         const char *name, const char *shortDescription,
796         CMainFunction mainFunction)
797 {
798     CommandLineModulePointer module(
799             new CMainCommandLineModule(name, shortDescription, mainFunction));
800     addModule(move(module));
801 }
802
803 void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
804 {
805     impl_->ensureHelpModuleExists();
806     impl_->helpModule_->addTopic(move(topic));
807 }
808
809 int CommandLineModuleManager::run(int argc, char *argv[])
810 {
811     CommandLineModuleInterface *module;
812     const bool                  bMaster = (!gmx_mpi_initialized() || gmx_node_rank() == 0);
813     try
814     {
815         module = impl_->processCommonOptions(&argc, &argv);
816     }
817     catch (const std::exception &)
818     {
819         if (bMaster && !impl_->bQuiet_)
820         {
821             printBinaryInformation(stderr, impl_->programInfo_,
822                                    impl_->binaryInfoSettings_);
823         }
824         throw;
825     }
826     if (!bMaster)
827     {
828         impl_->bQuiet_ = true;
829     }
830     if (!impl_->bQuiet_)
831     {
832         FILE *out = (impl_->bStdOutInfo_ ? stdout : stderr);
833         printBinaryInformation(out, impl_->programInfo_,
834                                impl_->binaryInfoSettings_);
835         fprintf(out, "\n");
836     }
837     if (module == NULL)
838     {
839         return 0;
840     }
841     int rc = module->run(argc, argv);
842     if (!impl_->bQuiet_)
843     {
844         gmx_thanx(stderr);
845     }
846     return rc;
847 }
848
849 // static
850 int CommandLineModuleManager::runAsMainSingleModule(
851         int argc, char *argv[], CommandLineModuleInterface *module)
852 {
853     ProgramInfo &programInfo = gmx::init(&argc, &argv);
854     try
855     {
856         CommandLineModuleManager manager(&programInfo);
857         manager.impl_->singleModule_ = module;
858         int rc = manager.run(argc, argv);
859         gmx::finalize();
860         return rc;
861     }
862     catch (const std::exception &ex)
863     {
864         printFatalErrorMessage(stderr, ex);
865         return processExceptionAtExit(ex);
866     }
867 }
868
869 // static
870 int CommandLineModuleManager::runAsMainCMain(
871         int argc, char *argv[], CMainFunction mainFunction)
872 {
873     CMainCommandLineModule module(argv[0], NULL, mainFunction);
874     return runAsMainSingleModule(argc, argv, &module);
875 }
876
877 } // namespace gmx