Fix warnings with Doxygen 1.8.5.
[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 /*! \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 /*! \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 /*! \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
263  * \brief
264  * Command-line module for producing help.
265  *
266  * This module implements the 'help' subcommand that is automatically added by
267  * CommandLineModuleManager.
268  *
269  * \ingroup module_commandline
270  */
271 class CommandLineHelpModule : public CommandLineModuleInterface
272 {
273     public:
274         /*! \brief
275          * Creates a command-line help module.
276          *
277          * \param[in] modules  List of modules for to use for module listings.
278          * \throws    std::bad_alloc if out of memory.
279          */
280         explicit CommandLineHelpModule(const CommandLineModuleMap &modules);
281
282         /*! \brief
283          * Adds a top-level help topic.
284          *
285          * \param[in] topic  Help topic to add.
286          * \throws    std::bad_alloc if out of memory.
287          */
288         void addTopic(HelpTopicPointer topic);
289         //! Sets whether hidden options will be shown in help.
290         void setShowHidden(bool bHidden) { bHidden_ = bHidden; }
291         /*! \brief
292          * Sets an override to show the help for the given module.
293          *
294          * If called, the help module directly prints the help for the given
295          * module when called, skipping any other processing.
296          */
297         void setModuleOverride(const CommandLineModuleInterface &module)
298         {
299             moduleOverride_ = &module;
300         }
301
302         //! Returns the context object for help output.
303         const CommandLineHelpContext &context() const
304         {
305             return *context_;
306         }
307
308         virtual const char *name() const { return "help"; }
309         virtual const char *shortDescription() const
310         {
311             return "Print help information";
312         }
313
314         virtual int run(int argc, char *argv[]);
315         virtual void writeHelp(const CommandLineHelpContext &context) const;
316
317     private:
318         void exportHelp(HelpExportInterface *exporter) const;
319
320         boost::scoped_ptr<RootHelpTopic>  rootTopic_;
321         const CommandLineModuleMap       &modules_;
322
323         CommandLineHelpContext           *context_;
324         const CommandLineModuleInterface *moduleOverride_;
325         bool                              bHidden_;
326
327         GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModule);
328 };
329
330 CommandLineHelpModule::CommandLineHelpModule(const CommandLineModuleMap &modules)
331     : rootTopic_(new RootHelpTopic(modules)), modules_(modules),
332       context_(NULL), moduleOverride_(NULL), bHidden_(false)
333 {
334 }
335
336 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
337 {
338     rootTopic_->addSubTopic(move(topic));
339 }
340
341 int CommandLineHelpModule::run(int argc, char *argv[])
342 {
343     const char *const exportFormats[] = { "man", "html", "completion" };
344     std::string       exportFormat;
345     Options           options(NULL, NULL);
346     options.addOption(StringOption("export").store(&exportFormat)
347                           .enumValue(exportFormats));
348     CommandLineParser(&options).parse(&argc, argv);
349     if (!exportFormat.empty())
350     {
351         boost::scoped_ptr<HelpExportInterface> exporter;
352         {
353             GMX_THROW(NotImplementedError("This help format is not implemented"));
354         }
355         exportHelp(exporter.get());
356         return 0;
357     }
358
359     boost::scoped_ptr<CommandLineHelpContext> context(
360             new CommandLineHelpContext(&File::standardOutput(),
361                                        eHelpOutputFormat_Console));
362     context->setShowHidden(bHidden_);
363     context_ = context.get();
364     if (moduleOverride_ != NULL)
365     {
366         ModuleHelpTopic(*moduleOverride_, *this).writeHelp(context->writerContext());
367         return 0;
368     }
369
370     HelpManager       helpManager(*rootTopic_, context->writerContext());
371     try
372     {
373         for (int i = 1; i < argc; ++i)
374         {
375             helpManager.enterTopic(argv[i]);
376         }
377     }
378     catch (const InvalidInputError &ex)
379     {
380         fprintf(stderr, "%s\n", ex.what());
381         return 2;
382     }
383     helpManager.writeCurrentTopic();
384     return 0;
385 }
386
387 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
388 {
389     const HelpWriterContext &writerContext = context.writerContext();
390     // TODO: Implement.
391     if (writerContext.outputFormat() != eHelpOutputFormat_Console)
392     {
393         return;
394     }
395     writerContext.writeTextBlock(
396             "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
397     // TODO: More information.
398 }
399
400 void CommandLineHelpModule::exportHelp(HelpExportInterface *exporter) const
401 {
402     // TODO: Would be nicer to have the file names supplied by the build system
403     // and/or export a list of files from here.
404     const char *const program =
405         ProgramInfo::getInstance().invariantProgramName().c_str();
406
407     CommandLineModuleMap::const_iterator module;
408     for (module = modules_.begin(); module != modules_.end(); ++module)
409     {
410         if (module->second->shortDescription() != NULL)
411         {
412             const char *const moduleName = module->first.c_str();
413             std::string       tag(formatString("%s-%s", program, moduleName));
414             exporter->exportModuleHelp(tag, *module->second);
415         }
416     }
417 }
418
419 namespace
420 {
421
422 /********************************************************************
423  * ModuleHelpTopic implementation
424  */
425
426 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
427 {
428     module_.writeHelp(helpModule_.context());
429 }
430
431 /********************************************************************
432  * CMainCommandLineModule
433  */
434
435 /*! \internal \brief
436  * Implements a CommandLineModuleInterface, given a function with C/C++ main()
437  * signature.
438  *
439  * \ingroup module_commandline
440  */
441 class CMainCommandLineModule : public CommandLineModuleInterface
442 {
443     public:
444         //! \copydoc gmx::CommandLineModuleManager::CMainFunction
445         typedef CommandLineModuleManager::CMainFunction CMainFunction;
446
447         /*! \brief
448          * Creates a wrapper module for the given main function.
449          *
450          * \param[in] name             Name for the module.
451          * \param[in] shortDescription One-line description for the module.
452          * \param[in] mainFunction     Main function to wrap.
453          *
454          * Does not throw.  This is essential for correct implementation of
455          * CommandLineModuleManager::runAsMainCMain().
456          */
457         CMainCommandLineModule(const char *name, const char *shortDescription,
458                                CMainFunction mainFunction)
459             : name_(name), shortDescription_(shortDescription),
460               mainFunction_(mainFunction)
461         {
462         }
463
464         virtual const char *name() const
465         {
466             return name_;
467         }
468         virtual const char *shortDescription() const
469         {
470             return shortDescription_;
471         }
472
473         virtual int run(int argc, char *argv[])
474         {
475             return mainFunction_(argc, argv);
476         }
477         virtual void writeHelp(const CommandLineHelpContext &context) const
478         {
479             const HelpOutputFormat format = context.writerContext().outputFormat();
480             const char            *type;
481             switch (format)
482             {
483                 case eHelpOutputFormat_Console:
484                     type = "help";
485                     break;
486                 default:
487                     GMX_THROW(NotImplementedError(
488                                       "Command-line help is not implemented for this output format"));
489             }
490             char *argv[4];
491             int   argc = 3;
492             // TODO: The constness should not be cast away.
493             argv[0] = const_cast<char *>(name_);
494             argv[1] = const_cast<char *>("-man");
495             argv[2] = const_cast<char *>(type);
496             argv[3] = NULL;
497             GlobalCommandLineHelpContext global(context);
498             mainFunction_(argc, argv);
499         }
500
501     private:
502         const char             *name_;
503         const char             *shortDescription_;
504         CMainFunction           mainFunction_;
505
506 };
507
508 }   // namespace
509
510 /********************************************************************
511  * CommandLineModuleManager::Impl
512  */
513
514 /*! \internal \brief
515  * Private implementation class for CommandLineModuleManager.
516  *
517  * \ingroup module_commandline
518  */
519 class CommandLineModuleManager::Impl
520 {
521     public:
522         /*! \brief
523          * Initializes the implementation class.
524          *
525          * \param     programInfo  Program information for the running binary.
526          */
527         explicit Impl(ProgramInfo *programInfo);
528
529         /*! \brief
530          * Helper method that adds a given module to the module manager.
531          *
532          * \throws    std::bad_alloc if out of memory.
533          */
534         void addModule(CommandLineModulePointer module);
535         /*! \brief
536          * Creates the help module if it does not yet exist.
537          *
538          * \throws    std::bad_alloc if out of memory.
539          *
540          * This method should be called before accessing \a helpModule_.
541          */
542         void ensureHelpModuleExists();
543
544         /*! \brief
545          * Finds a module that matches a name.
546          *
547          * \param[in] name  Module name to find.
548          * \returns   Iterator to the found module, or
549          *      \c modules_.end() if not found.
550          *
551          * Does not throw.
552          */
553         CommandLineModuleMap::const_iterator
554         findModuleByName(const std::string &name) const;
555         /*! \brief
556          * Finds a module that the name of the binary.
557          *
558          * \param[in] programInfo  Program information object to use.
559          * \throws    std::bad_alloc if out of memory.
560          * \returns   Iterator to the found module, or
561          *      \c modules_.end() if not found.
562          *
563          * Checks whether the program is invoked through a symlink whose name
564          * is different from ProgramInfo::realBinaryName(), and if so, checks
565          * if a module name matches the name of the symlink.
566          *
567          * Note that the \p programInfo parameter is currently not necessary
568          * (as the program info object is also contained as a member), but it
569          * clarifies the control flow.
570          */
571         CommandLineModuleMap::const_iterator
572         findModuleFromBinaryName(const ProgramInfo &programInfo) const;
573
574         /*! \brief
575          * Processes command-line options for the wrapper binary.
576          *
577          * \param[in,out] argc On input, argc passed to run().
578          *     On output, argc to be passed to the module.
579          * \param[in,out] argv On input, argv passed to run().
580          *     On output, argv to be passed to the module.
581          * \throws    InvalidInputError if there are invalid options.
582          * \returns   The module that should be run.
583          *
584          * Handles command-line options that affect the wrapper binary
585          * (potentially changing the members of \c this in response to the
586          * options).  Also finds the module that should be run and the
587          * arguments that should be passed to it.
588          */
589         CommandLineModuleInterface *
590         processCommonOptions(int *argc, char ***argv);
591
592         /*! \brief
593          * Maps module names to module objects.
594          *
595          * Owns the contained modules.
596          */
597         CommandLineModuleMap         modules_;
598         //! Information about the currently running program.
599         ProgramInfo                 &programInfo_;
600         /*! \brief
601          * Module that implements help for the binary.
602          *
603          * The pointed module is owned by the \a modules_ container.
604          */
605         CommandLineHelpModule       *helpModule_;
606         //! Settings for what to write in the startup header.
607         BinaryInformationSettings    binaryInfoSettings_;
608         //! If non-NULL, run this module in single-module mode.
609         CommandLineModuleInterface  *singleModule_;
610         //! Whether all stderr output should be suppressed.
611         bool                         bQuiet_;
612         //! Whether to write the startup information to stdout iso stderr.
613         bool                         bStdOutInfo_;
614
615     private:
616         GMX_DISALLOW_COPY_AND_ASSIGN(Impl);
617 };
618
619 CommandLineModuleManager::Impl::Impl(ProgramInfo *programInfo)
620     : programInfo_(*programInfo), helpModule_(NULL), singleModule_(NULL),
621       bQuiet_(false), bStdOutInfo_(false)
622 {
623     binaryInfoSettings_.copyright(true);
624 }
625
626 void CommandLineModuleManager::Impl::addModule(CommandLineModulePointer module)
627 {
628     GMX_ASSERT(modules_.find(module->name()) == modules_.end(),
629                "Attempted to register a duplicate module name");
630     ensureHelpModuleExists();
631     HelpTopicPointer helpTopic(new ModuleHelpTopic(*module, *helpModule_));
632     modules_.insert(std::make_pair(std::string(module->name()),
633                                    move(module)));
634     helpModule_->addTopic(move(helpTopic));
635 }
636
637 void CommandLineModuleManager::Impl::ensureHelpModuleExists()
638 {
639     if (helpModule_ == NULL)
640     {
641         helpModule_ = new CommandLineHelpModule(modules_);
642         addModule(CommandLineModulePointer(helpModule_));
643     }
644 }
645
646 CommandLineModuleMap::const_iterator
647 CommandLineModuleManager::Impl::findModuleByName(const std::string &name) const
648 {
649     // TODO: Accept unambiguous prefixes?
650     return modules_.find(name);
651 }
652
653 CommandLineModuleMap::const_iterator
654 CommandLineModuleManager::Impl::findModuleFromBinaryName(
655         const ProgramInfo &programInfo) const
656 {
657     std::string binaryName = programInfo.invariantProgramName();
658     if (binaryName == programInfo.realBinaryName())
659     {
660         return modules_.end();
661     }
662     if (binaryName.compare(0, 2, "g_") == 0)
663     {
664         binaryName.erase(0, 2);
665     }
666     if (binaryName.compare(0, 3, "gmx") == 0)
667     {
668         binaryName.erase(0, 3);
669     }
670     return findModuleByName(binaryName);
671 }
672
673 CommandLineModuleInterface *
674 CommandLineModuleManager::Impl::processCommonOptions(int *argc, char ***argv)
675 {
676     // Check if we are directly invoking a certain module.
677     CommandLineModuleInterface *module = singleModule_;
678     if (module == NULL)
679     {
680         // Also check for invokation through named symlinks.
681         CommandLineModuleMap::const_iterator moduleIter
682             = findModuleFromBinaryName(programInfo_);
683         if (moduleIter != modules_.end())
684         {
685             module = moduleIter->second.get();
686         }
687     }
688
689     bool bHelp      = false;
690     bool bHidden    = false;
691     bool bVersion   = false;
692     bool bCopyright = true;
693     // TODO: Print the common options into the help.
694     // TODO: It would be nice to propagate at least the -quiet option to
695     // the modules so that they can also be quiet in response to this.
696     Options options(NULL, NULL);
697     options.addOption(BooleanOption("h").store(&bHelp));
698     options.addOption(BooleanOption("hidden").store(&bHidden));
699     options.addOption(BooleanOption("quiet").store(&bQuiet_));
700     options.addOption(BooleanOption("version").store(&bVersion));
701     options.addOption(BooleanOption("copyright").store(&bCopyright));
702
703     if (module == NULL)
704     {
705         // If not in single-module mode, process options to the wrapper binary.
706         // TODO: Ideally, this could be done by CommandLineParser.
707         int argcForWrapper = 1;
708         while (argcForWrapper < *argc && (*argv)[argcForWrapper][0] == '-')
709         {
710             ++argcForWrapper;
711         }
712         if (argcForWrapper > 1)
713         {
714             CommandLineParser(&options).parse(&argcForWrapper, *argv);
715         }
716         // If no action requested and there is a module specified, process it.
717         if (argcForWrapper < *argc && !bHelp && !bVersion)
718         {
719             const char *moduleName = (*argv)[argcForWrapper];
720             CommandLineModuleMap::const_iterator moduleIter
721                 = findModuleByName(moduleName);
722             if (moduleIter == modules_.end())
723             {
724                 std::string message =
725                     formatString("'%s' is not a GROMACS command.", moduleName);
726                 GMX_THROW(InvalidInputError(message));
727             }
728             module = moduleIter->second.get();
729             programInfo_.setDisplayName(
730                     programInfo_.realBinaryName() + "-" + moduleIter->first);
731             *argc -= argcForWrapper;
732             *argv += argcForWrapper;
733             // After this point, argc and argv are the same independent of
734             // which path is taken: (*argv)[0] is the module name.
735         }
736     }
737     if (module != NULL)
738     {
739         // Recognize the common options also after the module name.
740         // TODO: It could be nicer to only recognize -h/-hidden if module is not
741         // null.
742         CommandLineParser(&options).skipUnknown(true).parse(argc, *argv);
743     }
744     options.finish();
745     binaryInfoSettings_.extendedInfo(bVersion);
746     binaryInfoSettings_.copyright(bCopyright);
747     if (bVersion)
748     {
749         bQuiet_      = false;
750         bStdOutInfo_ = true;
751         return NULL;
752     }
753     // If no module specified and no other action, show the help.
754     // Also explicitly specifying -h for the wrapper binary goes here.
755     if (module == NULL || bHelp)
756     {
757         ensureHelpModuleExists();
758         if (module != NULL)
759         {
760             helpModule_->setModuleOverride(*module);
761         }
762         *argc  = 1;
763         module = helpModule_;
764     }
765     if (module == helpModule_)
766     {
767         helpModule_->setShowHidden(bHidden);
768     }
769     return module;
770 }
771
772 /********************************************************************
773  * CommandLineModuleManager
774  */
775
776 CommandLineModuleManager::CommandLineModuleManager(ProgramInfo *programInfo)
777     : impl_(new Impl(programInfo))
778 {
779 }
780
781 CommandLineModuleManager::~CommandLineModuleManager()
782 {
783 }
784
785 void CommandLineModuleManager::setQuiet(bool bQuiet)
786 {
787     impl_->bQuiet_ = bQuiet;
788 }
789
790 void CommandLineModuleManager::addModule(CommandLineModulePointer module)
791 {
792     impl_->addModule(move(module));
793 }
794
795 void CommandLineModuleManager::addModuleCMain(
796         const char *name, const char *shortDescription,
797         CMainFunction mainFunction)
798 {
799     CommandLineModulePointer module(
800             new CMainCommandLineModule(name, shortDescription, mainFunction));
801     addModule(move(module));
802 }
803
804 void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
805 {
806     impl_->ensureHelpModuleExists();
807     impl_->helpModule_->addTopic(move(topic));
808 }
809
810 int CommandLineModuleManager::run(int argc, char *argv[])
811 {
812     CommandLineModuleInterface *module;
813     const bool                  bMaster = (!gmx_mpi_initialized() || gmx_node_rank() == 0);
814     try
815     {
816         module = impl_->processCommonOptions(&argc, &argv);
817     }
818     catch (const std::exception &)
819     {
820         if (bMaster && !impl_->bQuiet_)
821         {
822             printBinaryInformation(stderr, impl_->programInfo_,
823                                    impl_->binaryInfoSettings_);
824         }
825         throw;
826     }
827     if (!bMaster)
828     {
829         impl_->bQuiet_ = true;
830     }
831     if (!impl_->bQuiet_)
832     {
833         FILE *out = (impl_->bStdOutInfo_ ? stdout : stderr);
834         printBinaryInformation(out, impl_->programInfo_,
835                                impl_->binaryInfoSettings_);
836         fprintf(out, "\n");
837     }
838     if (module == NULL)
839     {
840         return 0;
841     }
842     int rc = module->run(argc, argv);
843     if (!impl_->bQuiet_)
844     {
845         gmx_thanx(stderr);
846     }
847     return rc;
848 }
849
850 // static
851 int CommandLineModuleManager::runAsMainSingleModule(
852         int argc, char *argv[], CommandLineModuleInterface *module)
853 {
854     ProgramInfo &programInfo = gmx::init(&argc, &argv);
855     try
856     {
857         CommandLineModuleManager manager(&programInfo);
858         manager.impl_->singleModule_ = module;
859         int rc = manager.run(argc, argv);
860         gmx::finalize();
861         return rc;
862     }
863     catch (const std::exception &ex)
864     {
865         printFatalErrorMessage(stderr, ex);
866         return processExceptionAtExit(ex);
867     }
868 }
869
870 // static
871 int CommandLineModuleManager::runAsMainCMain(
872         int argc, char *argv[], CMainFunction mainFunction)
873 {
874     CMainCommandLineModule module(argv[0], NULL, mainFunction);
875     return runAsMainSingleModule(argc, argv, &module);
876 }
877
878 } // namespace gmx