xref: /aosp_15_r20/external/libconfig/contrib/chained/libconfig_chained.h (revision 2e9d491483b805f09ea864149eadd5680efcc72a)
1*2e9d4914SAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
2*2e9d4914SAndroid Build Coastguard Worker    libconfig - A library for processing structured configuration files
3*2e9d4914SAndroid Build Coastguard Worker    libconfig chained - Extension for reading the configuration and defining
4*2e9d4914SAndroid Build Coastguard Worker                        the configuration specification at once.
5*2e9d4914SAndroid Build Coastguard Worker    Copyright (C) 2016 Richard Schubert
6*2e9d4914SAndroid Build Coastguard Worker 
7*2e9d4914SAndroid Build Coastguard Worker    This file is part of libconfig contributions.
8*2e9d4914SAndroid Build Coastguard Worker 
9*2e9d4914SAndroid Build Coastguard Worker    This library is free software; you can redistribute it and/or
10*2e9d4914SAndroid Build Coastguard Worker    modify it under the terms of the GNU Lesser General Public License
11*2e9d4914SAndroid Build Coastguard Worker    as published by the Free Software Foundation; either version 2.1 of
12*2e9d4914SAndroid Build Coastguard Worker    the License, or (at your option) any later version.
13*2e9d4914SAndroid Build Coastguard Worker 
14*2e9d4914SAndroid Build Coastguard Worker    This library is distributed in the hope that it will be useful, but
15*2e9d4914SAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
16*2e9d4914SAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17*2e9d4914SAndroid Build Coastguard Worker    Lesser General Public License for more details.
18*2e9d4914SAndroid Build Coastguard Worker 
19*2e9d4914SAndroid Build Coastguard Worker    You should have received a copy of the GNU Library General Public
20*2e9d4914SAndroid Build Coastguard Worker    License along with this library; if not, see
21*2e9d4914SAndroid Build Coastguard Worker    <http://www.gnu.org/licenses/>.
22*2e9d4914SAndroid Build Coastguard Worker    ----------------------------------------------------------------------------
23*2e9d4914SAndroid Build Coastguard Worker */
24*2e9d4914SAndroid Build Coastguard Worker 
25*2e9d4914SAndroid Build Coastguard Worker #pragma once
26*2e9d4914SAndroid Build Coastguard Worker #ifndef _CHAINED_LIBCONFIG_H_
27*2e9d4914SAndroid Build Coastguard Worker #define _CHAINED_LIBCONFIG_H_
28*2e9d4914SAndroid Build Coastguard Worker 
29*2e9d4914SAndroid Build Coastguard Worker #include <libconfig.h++>
30*2e9d4914SAndroid Build Coastguard Worker #include <cassert>
31*2e9d4914SAndroid Build Coastguard Worker #include <fstream>
32*2e9d4914SAndroid Build Coastguard Worker #include <sstream>
33*2e9d4914SAndroid Build Coastguard Worker #include <iostream>
34*2e9d4914SAndroid Build Coastguard Worker 
35*2e9d4914SAndroid Build Coastguard Worker namespace libconfig
36*2e9d4914SAndroid Build Coastguard Worker {
37*2e9d4914SAndroid Build Coastguard Worker 	class ChainedSetting
38*2e9d4914SAndroid Build Coastguard Worker 	{
39*2e9d4914SAndroid Build Coastguard Worker 		struct Variant
40*2e9d4914SAndroid Build Coastguard Worker 		{
41*2e9d4914SAndroid Build Coastguard Worker 		private:
42*2e9d4914SAndroid Build Coastguard Worker 			bool			isSet;
43*2e9d4914SAndroid Build Coastguard Worker 			Setting::Type	type;
44*2e9d4914SAndroid Build Coastguard Worker 
45*2e9d4914SAndroid Build Coastguard Worker 			bool			value_bool;
46*2e9d4914SAndroid Build Coastguard Worker 			int64_t			value_int;
47*2e9d4914SAndroid Build Coastguard Worker 			double			value_float;
48*2e9d4914SAndroid Build Coastguard Worker 			std::string		value_string;
49*2e9d4914SAndroid Build Coastguard Worker 
50*2e9d4914SAndroid Build Coastguard Worker 		public:
51*2e9d4914SAndroid Build Coastguard Worker 
VariantVariant52*2e9d4914SAndroid Build Coastguard Worker 			Variant()
53*2e9d4914SAndroid Build Coastguard Worker 				: isSet(false)
54*2e9d4914SAndroid Build Coastguard Worker 				, type(Setting::TypeNone)
55*2e9d4914SAndroid Build Coastguard Worker 			{
56*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant57*2e9d4914SAndroid Build Coastguard Worker 			Variant(bool value)
58*2e9d4914SAndroid Build Coastguard Worker 			{
59*2e9d4914SAndroid Build Coastguard Worker 				value_bool = value;
60*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
61*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeBoolean;
62*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant63*2e9d4914SAndroid Build Coastguard Worker 			Variant(int32_t value)
64*2e9d4914SAndroid Build Coastguard Worker 			{
65*2e9d4914SAndroid Build Coastguard Worker 				value_int = value;
66*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
67*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeInt;
68*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant69*2e9d4914SAndroid Build Coastguard Worker 			Variant(int64_t value)
70*2e9d4914SAndroid Build Coastguard Worker 			{
71*2e9d4914SAndroid Build Coastguard Worker 				value_int = value;
72*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
73*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeInt64;
74*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant75*2e9d4914SAndroid Build Coastguard Worker 			Variant(double value)
76*2e9d4914SAndroid Build Coastguard Worker 			{
77*2e9d4914SAndroid Build Coastguard Worker 				value_float = value;
78*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
79*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeFloat;
80*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant81*2e9d4914SAndroid Build Coastguard Worker 			Variant(std::string& value)
82*2e9d4914SAndroid Build Coastguard Worker 			{
83*2e9d4914SAndroid Build Coastguard Worker 				value_string = value;
84*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
85*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeString;
86*2e9d4914SAndroid Build Coastguard Worker 			}
VariantVariant87*2e9d4914SAndroid Build Coastguard Worker 			Variant(const char* value)
88*2e9d4914SAndroid Build Coastguard Worker 			{
89*2e9d4914SAndroid Build Coastguard Worker 				value_string = value;
90*2e9d4914SAndroid Build Coastguard Worker 				isSet = true;
91*2e9d4914SAndroid Build Coastguard Worker 				type = Setting::TypeString;
92*2e9d4914SAndroid Build Coastguard Worker 			}
93*2e9d4914SAndroid Build Coastguard Worker 
94*2e9d4914SAndroid Build Coastguard Worker 			operator bool() const { return value_bool; }
95*2e9d4914SAndroid Build Coastguard Worker 			operator int() const { return (int)value_int; }
96*2e9d4914SAndroid Build Coastguard Worker 			operator unsigned int() const { return (unsigned int)value_int; }
97*2e9d4914SAndroid Build Coastguard Worker 			operator long() const { return (long)value_int; }
98*2e9d4914SAndroid Build Coastguard Worker 			operator unsigned long() const { return (unsigned long)value_int; }
99*2e9d4914SAndroid Build Coastguard Worker 			operator long long() const { return (long long)value_int; }
100*2e9d4914SAndroid Build Coastguard Worker 			operator unsigned long long() const { return (unsigned long long)value_int; }
101*2e9d4914SAndroid Build Coastguard Worker 			operator double() const { return value_float; }
102*2e9d4914SAndroid Build Coastguard Worker 			operator float() const { return (float)value_float; }
stringVariant103*2e9d4914SAndroid Build Coastguard Worker 			operator std::string() const { return value_string; }
104*2e9d4914SAndroid Build Coastguard Worker 
IsSetVariant105*2e9d4914SAndroid Build Coastguard Worker 			const bool IsSet() const
106*2e9d4914SAndroid Build Coastguard Worker 			{
107*2e9d4914SAndroid Build Coastguard Worker 				return isSet;
108*2e9d4914SAndroid Build Coastguard Worker 			}
109*2e9d4914SAndroid Build Coastguard Worker 
GetTypeVariant110*2e9d4914SAndroid Build Coastguard Worker 			const Setting::Type GetType() const
111*2e9d4914SAndroid Build Coastguard Worker 			{
112*2e9d4914SAndroid Build Coastguard Worker 				return type;
113*2e9d4914SAndroid Build Coastguard Worker 			}
114*2e9d4914SAndroid Build Coastguard Worker 		};
115*2e9d4914SAndroid Build Coastguard Worker 
116*2e9d4914SAndroid Build Coastguard Worker 	public:
117*2e9d4914SAndroid Build Coastguard Worker 
118*2e9d4914SAndroid Build Coastguard Worker 		// Starting point for method chained libconfig.
119*2e9d4914SAndroid Build Coastguard Worker 		// Pass a custom ostream to intercept any error messages (useful for Applications with UI).
120*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting(Setting& setting, std::ostream& err = std::cerr)
121*2e9d4914SAndroid Build Coastguard Worker 			: name(setting.isRoot() ? "<root>" : (setting.getName() ? setting.getName() : ""))
122*2e9d4914SAndroid Build Coastguard Worker 			, index(setting.getIndex())
123*2e9d4914SAndroid Build Coastguard Worker 			, parent(NULL)
124*2e9d4914SAndroid Build Coastguard Worker 			, setting(&setting)
125*2e9d4914SAndroid Build Coastguard Worker 			, err(err)
126*2e9d4914SAndroid Build Coastguard Worker 			, isSettingMandatory(false)
127*2e9d4914SAndroid Build Coastguard Worker 			, anySettingIsMissing(false)
128*2e9d4914SAndroid Build Coastguard Worker 			, anyMandatorySettingIsMissing(false)
129*2e9d4914SAndroid Build Coastguard Worker 			, capturedSpecification(NULL)
130*2e9d4914SAndroid Build Coastguard Worker 			, capturedSetting(NULL)
131*2e9d4914SAndroid Build Coastguard Worker 		{
132*2e9d4914SAndroid Build Coastguard Worker 		}
133*2e9d4914SAndroid Build Coastguard Worker 
134*2e9d4914SAndroid Build Coastguard Worker 		// Starts capturing any configuration readings into the temporary config object.
captureExpectedSpecification(Config * temporaryConfigSpecification)135*2e9d4914SAndroid Build Coastguard Worker 		void captureExpectedSpecification(Config* temporaryConfigSpecification)
136*2e9d4914SAndroid Build Coastguard Worker 		{
137*2e9d4914SAndroid Build Coastguard Worker 			capturedSpecification = temporaryConfigSpecification;
138*2e9d4914SAndroid Build Coastguard Worker 			capturedSetting = &capturedSpecification->getRoot();
139*2e9d4914SAndroid Build Coastguard Worker 		}
140*2e9d4914SAndroid Build Coastguard Worker 
141*2e9d4914SAndroid Build Coastguard Worker 		// Returns the captured configuration specification,
142*2e9d4914SAndroid Build Coastguard Worker 		// premised captureExpectedSpecification() was called earlier.
143*2e9d4914SAndroid Build Coastguard Worker 		// The path parameter is needed to write the configuration
144*2e9d4914SAndroid Build Coastguard Worker 		// to disk before it can be read into a usable string.
getCapturedSpecification(const std::string & tempFilePath)145*2e9d4914SAndroid Build Coastguard Worker 		std::string getCapturedSpecification(const std::string& tempFilePath)
146*2e9d4914SAndroid Build Coastguard Worker 		{
147*2e9d4914SAndroid Build Coastguard Worker 			try
148*2e9d4914SAndroid Build Coastguard Worker 			{
149*2e9d4914SAndroid Build Coastguard Worker 				capturedSpecification->writeFile(tempFilePath.c_str());
150*2e9d4914SAndroid Build Coastguard Worker 			}
151*2e9d4914SAndroid Build Coastguard Worker 			catch (const FileIOException&)
152*2e9d4914SAndroid Build Coastguard Worker 			{
153*2e9d4914SAndroid Build Coastguard Worker 				err << "I/O error while writing temporary setting file: " << tempFilePath << std::endl;
154*2e9d4914SAndroid Build Coastguard Worker 				return "";
155*2e9d4914SAndroid Build Coastguard Worker 			}
156*2e9d4914SAndroid Build Coastguard Worker 
157*2e9d4914SAndroid Build Coastguard Worker 			std::ifstream t(tempFilePath);
158*2e9d4914SAndroid Build Coastguard Worker 			if (!t.is_open())
159*2e9d4914SAndroid Build Coastguard Worker 			{
160*2e9d4914SAndroid Build Coastguard Worker 				err << "I/O error while reading temporary setting file: " << tempFilePath << std::endl;
161*2e9d4914SAndroid Build Coastguard Worker 				return "";
162*2e9d4914SAndroid Build Coastguard Worker 			}
163*2e9d4914SAndroid Build Coastguard Worker 			std::stringstream buffer;
164*2e9d4914SAndroid Build Coastguard Worker 			buffer << t.rdbuf();
165*2e9d4914SAndroid Build Coastguard Worker 
166*2e9d4914SAndroid Build Coastguard Worker 			capturedSpecification = NULL;
167*2e9d4914SAndroid Build Coastguard Worker 
168*2e9d4914SAndroid Build Coastguard Worker 			return buffer.str();
169*2e9d4914SAndroid Build Coastguard Worker 		}
170*2e9d4914SAndroid Build Coastguard Worker 
171*2e9d4914SAndroid Build Coastguard Worker 		// Defines the default value for this setting if missing from config file.
172*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
defaultValue(T defaultValue)173*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting& defaultValue(T defaultValue)
174*2e9d4914SAndroid Build Coastguard Worker 		{
175*2e9d4914SAndroid Build Coastguard Worker 			defaultVal = defaultValue;
176*2e9d4914SAndroid Build Coastguard Worker 			return *this;
177*2e9d4914SAndroid Build Coastguard Worker 		}
178*2e9d4914SAndroid Build Coastguard Worker 
179*2e9d4914SAndroid Build Coastguard Worker 		// Defines the inclusive minimum value for this setting.
180*2e9d4914SAndroid Build Coastguard Worker 		// A lesser value set in a configuration file will be clamped to this limit.
181*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
min(T min)182*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting& min(T min)
183*2e9d4914SAndroid Build Coastguard Worker 		{
184*2e9d4914SAndroid Build Coastguard Worker 			minVal = min;
185*2e9d4914SAndroid Build Coastguard Worker 			return *this;
186*2e9d4914SAndroid Build Coastguard Worker 		}
187*2e9d4914SAndroid Build Coastguard Worker 
188*2e9d4914SAndroid Build Coastguard Worker 		// Defines the inclusive maximum value for this setting.
189*2e9d4914SAndroid Build Coastguard Worker 		// A greater value set in a configuration file will be clamped to this limit.
190*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
max(T max)191*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting& max(T max)
192*2e9d4914SAndroid Build Coastguard Worker 		{
193*2e9d4914SAndroid Build Coastguard Worker 			maxVal = max;
194*2e9d4914SAndroid Build Coastguard Worker 			return *this;
195*2e9d4914SAndroid Build Coastguard Worker 		}
196*2e9d4914SAndroid Build Coastguard Worker 
197*2e9d4914SAndroid Build Coastguard Worker 		// Defines this setting to be mandatory.
198*2e9d4914SAndroid Build Coastguard Worker 		// Any mandatory value missing in the configuration file will raise an error.
199*2e9d4914SAndroid Build Coastguard Worker 		// Use isAnyMandatorySettingMissing() to check for any violations.
isMandatory()200*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting& isMandatory()
201*2e9d4914SAndroid Build Coastguard Worker 		{
202*2e9d4914SAndroid Build Coastguard Worker 			isSettingMandatory = true;
203*2e9d4914SAndroid Build Coastguard Worker 			if (parent) parent->isMandatory();
204*2e9d4914SAndroid Build Coastguard Worker 			return *this;
205*2e9d4914SAndroid Build Coastguard Worker 		}
206*2e9d4914SAndroid Build Coastguard Worker 
207*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
T()208*2e9d4914SAndroid Build Coastguard Worker 		operator T()
209*2e9d4914SAndroid Build Coastguard Worker 		{
210*2e9d4914SAndroid Build Coastguard Worker 			auto requestedType = GetRequestedType<T>();
211*2e9d4914SAndroid Build Coastguard Worker 			CheckType(defaultVal, requestedType);
212*2e9d4914SAndroid Build Coastguard Worker 			CheckType(minVal, requestedType);
213*2e9d4914SAndroid Build Coastguard Worker 			CheckType(maxVal, requestedType);
214*2e9d4914SAndroid Build Coastguard Worker 
215*2e9d4914SAndroid Build Coastguard Worker 			CaptureSetting<T>(requestedType);
216*2e9d4914SAndroid Build Coastguard Worker 
217*2e9d4914SAndroid Build Coastguard Worker 			if (!setting)
218*2e9d4914SAndroid Build Coastguard Worker 			{
219*2e9d4914SAndroid Build Coastguard Worker 				if (isSettingMandatory)
220*2e9d4914SAndroid Build Coastguard Worker 				{
221*2e9d4914SAndroid Build Coastguard Worker 					AlertMandatorySettingMissing<T>();
222*2e9d4914SAndroid Build Coastguard Worker 				}
223*2e9d4914SAndroid Build Coastguard Worker 				PropagateAnySettingIsMissing();
224*2e9d4914SAndroid Build Coastguard Worker 
225*2e9d4914SAndroid Build Coastguard Worker 				return GetDefaultValue<T>();
226*2e9d4914SAndroid Build Coastguard Worker 			}
227*2e9d4914SAndroid Build Coastguard Worker 
228*2e9d4914SAndroid Build Coastguard Worker 			try
229*2e9d4914SAndroid Build Coastguard Worker 			{
230*2e9d4914SAndroid Build Coastguard Worker 				T value = *setting;
231*2e9d4914SAndroid Build Coastguard Worker 				if (minVal.IsSet())
232*2e9d4914SAndroid Build Coastguard Worker 				{
233*2e9d4914SAndroid Build Coastguard Worker 					T min = minVal;
234*2e9d4914SAndroid Build Coastguard Worker 					if (value < min)
235*2e9d4914SAndroid Build Coastguard Worker 					{
236*2e9d4914SAndroid Build Coastguard Worker 						err << "'" << setting->getPath() << "' setting is out of valid bounds (min: " << min << "). Value was: " << value << std::endl;
237*2e9d4914SAndroid Build Coastguard Worker 						value = min;
238*2e9d4914SAndroid Build Coastguard Worker 					}
239*2e9d4914SAndroid Build Coastguard Worker 				}
240*2e9d4914SAndroid Build Coastguard Worker 				if (maxVal.IsSet())
241*2e9d4914SAndroid Build Coastguard Worker 				{
242*2e9d4914SAndroid Build Coastguard Worker 					T max = maxVal;
243*2e9d4914SAndroid Build Coastguard Worker 					if (value > max)
244*2e9d4914SAndroid Build Coastguard Worker 					{
245*2e9d4914SAndroid Build Coastguard Worker 						err << "'" << setting->getPath() << "' setting is out of valid bounds (max: " << max << "). Value was: " << value << std::endl;
246*2e9d4914SAndroid Build Coastguard Worker 						value = max;
247*2e9d4914SAndroid Build Coastguard Worker 					}
248*2e9d4914SAndroid Build Coastguard Worker 				}
249*2e9d4914SAndroid Build Coastguard Worker 				return value;
250*2e9d4914SAndroid Build Coastguard Worker 			}
251*2e9d4914SAndroid Build Coastguard Worker 			catch (const SettingTypeException& tex)
252*2e9d4914SAndroid Build Coastguard Worker 			{
253*2e9d4914SAndroid Build Coastguard Worker 				err << "'" << tex.getPath() << "' setting is of wrong type." << std::endl;
254*2e9d4914SAndroid Build Coastguard Worker 			}
255*2e9d4914SAndroid Build Coastguard Worker 
256*2e9d4914SAndroid Build Coastguard Worker 			return GetDefaultValue<T>();
257*2e9d4914SAndroid Build Coastguard Worker 		}
258*2e9d4914SAndroid Build Coastguard Worker 
259*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting operator[](const char *name)
260*2e9d4914SAndroid Build Coastguard Worker 		{
261*2e9d4914SAndroid Build Coastguard Worker 			CaptureSetting<Setting>(Setting::TypeGroup);
262*2e9d4914SAndroid Build Coastguard Worker 
263*2e9d4914SAndroid Build Coastguard Worker 			if (!setting)
264*2e9d4914SAndroid Build Coastguard Worker 			{
265*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting(name, this);
266*2e9d4914SAndroid Build Coastguard Worker 			}
267*2e9d4914SAndroid Build Coastguard Worker 
268*2e9d4914SAndroid Build Coastguard Worker 			if(setting->exists(name))
269*2e9d4914SAndroid Build Coastguard Worker 			{
270*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting((*setting)[name], this);
271*2e9d4914SAndroid Build Coastguard Worker 			}
272*2e9d4914SAndroid Build Coastguard Worker 			else
273*2e9d4914SAndroid Build Coastguard Worker 			{
274*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting(name, this);
275*2e9d4914SAndroid Build Coastguard Worker 			}
276*2e9d4914SAndroid Build Coastguard Worker 		}
277*2e9d4914SAndroid Build Coastguard Worker 
278*2e9d4914SAndroid Build Coastguard Worker 		inline ChainedSetting operator[](const std::string &name)
279*2e9d4914SAndroid Build Coastguard Worker 		{
280*2e9d4914SAndroid Build Coastguard Worker 			return(operator[](name.c_str()));
281*2e9d4914SAndroid Build Coastguard Worker 		}
282*2e9d4914SAndroid Build Coastguard Worker 
283*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting operator[](int index)
284*2e9d4914SAndroid Build Coastguard Worker 		{
285*2e9d4914SAndroid Build Coastguard Worker 			// This could also be an TypeArray but we cannot be sure here.
286*2e9d4914SAndroid Build Coastguard Worker 			// By using TypeList we ensure it will always work.
287*2e9d4914SAndroid Build Coastguard Worker 			CaptureSetting<Setting>(Setting::TypeList);
288*2e9d4914SAndroid Build Coastguard Worker 
289*2e9d4914SAndroid Build Coastguard Worker 			if (!setting)
290*2e9d4914SAndroid Build Coastguard Worker 			{
291*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting(index, this);
292*2e9d4914SAndroid Build Coastguard Worker 			}
293*2e9d4914SAndroid Build Coastguard Worker 
294*2e9d4914SAndroid Build Coastguard Worker 			if (index >= 0 && index < setting->getLength())
295*2e9d4914SAndroid Build Coastguard Worker 			{
296*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting((*setting)[index], this);
297*2e9d4914SAndroid Build Coastguard Worker 			}
298*2e9d4914SAndroid Build Coastguard Worker 			else
299*2e9d4914SAndroid Build Coastguard Worker 			{
300*2e9d4914SAndroid Build Coastguard Worker 				return ChainedSetting(index, this);
301*2e9d4914SAndroid Build Coastguard Worker 			}
302*2e9d4914SAndroid Build Coastguard Worker 		}
303*2e9d4914SAndroid Build Coastguard Worker 
getLength()304*2e9d4914SAndroid Build Coastguard Worker 		int getLength() const
305*2e9d4914SAndroid Build Coastguard Worker 		{
306*2e9d4914SAndroid Build Coastguard Worker 			return setting ? setting->getLength() : 0;
307*2e9d4914SAndroid Build Coastguard Worker 		}
308*2e9d4914SAndroid Build Coastguard Worker 
getType()309*2e9d4914SAndroid Build Coastguard Worker 		Setting::Type getType() const
310*2e9d4914SAndroid Build Coastguard Worker 		{
311*2e9d4914SAndroid Build Coastguard Worker 			return setting ? setting->getType() : Setting::TypeNone;
312*2e9d4914SAndroid Build Coastguard Worker 		}
313*2e9d4914SAndroid Build Coastguard Worker 
314*2e9d4914SAndroid Build Coastguard Worker 		// Indicates whether this setting is present in the read configuration file.
exists()315*2e9d4914SAndroid Build Coastguard Worker 		bool exists() const
316*2e9d4914SAndroid Build Coastguard Worker 		{
317*2e9d4914SAndroid Build Coastguard Worker 			return setting != NULL;
318*2e9d4914SAndroid Build Coastguard Worker 		}
319*2e9d4914SAndroid Build Coastguard Worker 
isAnyMandatorySettingMissing()320*2e9d4914SAndroid Build Coastguard Worker 		bool isAnyMandatorySettingMissing() const
321*2e9d4914SAndroid Build Coastguard Worker 		{
322*2e9d4914SAndroid Build Coastguard Worker 			return anyMandatorySettingIsMissing;
323*2e9d4914SAndroid Build Coastguard Worker 		}
324*2e9d4914SAndroid Build Coastguard Worker 
isAnySettingMissing()325*2e9d4914SAndroid Build Coastguard Worker 		bool isAnySettingMissing() const
326*2e9d4914SAndroid Build Coastguard Worker 		{
327*2e9d4914SAndroid Build Coastguard Worker 			return anySettingIsMissing;
328*2e9d4914SAndroid Build Coastguard Worker 		}
329*2e9d4914SAndroid Build Coastguard Worker 
clearAnySettingMissingFlag()330*2e9d4914SAndroid Build Coastguard Worker 		void clearAnySettingMissingFlag()
331*2e9d4914SAndroid Build Coastguard Worker 		{
332*2e9d4914SAndroid Build Coastguard Worker 			anySettingIsMissing = false;
333*2e9d4914SAndroid Build Coastguard Worker 		}
334*2e9d4914SAndroid Build Coastguard Worker 
335*2e9d4914SAndroid Build Coastguard Worker 	private:
336*2e9d4914SAndroid Build Coastguard Worker 
ChainedSetting(Setting & setting,ChainedSetting * parent)337*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting(Setting& setting, ChainedSetting* parent)
338*2e9d4914SAndroid Build Coastguard Worker 			: name(setting.isRoot() ? "<root>" : (setting.getName() ? setting.getName() : ""))
339*2e9d4914SAndroid Build Coastguard Worker 			, index(setting.getIndex())
340*2e9d4914SAndroid Build Coastguard Worker 			, parent(parent)
341*2e9d4914SAndroid Build Coastguard Worker 			, setting(&setting)
342*2e9d4914SAndroid Build Coastguard Worker 			, err(parent->err)
343*2e9d4914SAndroid Build Coastguard Worker 			, isSettingMandatory(false)
344*2e9d4914SAndroid Build Coastguard Worker 			, anySettingIsMissing(false)
345*2e9d4914SAndroid Build Coastguard Worker 			, anyMandatorySettingIsMissing(false)
346*2e9d4914SAndroid Build Coastguard Worker 			, capturedSpecification(NULL)
347*2e9d4914SAndroid Build Coastguard Worker 			, capturedSetting(NULL)
348*2e9d4914SAndroid Build Coastguard Worker 		{
349*2e9d4914SAndroid Build Coastguard Worker 		}
350*2e9d4914SAndroid Build Coastguard Worker 
ChainedSetting(const std::string & name,ChainedSetting * parent)351*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting(const std::string& name, ChainedSetting* parent)
352*2e9d4914SAndroid Build Coastguard Worker 			: name(name)
353*2e9d4914SAndroid Build Coastguard Worker 			, index(-1)
354*2e9d4914SAndroid Build Coastguard Worker 			, parent(parent)
355*2e9d4914SAndroid Build Coastguard Worker 			, setting(NULL)
356*2e9d4914SAndroid Build Coastguard Worker 			, err(parent->err)
357*2e9d4914SAndroid Build Coastguard Worker 			, isSettingMandatory(false)
358*2e9d4914SAndroid Build Coastguard Worker 			, anySettingIsMissing(true)
359*2e9d4914SAndroid Build Coastguard Worker 			, anyMandatorySettingIsMissing(false)
360*2e9d4914SAndroid Build Coastguard Worker 			, capturedSpecification(NULL)
361*2e9d4914SAndroid Build Coastguard Worker 			, capturedSetting(NULL)
362*2e9d4914SAndroid Build Coastguard Worker 		{
363*2e9d4914SAndroid Build Coastguard Worker 		}
364*2e9d4914SAndroid Build Coastguard Worker 
ChainedSetting(int index,ChainedSetting * parent)365*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting(int index, ChainedSetting* parent)
366*2e9d4914SAndroid Build Coastguard Worker 			: name("")
367*2e9d4914SAndroid Build Coastguard Worker 			, index(index)
368*2e9d4914SAndroid Build Coastguard Worker 			, parent(parent)
369*2e9d4914SAndroid Build Coastguard Worker 			, setting(NULL)
370*2e9d4914SAndroid Build Coastguard Worker 			, err(parent->err)
371*2e9d4914SAndroid Build Coastguard Worker 			, isSettingMandatory(false)
372*2e9d4914SAndroid Build Coastguard Worker 			, anySettingIsMissing(true)
373*2e9d4914SAndroid Build Coastguard Worker 			, anyMandatorySettingIsMissing(false)
374*2e9d4914SAndroid Build Coastguard Worker 			, capturedSpecification(NULL)
375*2e9d4914SAndroid Build Coastguard Worker 			, capturedSetting(NULL)
376*2e9d4914SAndroid Build Coastguard Worker 		{
377*2e9d4914SAndroid Build Coastguard Worker 		}
378*2e9d4914SAndroid Build Coastguard Worker 
379*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
ConditionalSetCapturedDefaultValue()380*2e9d4914SAndroid Build Coastguard Worker 		void ConditionalSetCapturedDefaultValue()
381*2e9d4914SAndroid Build Coastguard Worker 		{
382*2e9d4914SAndroid Build Coastguard Worker 			*capturedSetting = GetDefaultValue<T>();
383*2e9d4914SAndroid Build Coastguard Worker 		}
384*2e9d4914SAndroid Build Coastguard Worker 
385*2e9d4914SAndroid Build Coastguard Worker 
386*2e9d4914SAndroid Build Coastguard Worker 
387*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
CaptureSetting(Setting::Type type)388*2e9d4914SAndroid Build Coastguard Worker 		void CaptureSetting(Setting::Type type)
389*2e9d4914SAndroid Build Coastguard Worker 		{
390*2e9d4914SAndroid Build Coastguard Worker 			if (!capturedSetting && parent && parent->capturedSetting)
391*2e9d4914SAndroid Build Coastguard Worker 			{
392*2e9d4914SAndroid Build Coastguard Worker 				if (name.length() > 0)
393*2e9d4914SAndroid Build Coastguard Worker 				{
394*2e9d4914SAndroid Build Coastguard Worker 					if (!parent->capturedSetting->exists(name))
395*2e9d4914SAndroid Build Coastguard Worker 					{
396*2e9d4914SAndroid Build Coastguard Worker 						capturedSetting = &parent->capturedSetting->add(name, type);
397*2e9d4914SAndroid Build Coastguard Worker 					}
398*2e9d4914SAndroid Build Coastguard Worker 					else
399*2e9d4914SAndroid Build Coastguard Worker 					{
400*2e9d4914SAndroid Build Coastguard Worker 						capturedSetting = &(*parent->capturedSetting)[name.c_str()];
401*2e9d4914SAndroid Build Coastguard Worker 					}
402*2e9d4914SAndroid Build Coastguard Worker 				}
403*2e9d4914SAndroid Build Coastguard Worker 				else
404*2e9d4914SAndroid Build Coastguard Worker 				{
405*2e9d4914SAndroid Build Coastguard Worker 					if (index < parent->capturedSetting->getLength())
406*2e9d4914SAndroid Build Coastguard Worker 					{
407*2e9d4914SAndroid Build Coastguard Worker 						capturedSetting = &(*parent->capturedSetting)[0];
408*2e9d4914SAndroid Build Coastguard Worker 					}
409*2e9d4914SAndroid Build Coastguard Worker 					else
410*2e9d4914SAndroid Build Coastguard Worker 					{
411*2e9d4914SAndroid Build Coastguard Worker 						assert(index == parent->capturedSetting->getLength()); // you requested an index while omitting at least one of its previous siblings
412*2e9d4914SAndroid Build Coastguard Worker 						capturedSetting = &parent->capturedSetting->add(type);
413*2e9d4914SAndroid Build Coastguard Worker 					}
414*2e9d4914SAndroid Build Coastguard Worker 				}
415*2e9d4914SAndroid Build Coastguard Worker 
416*2e9d4914SAndroid Build Coastguard Worker 				ConditionalSetCapturedDefaultValue<T>();
417*2e9d4914SAndroid Build Coastguard Worker 			}
418*2e9d4914SAndroid Build Coastguard Worker 		}
419*2e9d4914SAndroid Build Coastguard Worker 
420*2e9d4914SAndroid Build Coastguard Worker 
GetPath()421*2e9d4914SAndroid Build Coastguard Worker 		std::string GetPath() const
422*2e9d4914SAndroid Build Coastguard Worker 		{
423*2e9d4914SAndroid Build Coastguard Worker 			if (setting)
424*2e9d4914SAndroid Build Coastguard Worker 			{
425*2e9d4914SAndroid Build Coastguard Worker 				return setting->getPath();
426*2e9d4914SAndroid Build Coastguard Worker 			}
427*2e9d4914SAndroid Build Coastguard Worker 
428*2e9d4914SAndroid Build Coastguard Worker 			std::string path = (name.length() > 0) ? name : "[" + std::to_string(index) + "]";
429*2e9d4914SAndroid Build Coastguard Worker 			if (parent)
430*2e9d4914SAndroid Build Coastguard Worker 			{
431*2e9d4914SAndroid Build Coastguard Worker 				auto parentPath = parent->GetPath();
432*2e9d4914SAndroid Build Coastguard Worker 				return (parentPath.length() > 0) ? (parentPath + ((name.length() == 0) ? "" : ".") + path) : path;
433*2e9d4914SAndroid Build Coastguard Worker 			}
434*2e9d4914SAndroid Build Coastguard Worker 			return path;
435*2e9d4914SAndroid Build Coastguard Worker 		}
436*2e9d4914SAndroid Build Coastguard Worker 
PropagateAnySettingIsMissing()437*2e9d4914SAndroid Build Coastguard Worker 		void PropagateAnySettingIsMissing()
438*2e9d4914SAndroid Build Coastguard Worker 		{
439*2e9d4914SAndroid Build Coastguard Worker 			anySettingIsMissing = true;
440*2e9d4914SAndroid Build Coastguard Worker 			if (parent)
441*2e9d4914SAndroid Build Coastguard Worker 			{
442*2e9d4914SAndroid Build Coastguard Worker 				parent->PropagateAnySettingIsMissing();
443*2e9d4914SAndroid Build Coastguard Worker 			}
444*2e9d4914SAndroid Build Coastguard Worker 		}
445*2e9d4914SAndroid Build Coastguard Worker 
PropagateAnyMandatorySettingIsMissing()446*2e9d4914SAndroid Build Coastguard Worker 		void PropagateAnyMandatorySettingIsMissing()
447*2e9d4914SAndroid Build Coastguard Worker 		{
448*2e9d4914SAndroid Build Coastguard Worker 			anyMandatorySettingIsMissing = true;
449*2e9d4914SAndroid Build Coastguard Worker 			if (parent)
450*2e9d4914SAndroid Build Coastguard Worker 			{
451*2e9d4914SAndroid Build Coastguard Worker 				parent->PropagateAnyMandatorySettingIsMissing();
452*2e9d4914SAndroid Build Coastguard Worker 			}
453*2e9d4914SAndroid Build Coastguard Worker 		}
454*2e9d4914SAndroid Build Coastguard Worker 
455*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
AlertMandatorySettingMissing()456*2e9d4914SAndroid Build Coastguard Worker 		void AlertMandatorySettingMissing()
457*2e9d4914SAndroid Build Coastguard Worker 		{
458*2e9d4914SAndroid Build Coastguard Worker 			PropagateAnyMandatorySettingIsMissing();
459*2e9d4914SAndroid Build Coastguard Worker 
460*2e9d4914SAndroid Build Coastguard Worker 			err << "Missing '" << GetPath() << "' setting in configuration file." << std::endl;
461*2e9d4914SAndroid Build Coastguard Worker 		}
462*2e9d4914SAndroid Build Coastguard Worker 
463*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
GetUnsetDefaultValue()464*2e9d4914SAndroid Build Coastguard Worker 		T GetUnsetDefaultValue() const
465*2e9d4914SAndroid Build Coastguard Worker 		{
466*2e9d4914SAndroid Build Coastguard Worker 			return (T)0;
467*2e9d4914SAndroid Build Coastguard Worker 		}
468*2e9d4914SAndroid Build Coastguard Worker 
469*2e9d4914SAndroid Build Coastguard Worker 
470*2e9d4914SAndroid Build Coastguard Worker 
471*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
GetDefaultValue()472*2e9d4914SAndroid Build Coastguard Worker 		T GetDefaultValue() const
473*2e9d4914SAndroid Build Coastguard Worker 		{
474*2e9d4914SAndroid Build Coastguard Worker 			if (defaultVal.IsSet())
475*2e9d4914SAndroid Build Coastguard Worker 			{
476*2e9d4914SAndroid Build Coastguard Worker 				return (T)defaultVal;
477*2e9d4914SAndroid Build Coastguard Worker 			}
478*2e9d4914SAndroid Build Coastguard Worker 
479*2e9d4914SAndroid Build Coastguard Worker 			return GetUnsetDefaultValue<T>();
480*2e9d4914SAndroid Build Coastguard Worker 		}
481*2e9d4914SAndroid Build Coastguard Worker 
482*2e9d4914SAndroid Build Coastguard Worker 		template<typename T>
GetRequestedType()483*2e9d4914SAndroid Build Coastguard Worker 		Setting::Type GetRequestedType() const
484*2e9d4914SAndroid Build Coastguard Worker 		{
485*2e9d4914SAndroid Build Coastguard Worker 			// TODO @ Hemofektik: Check whether the outcommented line is still needed. static_assert(false) is checked on compile time and, well, asserts :)
486*2e9d4914SAndroid Build Coastguard Worker             // static_assert(false, "should never happen, unless you requested an unsupported type");
487*2e9d4914SAndroid Build Coastguard Worker 			return Setting::TypeNone;
488*2e9d4914SAndroid Build Coastguard Worker 		}
489*2e9d4914SAndroid Build Coastguard Worker 
490*2e9d4914SAndroid Build Coastguard Worker 
CheckType(const Variant & variant,Setting::Type expectedType)491*2e9d4914SAndroid Build Coastguard Worker 		void CheckType(const Variant& variant, Setting::Type expectedType) const
492*2e9d4914SAndroid Build Coastguard Worker 		{
493*2e9d4914SAndroid Build Coastguard Worker 			if (!variant.IsSet()) return;
494*2e9d4914SAndroid Build Coastguard Worker 			if(expectedType != variant.GetType())
495*2e9d4914SAndroid Build Coastguard Worker 			{
496*2e9d4914SAndroid Build Coastguard Worker 				assert(false); // fix your code to match the whole chain of this setting to one single type!
497*2e9d4914SAndroid Build Coastguard Worker 				err << "'" << GetPath() << "' setting limits or default value is of incompatible type." << std::endl;
498*2e9d4914SAndroid Build Coastguard Worker 			}
499*2e9d4914SAndroid Build Coastguard Worker 		}
500*2e9d4914SAndroid Build Coastguard Worker 
501*2e9d4914SAndroid Build Coastguard Worker 		std::string name;
502*2e9d4914SAndroid Build Coastguard Worker 		int index;
503*2e9d4914SAndroid Build Coastguard Worker 		ChainedSetting* parent;
504*2e9d4914SAndroid Build Coastguard Worker 		Setting* setting;
505*2e9d4914SAndroid Build Coastguard Worker 		std::ostream& err;
506*2e9d4914SAndroid Build Coastguard Worker 		Variant defaultVal;
507*2e9d4914SAndroid Build Coastguard Worker 		Variant minVal;
508*2e9d4914SAndroid Build Coastguard Worker 		Variant maxVal;
509*2e9d4914SAndroid Build Coastguard Worker 		bool isSettingMandatory;
510*2e9d4914SAndroid Build Coastguard Worker 		bool anySettingIsMissing;
511*2e9d4914SAndroid Build Coastguard Worker 		bool anyMandatorySettingIsMissing;
512*2e9d4914SAndroid Build Coastguard Worker 		Config* capturedSpecification;
513*2e9d4914SAndroid Build Coastguard Worker 		Setting* capturedSetting;
514*2e9d4914SAndroid Build Coastguard Worker 	};
515*2e9d4914SAndroid Build Coastguard Worker 
516*2e9d4914SAndroid Build Coastguard Worker     template<>
517*2e9d4914SAndroid Build Coastguard Worker     inline
518*2e9d4914SAndroid Build Coastguard Worker     void ChainedSetting::ConditionalSetCapturedDefaultValue<Setting>() { }
519*2e9d4914SAndroid Build Coastguard Worker 
520*2e9d4914SAndroid Build Coastguard Worker 	template<>
521*2e9d4914SAndroid Build Coastguard Worker     inline
GetUnsetDefaultValue()522*2e9d4914SAndroid Build Coastguard Worker     std::string ChainedSetting::GetUnsetDefaultValue() const
523*2e9d4914SAndroid Build Coastguard Worker     {
524*2e9d4914SAndroid Build Coastguard Worker         return "";
525*2e9d4914SAndroid Build Coastguard Worker     }
526*2e9d4914SAndroid Build Coastguard Worker 
527*2e9d4914SAndroid Build Coastguard Worker 
528*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<int8_t>() const { return Setting::TypeInt; }
529*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<uint8_t>() const { return Setting::TypeInt; }
530*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<int16_t>() const { return Setting::TypeInt; }
531*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<uint16_t>() const { return Setting::TypeInt; }
532*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<int32_t>() const { return Setting::TypeInt; }
533*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<uint32_t>() const { return Setting::TypeInt; }
534*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<int64_t>() const { return Setting::TypeInt64; }
535*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<uint64_t>() const { return Setting::TypeInt64; }
536*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<float>() const { return Setting::TypeFloat; }
537*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<double>() const { return Setting::TypeFloat; }
538*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<std::string>() const { return Setting::TypeString; }
539*2e9d4914SAndroid Build Coastguard Worker     template<> inline Setting::Type ChainedSetting::GetRequestedType<bool>() const { return Setting::TypeBoolean; }
540*2e9d4914SAndroid Build Coastguard Worker }
541*2e9d4914SAndroid Build Coastguard Worker 
542*2e9d4914SAndroid Build Coastguard Worker #endif