Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / options / optionsassigner.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::OptionsAssigner.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_options
37  */
38 #include "gromacs/options/optionsassigner.h"
39
40 #include <deque>
41
42 #include "gromacs/options/abstractoptionstorage.h"
43 #include "gromacs/options/options.h"
44 #include "gromacs/utility/exceptions.h"
45 #include "gromacs/utility/gmxassert.h"
46
47 #include "options-impl.h"
48
49 namespace gmx
50 {
51
52 /********************************************************************
53  * OptionsAssigner::Impl
54  */
55
56 /*! \internal \brief
57  * Private implementation class for OptionsAssigner.
58  *
59  * \ingroup module_options
60  */
61 class OptionsAssigner::Impl
62 {
63     public:
64         //! Sets the option object to assign to.
65         explicit Impl(Options *options);
66
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 &currentSection() const { return *sectionStack_.back(); }
71         /*! \brief
72          * Finds an option by the given name.
73          *
74          * \param[in] name  Name of the option to look for.
75          * \returns Pointer to the found option, or NULL if none found.
76          *
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.
80          */
81         AbstractOptionStorage *findOption(const char *name);
82
83         //! Options object to assign to.
84         Options                &options_;
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_;
89         /*! \brief
90          * List of (sub)sections being assigned to.
91          *
92          * The first element always points to \a options_.
93          */
94         std::vector<Options *>  sectionStack_;
95         //! Current option being assigned to, or NULL if none.
96         AbstractOptionStorage  *currentOption_;
97         /*! \brief
98          * Number of values assigned so far to the current option.
99          *
100          * Counts the number of attempted assignments, whether they have been
101          * successful or not.
102          */
103         int                     currentValueCount_;
104         //! If true, a "no" prefix was given for the current boolean option.
105         bool                    reverseBoolean_;
106 };
107
108 OptionsAssigner::Impl::Impl(Options *options)
109     : options_(*options), bAcceptBooleanNoPrefix_(false),
110       bNoStrictSectioning_(false), currentOption_(NULL),
111       currentValueCount_(0), reverseBoolean_(false)
112 {
113     sectionStack_.push_back(&options_);
114 }
115
116 AbstractOptionStorage *
117 OptionsAssigner::Impl::findOption(const char *name)
118 {
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    = &currentSection();
124     Options               *oldRoot = NULL;
125     int                    upcount = 0;
126     std::deque<Options *>  searchList;
127     searchList.push_back(root);
128     while (option == NULL && !searchList.empty())
129     {
130         section = searchList.front();
131         option  = section->impl_->findOption(name);
132         if (option == NULL && bAcceptBooleanNoPrefix_)
133         {
134             if (name[0] == 'n' && name[1] == 'o')
135             {
136                 option = section->impl_->findOption(name + 2);
137                 if (option != NULL && option->isBoolean())
138                 {
139                     reverseBoolean_ = true;
140                 }
141                 else
142                 {
143                     option = NULL;
144                 }
145             }
146         }
147         searchList.pop_front();
148         if (bNoStrictSectioning_)
149         {
150             Options::Impl::SubSectionList::const_iterator i;
151             for (i = section->impl_->subSections_.begin();
152                  i != section->impl_->subSections_.end(); ++i)
153             {
154                 if (*i != oldRoot)
155                 {
156                     searchList.push_back(*i);
157                 }
158             }
159             if (searchList.empty() && root != &options_)
160             {
161                 root = root->impl_->parent_;
162                 ++upcount;
163                 searchList.push_back(root);
164             }
165         }
166     }
167     if (bNoStrictSectioning_ && option != NULL)
168     {
169         while (upcount > 0)
170         {
171             sectionStack_.pop_back();
172             --upcount;
173         }
174         std::vector<Options *> sections;
175         while (section != &currentSection())
176         {
177             sections.push_back(section);
178             section = section->impl_->parent_;
179         }
180         while (!sections.empty())
181         {
182             sectionStack_.push_back(sections.back());
183             sections.pop_back();
184         }
185     }
186     return option;
187 }
188
189 /********************************************************************
190  * OptionsAssigner
191  */
192
193 OptionsAssigner::OptionsAssigner(Options *options)
194     : impl_(new Impl(options))
195 {
196 }
197
198 OptionsAssigner::~OptionsAssigner()
199 {
200 }
201
202 void OptionsAssigner::setAcceptBooleanNoPrefix(bool bEnabled)
203 {
204     impl_->bAcceptBooleanNoPrefix_ = bEnabled;
205 }
206
207 void OptionsAssigner::setNoStrictSectioning(bool bEnabled)
208 {
209     impl_->bNoStrictSectioning_ = bEnabled;
210 }
211
212 void OptionsAssigner::start()
213 {
214     impl_->options_.impl_->startSource();
215 }
216
217 void OptionsAssigner::startSubSection(const char *name)
218 {
219     Options *section = impl_->currentSection().impl_->findSubSection(name);
220     if (section == NULL)
221     {
222         GMX_THROW(InvalidInputError("Unknown subsection"));
223     }
224     impl_->sectionStack_.push_back(section);
225 }
226
227 void OptionsAssigner::startOption(const char *name)
228 {
229     GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
230     AbstractOptionStorage *option = impl_->findOption(name);
231     if (option == NULL)
232     {
233         GMX_THROW(InvalidInputError("Unknown option"));
234     }
235     option->startSet();
236     impl_->currentOption_     = option;
237     impl_->currentValueCount_ = 0;
238 }
239
240 void OptionsAssigner::appendValue(const std::string &value)
241 {
242     AbstractOptionStorage *option = impl_->currentOption_;
243     GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
244     ++impl_->currentValueCount_;
245     option->appendValue(value);
246 }
247
248 void OptionsAssigner::finishOption()
249 {
250     AbstractOptionStorage *option = impl_->currentOption_;
251     GMX_RELEASE_ASSERT(option != NULL, "startOption() not called");
252     bool                   bBoolReverseValue = false;
253     if (option->isBoolean())
254     {
255         if (impl_->currentValueCount_ == 0)
256         {
257             // Should not throw, otherwise something is wrong.
258             // TODO: Get rid of the hard-coded values.
259             option->appendValue(impl_->reverseBoolean_ ? "0" : "1");
260         }
261         else if (impl_->reverseBoolean_)
262         {
263             bBoolReverseValue = true;
264         }
265     }
266     impl_->currentOption_  = NULL;
267     impl_->reverseBoolean_ = false;
268     option->finishSet();
269     if (bBoolReverseValue)
270     {
271         GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix"));
272     }
273 }
274
275 void OptionsAssigner::finishSubSection()
276 {
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();
280 }
281
282 void OptionsAssigner::finish()
283 {
284     GMX_RELEASE_ASSERT(impl_->currentOption_ == NULL, "finishOption() not called");
285     if (impl_->bNoStrictSectioning_)
286     {
287         while (impl_->inSubSection())
288         {
289             finishSubSection();
290         }
291     }
292     GMX_RELEASE_ASSERT(!impl_->inSubSection(), "finishSubSection() not called");
293 }
294
295 } // namespace gmx