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 //! Sets the option object to assign to.
65 explicit Impl(Options *options);
67 //! Returns true if a subsection has been set.
68 bool inSubSection() const { return sectionStack_.size() > 1; }
69 //! Returns the Options object for the current section.
70 Options ¤tSection() const { return *sectionStack_.back(); }
72 * Finds an option by the given name.
74 * \param[in] name Name of the option to look for.
75 * \returns Pointer to the found option, or NULL if none found.
77 * This function takes into account the flags specified, and may change
78 * the internal state of the assigner to match the option found.
79 * If no option is found, the internal state is not modified.
81 AbstractOptionStorage *findOption(const char *name);
83 //! Options object to assign to.
85 //! Recognize boolean option "name" also as "noname".
86 bool bAcceptBooleanNoPrefix_;
87 //! Look for options in all sections, not just the current one.
88 bool bNoStrictSectioning_;
90 * List of (sub)sections being assigned to.
92 * The first element always points to \a options_.
94 std::vector<Options *> sectionStack_;
95 //! Current option being assigned to, or NULL if none.
96 AbstractOptionStorage *currentOption_;
98 * Number of values assigned so far to the current option.
100 * Counts the number of attempted assignments, whether they have been
103 int currentValueCount_;
104 //! If true, a "no" prefix was given for the current boolean option.
105 bool reverseBoolean_;
108 OptionsAssigner::Impl::Impl(Options *options)
109 : options_(*options), bAcceptBooleanNoPrefix_(false),
110 bNoStrictSectioning_(false), currentOption_(NULL),
111 currentValueCount_(0), reverseBoolean_(false)
113 sectionStack_.push_back(&options_);
116 AbstractOptionStorage *
117 OptionsAssigner::Impl::findOption(const char *name)
119 GMX_RELEASE_ASSERT(currentOption_ == NULL,
120 "Cannot search for another option while processing one");
121 AbstractOptionStorage *option = NULL;
122 Options *section = NULL;
123 Options *root = ¤tSection();
124 Options *oldRoot = NULL;
126 std::deque<Options *> searchList;
127 searchList.push_back(root);
128 while (option == NULL && !searchList.empty())
130 section = searchList.front();
131 option = section->impl_->findOption(name);
132 if (option == NULL && bAcceptBooleanNoPrefix_)
134 if (name[0] == 'n' && name[1] == 'o')
136 option = section->impl_->findOption(name + 2);
137 if (option != NULL && option->isBoolean())
139 reverseBoolean_ = true;
147 searchList.pop_front();
148 if (bNoStrictSectioning_)
150 Options::Impl::SubSectionList::const_iterator i;
151 for (i = section->impl_->subSections_.begin();
152 i != section->impl_->subSections_.end(); ++i)
156 searchList.push_back(*i);
159 if (searchList.empty() && root != &options_)
161 root = root->impl_->parent_;
163 searchList.push_back(root);
167 if (bNoStrictSectioning_ && option != NULL)
171 sectionStack_.pop_back();
174 std::vector<Options *> sections;
175 while (section != ¤tSection())
177 sections.push_back(section);
178 section = section->impl_->parent_;
180 while (!sections.empty())
182 sectionStack_.push_back(sections.back());
189 /********************************************************************
193 OptionsAssigner::OptionsAssigner(Options *options)
194 : impl_(new Impl(options))
198 OptionsAssigner::~OptionsAssigner()
202 void OptionsAssigner::setAcceptBooleanNoPrefix(bool bEnabled)
204 impl_->bAcceptBooleanNoPrefix_ = bEnabled;
207 void OptionsAssigner::setNoStrictSectioning(bool bEnabled)
209 impl_->bNoStrictSectioning_ = bEnabled;
212 void OptionsAssigner::start()
214 impl_->options_.impl_->startSource();
217 void OptionsAssigner::startSubSection(const char *name)
219 Options *section = impl_->currentSection().impl_->findSubSection(name);
222 GMX_THROW(InvalidInputError("Unknown subsection"));
224 impl_->sectionStack_.push_back(section);
227 void OptionsAssigner::startOption(const char *name)
229 GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
230 AbstractOptionStorage *option = impl_->findOption(name);
233 GMX_THROW(InvalidInputError("Unknown option"));
236 impl_->currentOption_ = option;
237 impl_->currentValueCount_ = 0;
240 void OptionsAssigner::appendValue(const std::string &value)
242 AbstractOptionStorage *option = impl_->currentOption_;
243 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
244 ++impl_->currentValueCount_;
245 option->appendValue(value);
248 void OptionsAssigner::finishOption()
250 AbstractOptionStorage *option = impl_->currentOption_;
251 GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
252 bool bBoolReverseValue = false;
253 if (option->isBoolean())
255 if (impl_->currentValueCount_ == 0)
257 // Should not throw, otherwise something is wrong.
258 // TODO: Get rid of the hard-coded values.
259 option->appendValue(impl_->reverseBoolean_ ? "0" : "1");
261 else if (impl_->reverseBoolean_)
263 bBoolReverseValue = true;
266 impl_->currentOption_ = NULL;
267 impl_->reverseBoolean_ = false;
269 if (bBoolReverseValue)
271 GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix"));
275 void OptionsAssigner::finishSubSection()
277 // Should only be called if we are in a subsection.
278 GMX_RELEASE_ASSERT(impl_->inSubSection(), "startSubSection() not called");
279 impl_->sectionStack_.pop_back();
282 void OptionsAssigner::finish()
284 GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
285 if (impl_->bNoStrictSectioning_)
287 while (impl_->inSubSection())
292 GMX_RELEASE_ASSERT(!impl_->inSubSection(), "finishSubSection() not called");