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 "optionsassigner-impl.h"
48 #include "options-impl.h"
53 /********************************************************************
54 * OptionsAssigner::Impl
57 OptionsAssigner::Impl::Impl(Options *options)
58 : _options(*options), _flags(0), _currentOption(NULL),
59 _currentValueCount(0), _reverseBoolean(false)
61 _sectionStack.push_back(&_options);
64 void OptionsAssigner::Impl::setFlag(OptionsAssigner::Impl::Flag flag, bool bSet)
76 AbstractOptionStorage *
77 OptionsAssigner::Impl::findOption(const char *name)
79 GMX_RELEASE_ASSERT(_currentOption == NULL,
80 "Cannot search for another option while processing one");
81 AbstractOptionStorage *option = NULL;
82 Options *section = NULL;
83 Options *root = ¤tSection();
84 Options *oldRoot = NULL;
86 std::deque<Options *> searchList;
87 searchList.push_back(root);
88 while (option == NULL && !searchList.empty())
90 section = searchList.front();
91 option = section->_impl->findOption(name);
92 if (option == NULL && hasFlag(efAcceptBooleanNoPrefix))
94 if (name[0] == 'n' && name[1] == 'o')
96 option = section->_impl->findOption(name + 2);
97 if (option != NULL && option->isBoolean())
99 _reverseBoolean = true;
107 searchList.pop_front();
108 if (hasFlag(efNoStrictSectioning))
110 Options::Impl::SubSectionList::const_iterator i;
111 for (i = section->_impl->_subSections.begin();
112 i != section->_impl->_subSections.end(); ++i)
116 searchList.push_back(*i);
119 if (searchList.empty() && root != &_options)
121 root = root->_impl->_parent;
123 searchList.push_back(root);
127 if (hasFlag(efNoStrictSectioning) && option != NULL)
131 _sectionStack.pop_back();
134 std::vector<Options *> sections;
135 while (section != ¤tSection())
137 sections.push_back(section);
138 section = section->_impl->_parent;
140 while (!sections.empty())
142 _sectionStack.push_back(sections.back());
149 /********************************************************************
153 OptionsAssigner::OptionsAssigner(Options *options)
154 : _impl(new Impl(options))
158 OptionsAssigner::~OptionsAssigner()
162 void OptionsAssigner::setAcceptBooleanNoPrefix(bool enabled)
164 _impl->setFlag(Impl::efAcceptBooleanNoPrefix, enabled);
167 void OptionsAssigner::setNoStrictSectioning(bool enabled)
169 _impl->setFlag(Impl::efNoStrictSectioning, enabled);
172 void OptionsAssigner::start()
174 _impl->_options._impl->startSource();
177 void OptionsAssigner::startSubSection(const char *name)
179 Options *section = _impl->currentSection()._impl->findSubSection(name);
182 GMX_THROW(InvalidInputError("Unknown subsection"));
184 _impl->_sectionStack.push_back(section);
187 void OptionsAssigner::startOption(const char *name)
189 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
190 AbstractOptionStorage *option = _impl->findOption(name);
193 GMX_THROW(InvalidInputError("Unknown option"));
196 _impl->_currentOption = option;
197 _impl->_currentValueCount = 0;
200 void OptionsAssigner::appendValue(const std::string &value)
202 AbstractOptionStorage *option = _impl->_currentOption;
203 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
204 // Does not count correctly, but the actual count is not really used.
205 // TODO: Rename the variable to better reflect the usage.
206 ++_impl->_currentValueCount;
207 option->appendValue(value);
210 void OptionsAssigner::finishOption()
212 AbstractOptionStorage *option = _impl->_currentOption;
213 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
214 bool bBoolReverseValue = false;
215 if (option->isBoolean())
217 if (_impl->_currentValueCount == 0)
219 // Should not throw, otherwise something is wrong.
220 // TODO: Get rid of the hard-coded values.
221 option->appendValue(_impl->_reverseBoolean ? "0" : "1");
223 else if (_impl->_reverseBoolean)
225 bBoolReverseValue = true;
228 _impl->_currentOption = NULL;
229 _impl->_reverseBoolean = false;
231 if (bBoolReverseValue)
233 GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix"));
237 void OptionsAssigner::finishSubSection()
239 // Should only be called if we are in a subsection.
240 GMX_RELEASE_ASSERT(_impl->inSubSection(), "startSubSection() not called");
241 _impl->_sectionStack.pop_back();
244 void OptionsAssigner::finish()
246 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
247 if (_impl->hasFlag(Impl::efNoStrictSectioning))
249 while (_impl->inSubSection())
254 GMX_RELEASE_ASSERT(!_impl->inSubSection(), "finishSubSection() not called");