3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements gmx::OptionsAssigner.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_options
38 #include "gromacs/options/optionsassigner.h"
42 #include "gromacs/options/abstractoptionstorage.h"
43 #include "gromacs/options/options.h"
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/gmxassert.h"
47 #include "options-impl.h"
52 /********************************************************************
53 * OptionsAssigner::Impl
57 * Private implementation class for OptionsAssigner.
59 * \ingroup module_options
61 class OptionsAssigner::Impl
64 //! Possible flags for controlling assignment behavior.
67 //! Recognize boolean option "name" also as "noname".
68 efAcceptBooleanNoPrefix = 1<<0,
69 //! Look for options in all sections, not just the current one.
70 efNoStrictSectioning = 1<<1,
72 //! Sets the option object to assign to.
73 Impl(Options *options);
75 //! Sets or clears the given flag.
76 void setFlag(Flag flag, bool bSet);
78 //! Returns true if the given flag is set.
79 bool hasFlag(Flag flag) const { return _flags & flag; }
80 //! Returns true if a subsection has been set.
81 bool inSubSection() const { return _sectionStack.size() > 1; }
82 //! Returns the Options object for the current section.
83 Options ¤tSection() const { return *_sectionStack.back(); }
85 * Finds an option by the given name.
87 * \param[in] name Name of the option to look for.
88 * \returns Pointer to the found option, or NULL if none found.
90 * This function takes into account the flags specified, and may change
91 * the internal state of the assigner to match the option found.
92 * If no option is found, the internal state is not modified.
94 AbstractOptionStorage *findOption(const char *name);
96 //! Options object to assign to.
98 //! Flags that control assignment behavior.
101 * List of (sub)sections being assigned to.
103 * The first element always points to \a _options.
105 std::vector<Options *> _sectionStack;
106 //! Current option being assigned to, or NULL if none.
107 AbstractOptionStorage *_currentOption;
108 //! Number of values assigned so far to the current option.
109 int _currentValueCount;
110 //! If true, a "no" prefix was given for the current boolean option.
111 bool _reverseBoolean;
114 OptionsAssigner::Impl::Impl(Options *options)
115 : _options(*options), _flags(0), _currentOption(NULL),
116 _currentValueCount(0), _reverseBoolean(false)
118 _sectionStack.push_back(&_options);
121 void OptionsAssigner::Impl::setFlag(OptionsAssigner::Impl::Flag flag, bool bSet)
133 AbstractOptionStorage *
134 OptionsAssigner::Impl::findOption(const char *name)
136 GMX_RELEASE_ASSERT(_currentOption == NULL,
137 "Cannot search for another option while processing one");
138 AbstractOptionStorage *option = NULL;
139 Options *section = NULL;
140 Options *root = ¤tSection();
141 Options *oldRoot = NULL;
143 std::deque<Options *> searchList;
144 searchList.push_back(root);
145 while (option == NULL && !searchList.empty())
147 section = searchList.front();
148 option = section->_impl->findOption(name);
149 if (option == NULL && hasFlag(efAcceptBooleanNoPrefix))
151 if (name[0] == 'n' && name[1] == 'o')
153 option = section->_impl->findOption(name + 2);
154 if (option != NULL && option->isBoolean())
156 _reverseBoolean = true;
164 searchList.pop_front();
165 if (hasFlag(efNoStrictSectioning))
167 Options::Impl::SubSectionList::const_iterator i;
168 for (i = section->_impl->_subSections.begin();
169 i != section->_impl->_subSections.end(); ++i)
173 searchList.push_back(*i);
176 if (searchList.empty() && root != &_options)
178 root = root->_impl->_parent;
180 searchList.push_back(root);
184 if (hasFlag(efNoStrictSectioning) && option != NULL)
188 _sectionStack.pop_back();
191 std::vector<Options *> sections;
192 while (section != ¤tSection())
194 sections.push_back(section);
195 section = section->_impl->_parent;
197 while (!sections.empty())
199 _sectionStack.push_back(sections.back());
206 /********************************************************************
210 OptionsAssigner::OptionsAssigner(Options *options)
211 : _impl(new Impl(options))
215 OptionsAssigner::~OptionsAssigner()
219 void OptionsAssigner::setAcceptBooleanNoPrefix(bool enabled)
221 _impl->setFlag(Impl::efAcceptBooleanNoPrefix, enabled);
224 void OptionsAssigner::setNoStrictSectioning(bool enabled)
226 _impl->setFlag(Impl::efNoStrictSectioning, enabled);
229 void OptionsAssigner::start()
231 _impl->_options._impl->startSource();
234 void OptionsAssigner::startSubSection(const char *name)
236 Options *section = _impl->currentSection()._impl->findSubSection(name);
239 GMX_THROW(InvalidInputError("Unknown subsection"));
241 _impl->_sectionStack.push_back(section);
244 void OptionsAssigner::startOption(const char *name)
246 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
247 AbstractOptionStorage *option = _impl->findOption(name);
250 GMX_THROW(InvalidInputError("Unknown option"));
253 _impl->_currentOption = option;
254 _impl->_currentValueCount = 0;
257 void OptionsAssigner::appendValue(const std::string &value)
259 AbstractOptionStorage *option = _impl->_currentOption;
260 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
261 // Does not count correctly, but the actual count is not really used.
262 // TODO: Rename the variable to better reflect the usage.
263 ++_impl->_currentValueCount;
264 option->appendValue(value);
267 void OptionsAssigner::finishOption()
269 AbstractOptionStorage *option = _impl->_currentOption;
270 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
271 bool bBoolReverseValue = false;
272 if (option->isBoolean())
274 if (_impl->_currentValueCount == 0)
276 // Should not throw, otherwise something is wrong.
277 // TODO: Get rid of the hard-coded values.
278 option->appendValue(_impl->_reverseBoolean ? "0" : "1");
280 else if (_impl->_reverseBoolean)
282 bBoolReverseValue = true;
285 _impl->_currentOption = NULL;
286 _impl->_reverseBoolean = false;
288 if (bBoolReverseValue)
290 GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix"));
294 void OptionsAssigner::finishSubSection()
296 // Should only be called if we are in a subsection.
297 GMX_RELEASE_ASSERT(_impl->inSubSection(), "startSubSection() not called");
298 _impl->_sectionStack.pop_back();
301 void OptionsAssigner::finish()
303 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
304 if (_impl->hasFlag(Impl::efNoStrictSectioning))
306 while (_impl->inSubSection())
311 GMX_RELEASE_ASSERT(!_impl->inSubSection(), "finishSubSection() not called");