f49763e0755790a9bc6ceec81377463e2faa000a
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlineoptionsmodule.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source 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 supporting routines for gmx::ICommandLineOptionsModule.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_commandline
41  */
42 #include "gmxpre.h"
43
44 #include "cmdlineoptionsmodule.h"
45
46 #include <memory>
47 #include <utility>
48
49 #include "gromacs/commandline/cmdlinehelpwriter.h"
50 #include "gromacs/commandline/cmdlinemodulemanager.h"
51 #include "gromacs/commandline/cmdlineparser.h"
52 #include "gromacs/options/behaviorcollection.h"
53 #include "gromacs/options/filenameoptionmanager.h"
54 #include "gromacs/options/ioptionsbehavior.h"
55 #include "gromacs/options/options.h"
56 #include "gromacs/utility/arrayref.h"
57 #include "gromacs/utility/gmxassert.h"
58 #include "gromacs/utility/stringutil.h"
59
60 namespace gmx
61 {
62
63 namespace
64 {
65
66 /********************************************************************
67  * CommandLineOptionsModuleSettings
68  */
69
70 class CommandLineOptionsModuleSettings : public ICommandLineOptionsModuleSettings
71 {
72 public:
73     explicit CommandLineOptionsModuleSettings(OptionsBehaviorCollection* behaviors) :
74         behaviors_(*behaviors)
75     {
76     }
77
78     const std::string& helpText() const { return helpText_; }
79
80     ArrayRef<const std::string> bugText() const { return bugText_; }
81
82     void setHelpText(const ArrayRef<const char* const>& help) override
83     {
84         helpText_ = joinStrings(help, "\n");
85     }
86
87     void setBugText(const ArrayRef<const char* const>& bug) override
88     {
89         bugText_ = std::vector<std::string>(bug.begin(), bug.end());
90     }
91     void addOptionsBehavior(const OptionsBehaviorPointer& behavior) override
92     {
93         behaviors_.addBehavior(behavior);
94     }
95
96 private:
97     std::string                helpText_;
98     std::vector<std::string>   bugText_;
99     OptionsBehaviorCollection& behaviors_;
100 };
101
102 /********************************************************************
103  * CommandLineOptionsModule
104  */
105
106 class CommandLineOptionsModule : public ICommandLineModule
107 {
108 public:
109     //! Shorthand for the factory function pointer type.
110     typedef ICommandLineOptionsModule::FactoryMethod FactoryMethod;
111
112     CommandLineOptionsModule(const char* name, const char* description, FactoryMethod factory) :
113         name_(name),
114         description_(description),
115         factory_(std::move(factory))
116     {
117     }
118     CommandLineOptionsModule(const char* name, const char* description, ICommandLineOptionsModulePointer module) :
119         name_(name),
120         description_(description),
121         module_(std::move(module))
122     {
123     }
124     const char* name() const override { return name_; }
125     const char* shortDescription() const override { return description_; }
126
127     void init(CommandLineModuleSettings* settings) override;
128     int  run(int argc, char* argv[]) override;
129     void writeHelp(const CommandLineHelpContext& context) const override;
130
131 private:
132     void parseOptions(int argc, char* argv[]);
133
134     const char*                      name_;
135     const char*                      description_;
136     FactoryMethod                    factory_;
137     ICommandLineOptionsModulePointer module_;
138 };
139
140 void CommandLineOptionsModule::init(CommandLineModuleSettings* settings)
141 {
142     if (!module_)
143     {
144         GMX_RELEASE_ASSERT(factory_ != nullptr, "Neither factory nor module provided");
145         module_ = factory_();
146     }
147     module_->init(settings);
148 }
149
150 int CommandLineOptionsModule::run(int argc, char* argv[])
151 {
152     GMX_RELEASE_ASSERT(module_, "init() has not been called");
153     parseOptions(argc, argv);
154     return module_->run();
155 }
156
157 void CommandLineOptionsModule::writeHelp(const CommandLineHelpContext& context) const
158 {
159     ICommandLineOptionsModulePointer moduleGuard;
160     ICommandLineOptionsModule*       module = module_.get();
161     if (!module)
162     {
163         GMX_RELEASE_ASSERT(factory_ != nullptr, "Neither factory nor module provided");
164         moduleGuard = factory_();
165         module      = moduleGuard.get();
166     }
167     Options                          options;
168     OptionsBehaviorCollection        behaviors(&options);
169     CommandLineOptionsModuleSettings settings(&behaviors);
170     module->initOptions(&options, &settings);
171     CommandLineHelpWriter(options)
172             .setHelpText(settings.helpText())
173             .setKnownIssues(settings.bugText())
174             .writeHelp(context);
175 }
176
177 void CommandLineOptionsModule::parseOptions(int argc, char* argv[])
178 {
179     FileNameOptionManager fileoptManager;
180     Options               options;
181
182     options.addManager(&fileoptManager);
183
184     OptionsBehaviorCollection        behaviors(&options);
185     CommandLineOptionsModuleSettings settings(&behaviors);
186     module_->initOptions(&options, &settings);
187     {
188         CommandLineParser parser(&options);
189         parser.parse(&argc, argv);
190         behaviors.optionsFinishing();
191         options.finish();
192     }
193     module_->optionsFinished();
194     behaviors.optionsFinished();
195 }
196
197 } // namespace
198
199 /********************************************************************
200  * ICommandLineOptionsModuleSettings
201  */
202
203 ICommandLineOptionsModuleSettings::~ICommandLineOptionsModuleSettings() {}
204
205 /********************************************************************
206  * ICommandLineOptionsModule
207  */
208
209 ICommandLineOptionsModule::~ICommandLineOptionsModule() {}
210
211 // static
212 std::unique_ptr<ICommandLineModule> ICommandLineOptionsModule::createModule(const char* name,
213                                                                             const char* description,
214                                                                             ICommandLineOptionsModulePointer module)
215 {
216     return std::unique_ptr<ICommandLineModule>(
217             new CommandLineOptionsModule(name, description, std::move(module)));
218 }
219
220 // static
221 int ICommandLineOptionsModule::runAsMain(int           argc,
222                                          char*         argv[],
223                                          const char*   name,
224                                          const char*   description,
225                                          FactoryMethod factory)
226 {
227     CommandLineOptionsModule module(name, description, std::move(factory));
228     return CommandLineModuleManager::runAsMainSingleModule(argc, argv, &module);
229 }
230
231 // static
232 void ICommandLineOptionsModule::registerModuleFactory(CommandLineModuleManager* manager,
233                                                       const char*               name,
234                                                       const char*               description,
235                                                       FactoryMethod             factory)
236 {
237     CommandLineModulePointer module(new CommandLineOptionsModule(name, description, std::move(factory)));
238     manager->addModule(std::move(module));
239 }
240
241 // static
242 void ICommandLineOptionsModule::registerModuleDirect(CommandLineModuleManager*        manager,
243                                                      const char*                      name,
244                                                      const char*                      description,
245                                                      ICommandLineOptionsModulePointer module)
246 {
247     CommandLineModulePointer wrapperModule(createModule(name, description, std::move(module)));
248     manager->addModule(std::move(wrapperModule));
249 }
250
251 } // namespace gmx