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/fatalerror/exceptions.h"
43 #include "gromacs/fatalerror/gmxassert.h"
44 #include "gromacs/options/abstractoptionstorage.h"
45 #include "gromacs/options/options.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 Options *oldRoot = root;
122 root = root->_impl->_parent;
124 searchList.push_back(root);
128 if (hasFlag(efNoStrictSectioning) && option != NULL)
132 _sectionStack.pop_back();
135 std::vector<Options *> sections;
136 while (section != ¤tSection())
138 sections.push_back(section);
139 section = section->_impl->_parent;
141 while (!sections.empty())
143 _sectionStack.push_back(sections.back());
150 /********************************************************************
154 OptionsAssigner::OptionsAssigner(Options *options)
155 : _impl(new Impl(options))
159 OptionsAssigner::~OptionsAssigner()
163 void OptionsAssigner::setAcceptBooleanNoPrefix(bool enabled)
165 _impl->setFlag(Impl::efAcceptBooleanNoPrefix, enabled);
168 void OptionsAssigner::setNoStrictSectioning(bool enabled)
170 _impl->setFlag(Impl::efNoStrictSectioning, enabled);
173 void OptionsAssigner::start()
175 _impl->_options._impl->startSource();
178 void OptionsAssigner::startSubSection(const char *name)
180 Options *section = _impl->currentSection()._impl->findSubSection(name);
183 GMX_THROW(InvalidInputError("Unknown subsection"));
185 _impl->_sectionStack.push_back(section);
188 void OptionsAssigner::startOption(const char *name)
190 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
191 AbstractOptionStorage *option = _impl->findOption(name);
194 GMX_THROW(InvalidInputError("Unknown option"));
197 _impl->_currentOption = option;
198 _impl->_currentValueCount = 0;
201 void OptionsAssigner::appendValue(const std::string &value)
203 AbstractOptionStorage *option = _impl->_currentOption;
204 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
205 // Does not count correctly, but the actual count is not really used.
206 // TODO: Rename the variable to better reflect the usage.
207 ++_impl->_currentValueCount;
208 option->appendValue(value);
211 void OptionsAssigner::finishOption()
213 AbstractOptionStorage *option = _impl->_currentOption;
214 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
215 bool bBoolReverseValue = false;
216 if (option->isBoolean())
218 if (_impl->_currentValueCount == 0)
220 // Should not throw, otherwise something is wrong.
221 // TODO: Get rid of the hard-coded values.
222 option->appendValue(_impl->_reverseBoolean ? "0" : "1");
224 else if (_impl->_reverseBoolean)
226 bBoolReverseValue = true;
229 _impl->_currentOption = NULL;
230 _impl->_reverseBoolean = false;
232 if (bBoolReverseValue)
234 GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix"));
238 void OptionsAssigner::finishSubSection()
240 // Should only be called if we are in a subsection.
241 GMX_RELEASE_ASSERT(_impl->inSubSection(), "startSubSection() not called");
242 _impl->_sectionStack.pop_back();
245 void OptionsAssigner::finish()
247 GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called");
248 if (_impl->hasFlag(Impl::efNoStrictSectioning))
250 while (_impl->inSubSection())
255 GMX_RELEASE_ASSERT(!_impl->inSubSection(), "finishSubSection() not called");