Merge remote-tracking branch 'origin/release-4-6'
[alexxy/gromacs.git] / src / gromacs / options / options.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements gmx::Options.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_options
37  */
38 #include "gromacs/options/options.h"
39
40 #include "gromacs/options/abstractoption.h"
41 #include "gromacs/options/abstractoptionstorage.h"
42 #include "gromacs/utility/exceptions.h"
43 #include "gromacs/utility/format.h"
44 #include "gromacs/utility/gmxassert.h"
45 #include "gromacs/utility/messagestringcollector.h"
46
47 #include "options-impl.h"
48
49 namespace gmx
50 {
51
52 /********************************************************************
53  * Options::Impl
54  */
55
56 Options::Impl::Impl(const char *name, const char *title)
57     : _name(name != NULL ? name : ""), _title(title != NULL ? title : ""),
58       _parent(NULL)
59 {
60 }
61
62 Options::Impl::~Impl()
63 {
64 }
65
66 Options *Options::Impl::findSubSection(const char *name) const
67 {
68     SubSectionList::const_iterator i;
69     for (i = _subSections.begin(); i != _subSections.end(); ++i)
70     {
71         if ((*i)->name() == name)
72         {
73             return *i;
74         }
75     }
76     return NULL;
77 }
78
79 AbstractOptionStorage *Options::Impl::findOption(const char *name) const
80 {
81     OptionList::const_iterator i;
82     for (i = _options.begin(); i != _options.end(); ++i)
83     {
84         if ((*i)->name() == name)
85         {
86             return i->get();
87         }
88     }
89     return NULL;
90 }
91
92 void Options::Impl::startSource()
93 {
94     OptionList::const_iterator i;
95     for (i = _options.begin(); i != _options.end(); ++i)
96     {
97         AbstractOptionStorage &option = **i;
98         option.startSource();
99     }
100     SubSectionList::const_iterator j;
101     for (j = _subSections.begin(); j != _subSections.end(); ++j)
102     {
103         Options &section = **j;
104         section._impl->startSource();
105     }
106 }
107
108 /********************************************************************
109  * Options
110  */
111
112 Options::Options(const char *name, const char *title)
113     : _impl(new Impl(name, title))
114 {
115 }
116
117 Options::~Options()
118 {
119 }
120
121 const std::string &Options::name() const
122 {
123     return _impl->_name;
124 }
125
126 const std::string &Options::title() const
127 {
128     return _impl->_title;
129 }
130
131 const std::string &Options::description() const
132 {
133     return _impl->_description;
134 }
135
136 void Options::setDescription(const std::string &desc)
137 {
138     _impl->_description = desc;
139 }
140
141 void Options::addSubSection(Options *section)
142 {
143     // Make sure that section is not already inserted somewhere.
144     GMX_RELEASE_ASSERT(section->_impl->_parent == NULL,
145                        "Cannot add as subsection twice");
146     // Make sure that there are no duplicate sections.
147     GMX_RELEASE_ASSERT(_impl->findSubSection(section->name().c_str()) == NULL,
148                        "Duplicate subsection name");
149     _impl->_subSections.push_back(section);
150     section->_impl->_parent = this;
151 }
152
153 void Options::addOption(const AbstractOption &settings)
154 {
155     AbstractOptionStoragePointer option(settings.createStorage());
156     if (_impl->findOption(option->name().c_str()) != NULL)
157     {
158         GMX_THROW(APIError("Duplicate option: " + option->name()));
159     }
160     _impl->_options.push_back(move(option));
161 }
162
163 bool Options::isSet(const char *name) const
164 {
165     AbstractOptionStorage *option = _impl->findOption(name);
166     return (option != NULL ? option->isSet() : false);
167 }
168
169 void Options::finish()
170 {
171     MessageStringCollector errors;
172     Impl::OptionList::const_iterator i;
173     for (i = _impl->_options.begin(); i != _impl->_options.end(); ++i)
174     {
175         AbstractOptionStorage &option = **i;
176         try
177         {
178             option.finish();
179         }
180         catch (const UserInputError &ex)
181         {
182             MessageStringContext context(&errors, "In option " + option.name());
183             errors.append(ex.what());
184         }
185     }
186     Impl::SubSectionList::const_iterator j;
187     for (j = _impl->_subSections.begin(); j != _impl->_subSections.end(); ++j)
188     {
189         Options &section = **j;
190         try
191         {
192             section.finish();
193         }
194         catch (const UserInputError &ex)
195         {
196             errors.append(ex.what());
197         }
198     }
199     if (!errors.isEmpty())
200     {
201         // TODO: This exception type may not always be appropriate.
202         GMX_THROW(InvalidInputError(errors.toString()));
203     }
204 }
205
206 } // namespace gmx