Panda3D
Loading...
Searching...
No Matches
configVariableCore.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file configVariableCore.cxx
10 * @author drose
11 * @date 2004-10-15
12 */
13
14#include "configVariableCore.h"
15#include "configDeclaration.h"
16#include "configPage.h"
17#include "pset.h"
18#include "pnotify.h"
19#include "config_prc.h"
20
21// This file is generated by ppremake.
22#include "prc_parameters.h"
23
24#include <algorithm>
25
26using std::string;
27
28
29/**
30 * Use the ConfigVariableManager::make_variable() interface to create a new
31 * ConfigVariableCore.
32 */
33ConfigVariableCore::
34ConfigVariableCore(const string &name) :
35 _name(name),
36 _is_used(false),
37 _value_type(VT_undefined),
38 _flags(0),
39 _default_value(nullptr),
40 _local_value(nullptr),
41 _declarations_sorted(true),
42 _value_queried(false)
43{
44#if defined(PRC_INC_TRUST_LEVEL) && PRC_INC_TRUST_LEVEL != 0
45 _flags = (_flags & ~F_trust_level_mask) | ((_flags & F_trust_level_mask) + PRC_INC_TRUST_LEVEL);
46#endif // PRC_INC_TRUST_LEVEL
47}
48
49/**
50 * This is used by ConfigVariableManager to create the variable from a
51 * template--basically, another variable with all of the initial properties
52 * pre-defined.
53 */
54ConfigVariableCore::
55ConfigVariableCore(const ConfigVariableCore &templ, const string &name) :
56 _name(name),
57 _is_used(templ._is_used),
58 _value_type(templ._value_type),
59 _description(templ._description),
60 _flags(templ._flags),
61 _default_value(nullptr),
62 _local_value(nullptr),
63 _declarations_sorted(false),
64 _value_queried(false)
65{
66 if (templ._default_value != nullptr) {
67 set_default_value(templ._default_value->get_string_value());
68 }
69}
70
71/**
72 * The destructor should never be called; ConfigVariableCore objects live
73 * forever and never get destructed.
74 */
75ConfigVariableCore::
76~ConfigVariableCore() {
77 prc_cat->error()
78 << "Internal error--ConfigVariableCore destructor called!\n";
79}
80
81/**
82 * Specifies the type of this variable. See get_value_type(). It is not an
83 * error to call this multiple times, but if the value changes once
84 * get_declaration() has been called, a warning is printed.
85 */
87set_value_type(ConfigVariableCore::ValueType value_type) {
88 if (_value_queried && _value_type != value_type) {
89 if ((_flags & F_dconfig) != 0) {
90 // As a special exception, if the flags include F_dconfig, we don't
91 // report a warning for changing the type, assuming the variable is
92 // being defined through the older DConfig interface.
93
94 } else {
95 prc_cat->warning()
96 << "changing type for ConfigVariable "
97 << get_name() << " from " << _value_type << " to "
98 << value_type << ".\n";
99 }
100 }
101
102 _value_type = value_type;
103}
104
105/**
106 * Specifies the trust level of this variable. See get_flags(). It is not an
107 * error to call this multiple times, but if the value changes once
108 * get_declaration() has been called, a warning is printed.
109 */
111set_flags(int flags) {
112 if ((flags & F_dconfig) != 0) {
113 flags = (flags & ~F_trust_level_mask) | PRC_DCONFIG_TRUST_LEVEL;
114 }
115
116#if defined(PRC_INC_TRUST_LEVEL) && PRC_INC_TRUST_LEVEL != 0
117 flags = (flags & ~F_trust_level_mask) | ((flags & F_trust_level_mask) + PRC_INC_TRUST_LEVEL);
118#endif // PRC_INC_TRUST_LEVEL
119
120 if (_value_queried) {
121 int bits_changed = (_flags ^ flags);
122 if ((bits_changed & F_trust_level_mask) != 0) {
123 prc_cat->warning()
124 << "changing trust level for ConfigVariable "
125 << get_name() << " from " << (_flags & F_trust_level_mask) << " to "
126 << (flags & F_trust_level_mask) << ".\n";
127 }
128 if ((bits_changed & ~(F_trust_level_mask | F_dconfig)) != 0) {
129 prc_cat->warning()
130 << "changing flags for ConfigVariable "
131 << get_name() << " from " << std::hex
132 << (_flags & ~F_trust_level_mask) << " to "
133 << (flags & ~F_trust_level_mask) << std::dec << ".\n";
134 }
135 }
136
137 _flags = flags;
138
139 // Changing the trust level will require re-sorting the declarations.
140 _declarations_sorted = false;
141}
142
143/**
144 * Specifies the one-line description of this variable. See
145 * get_description(). It is not an error to call this multiple times, but if
146 * the value changes once get_declaration() has been called, a warning is
147 * printed.
148 */
150set_description(const string &description) {
151 if (_value_queried && _description != description) {
152 if ((_flags & F_dconfig) != 0) {
153 // As a special exception, if the flags include F_dconfig, we don't
154 // change it, since this is presumably coming from the older DConfig
155 // interface.
156 return;
157 }
158 if (description == "DConfig") {
159 // As a similar exception, we don't replace an existing description with
160 // one that reads simply "DConfig", unless it was empty previously.
161 if (_description.empty()) {
162 _description = description;
163 }
164 return;
165 }
166
167 if (description.empty()) {
168 // If the new description is empty, we don't do anything.
169 return;
170 }
171
172 if (_description.empty()) {
173 // If the previous description was empty, we quietly replace it.
174 _description = description;
175 return;
176 }
177
178 prc_cat->warning()
179 << "changing description for ConfigVariable "
180 << get_name() << ".\n";
181 }
182
183 _description = description;
184}
185
186/**
187 * Specifies the default value for this variable if it is not defined in any
188 * prc file.
189 */
191set_default_value(const string &default_value) {
192 if (_default_value == nullptr) {
193 // Defining the default value for the first time.
195 _default_value = default_page->make_declaration(this, default_value);
196
197 } else {
198 // Modifying an existing default value.
199
200 // We set the original default value first, to avoid infinite recursion
201 // when the config variable in question happens to be consulted in
202 // NotifyCategory::out() (for instance, notify-timestamp).
203 string orig_default_value = _default_value->get_string_value();
204 _default_value->set_string_value(default_value);
205
206 if (orig_default_value != default_value) {
207 if ((_flags & F_dconfig) != 0) {
208 // As a special exception, if the flags include F_dconfig, we don't
209 // report a warning for changing the default value, assuming the
210 // variable is being defined through the older DConfig interface.
211
212 } else {
213 prc_cat->warning()
214 << "changing default value for ConfigVariable "
215 << get_name() << " from '" << orig_default_value
216 << "' to '" << default_value << "'.\n";
217 }
218 }
219 }
220}
221
222/**
223 * Creates a new local value for this variable, if there is not already one
224 * specified. This will shadow any values defined in the various .prc files.
225 *
226 * If there is already a local value defined for this variable, simply returns
227 * that one.
228 *
229 * Use clear_local_value() to remove the local value definition.
230 */
233 if (_local_value == nullptr) {
235 string string_value = get_declaration(0)->get_string_value();
236 _local_value = local_page->make_declaration(this, string_value);
237
238 if (is_closed()) {
239 prc_cat.warning()
240 << "Assigning a local value to a \"closed\" ConfigVariable. "
241 "This is legal in a development build, but illegal in a release "
242 "build and may result in a compilation error or exception.\n";
243 }
244 }
245
246 return _local_value;
247}
248
249/**
250 * Removes the local value defined for this variable, and allows its value to
251 * be once again retrieved from the .prc files.
252 *
253 * Returns true if the value was successfully removed, false if it did not
254 * exist in the first place.
255 */
258 if (_local_value != nullptr) {
260 _local_value = nullptr;
261 invalidate_cache();
262 return true;
263 }
264
265 return false;
266}
267
268/**
269 * Returns true if this variable has an explicit value, either from a prc file
270 * or locally set, or false if variable has its default value.
271 */
273has_value() const {
274 if (has_local_value()) {
275 return true;
276 }
277 check_sort_declarations();
278 return (!_trusted_declarations.empty());
279}
280
281/**
282 * Returns the number of declarations that contribute to this variable's
283 * value. If the variable has been defined, this will always be at least 1
284 * (for the default value, at least).
285 */
287get_num_declarations() const {
288 if (has_local_value()) {
289 return 1;
290 }
291 check_sort_declarations();
292 if (!_trusted_declarations.empty()) {
293 return _trusted_declarations.size();
294 }
295
296 // We always have at least one: the default value.
297 return 1;
298}
299
300/**
301 * Returns the nth declarations that contributes to this variable's value.
302 * The declarations are arranged in order such that earlier declarations
303 * shadow later declarations; thus, get_declaration(0) is always defined and
304 * always returns the current value of the variable.
305 */
307get_declaration(size_t n) const {
308 ((ConfigVariableCore *)this)->_value_queried = true;
309 if (_default_value == nullptr) {
310 prc_cat->warning()
311 << "value queried before default value set for "
312 << get_name() << ".\n";
313 ((ConfigVariableCore *)this)->set_default_value("");
314 }
315
316 if (has_local_value()) {
317 return _local_value;
318 }
319 check_sort_declarations();
320 if (n < _trusted_declarations.size()) {
321 return _trusted_declarations[n];
322 }
323 return _default_value;
324}
325
326/**
327 *
328 */
329void ConfigVariableCore::
330output(std::ostream &out) const {
331 out << get_declaration(0)->get_string_value();
332}
333
334/**
335 *
336 */
337void ConfigVariableCore::
338write(std::ostream &out) const {
339 out << "ConfigVariable " << get_name() << ":\n";
340
341 check_sort_declarations();
342
343 if (has_local_value()) {
344 out << " " << *_local_value << " (defined locally)\n";
345 }
346
347 Declarations::const_iterator di;
348 for (di = _trusted_declarations.begin();
349 di != _trusted_declarations.end();
350 ++di) {
351 out << " " << *(*di)
352 << " (from " << (*di)->get_page()->get_name() << ")\n";
353 }
354
355 if (_default_value != nullptr) {
356 out << " " << *_default_value << " (default value)\n";
357 }
358
359 for (di = _untrusted_declarations.begin();
360 di != _untrusted_declarations.end();
361 ++di) {
362 out << " " << *(*di)
363 << " (from " << (*di)->get_page()->get_name() << ", untrusted)\n";
364 }
365
366 if (!_description.empty()) {
367 out << "\n" << _description << "\n";
368 }
369}
370
371/**
372 * Called only by the ConfigDeclaration constructor, this adds the indicated
373 * declaration to the list of declarations that reference this variable.
374 */
375void ConfigVariableCore::
376add_declaration(ConfigDeclaration *decl) {
377 _declarations.push_back(decl);
378
379 _declarations_sorted = false;
380}
381
382/**
383 * Called only by the ConfigDeclaration destructor, this removes the indicated
384 * declaration from the list of declarations that reference this variable.
385 */
386void ConfigVariableCore::
387remove_declaration(ConfigDeclaration *decl) {
388 Declarations::iterator di;
389 for (di = _declarations.begin(); di != _declarations.end(); ++di) {
390 if ((*di) == decl) {
391 // Rather than deleting the declaration from the middle of the list, we
392 // maybe save a bit of time by swapping in the one at the end of the
393 // list (although this will unsort the list).
394 Declarations::iterator di2 = _declarations.end();
395 di2--;
396 (*di) = (*di2);
397 _declarations.erase(di2);
398 _declarations_sorted = false;
399 return;
400 }
401 }
402
403 // Hmm, it wasn't here. Oh well.
404}
405
406// This class is used in sort_declarations, below.
407class CompareConfigDeclarations {
408public:
409 bool operator () (const ConfigDeclaration *a, const ConfigDeclaration *b) const {
410 return (*a) < (*b);
411 }
412};
413
414/**
415 * Sorts the list of declarations into priority order, so that the declaration
416 * at the front of the list is the one that shadows all following
417 * declarations.
418 */
419void ConfigVariableCore::
420sort_declarations() {
421 sort(_declarations.begin(), _declarations.end(), CompareConfigDeclarations());
422 Declarations::iterator di;
423
424 // Now that they're sorted, divide them into either trusted or untrusted
425 // declarations.
426#ifdef PRC_RESPECT_TRUST_LEVEL
427 // In this mode, normally for a release build, we sort the declarations
428 // honestly according to whether the prc file that defines them meets the
429 // required trust level.
430 _trusted_declarations.clear();
431 _untrusted_declarations.clear();
432 for (di = _declarations.begin(); di != _declarations.end(); ++di) {
433 const ConfigDeclaration *decl = (*di);
434 if (!is_closed() &&
435 get_trust_level() <= decl->get_page()->get_trust_level()) {
436 _trusted_declarations.push_back(decl);
437 } else {
438 _untrusted_declarations.push_back(decl);
439 }
440 }
441
442#else // PRC_RESPECT_TRUST_LEVEL
443 // In this mode, normally for the development environment, all declarations
444 // are trusted, regardless of the trust level.
445 _trusted_declarations = _declarations;
446 _untrusted_declarations.clear();
447
448#endif // PRC_RESPECT_TRUST_LEVEL
449
450 // Finally, determine the set of unique, trusted declarations--trusted
451 // declarations that have a unique string value. This is usually unneeded,
452 // but what the heck, it doesn't need to be recomputed all that often.
453 _unique_declarations.clear();
454
455 init_system_type_handles(); // Make sure pset_type_handle is initted.
456 pset<string> already_added;
457 for (di = _trusted_declarations.begin();
458 di != _trusted_declarations.end();
459 ++di) {
460 const ConfigDeclaration *decl = (*di);
461 if (already_added.insert(decl->get_string_value()).second) {
462 _unique_declarations.push_back(decl);
463 }
464 }
465
466 _declarations_sorted = true;
467}
A single declaration of a config variable, typically defined as one line in a .prc file,...
const std::string & get_string_value() const
Returns the value assigned to this variable.
get_page
Returns the page on which this declaration can be found.
void set_string_value(const std::string &value)
Changes the value assigned to this variable.
A page of ConfigDeclarations that may be loaded or unloaded.
Definition configPage.h:30
bool delete_declaration(ConfigDeclaration *decl)
Removes the indicated declaration from the page and deletes it.
ConfigDeclaration * make_declaration(const std::string &variable, const std::string &value)
Adds the indicated variable/value pair as a new declaration on the page.
static ConfigPage * get_default_page()
Returns a pointer to the global "default page".
static ConfigPage * get_local_page()
Returns a pointer to the global "local page".
The internal definition of a ConfigVariable.
void set_flags(int flags)
Specifies the trust level of this variable.
bool has_local_value() const
Returns true if this variable's value has been shadowed by a local assignment (as created via make_lo...
get_declaration
Returns the nth declarations that contributes to this variable's value.
set_default_value
Specifies the default value for this variable if it is not defined in any prc file.
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set,...
set_description
Specifies the one-line description of this variable.
bool clear_local_value()
Removes the local value defined for this variable, and allows its value to be once again retrieved fr...
is_closed
Returns true if the variable is not trusted by any prc file (and hence cannot be modified from its co...
get_num_declarations
Returns the number of declarations that contribute to this variable's value.
get_name
Returns the name of the variable.
ConfigDeclaration * make_local_value()
Creates a new local value for this variable, if there is not already one specified.
get_trust_level
Returns the minimum trust_level a prc file must demonstrate in order to redefine the value for this v...
set_value_type
Specifies the type of this variable.
This is our own Panda specialization on the default STL set.
Definition pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.