Panda3D
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 
26 using std::string;
27 
28 
29 /**
30  * Use the ConfigVariableManager::make_variable() interface to create a new
31  * ConfigVariableCore.
32  */
33 ConfigVariableCore::
34 ConfigVariableCore(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  */
54 ConfigVariableCore::
55 ConfigVariableCore(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  */
75 ConfigVariableCore::
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  */
87 set_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  */
111 set_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  */
150 set_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  */
191 set_default_value(const string &default_value) {
192  if (_default_value == nullptr) {
193  // Defining the default value for the first time.
194  ConfigPage *default_page = ConfigPage::get_default_page();
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) {
234  ConfigPage *local_page = ConfigPage::get_local_page();
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  */
273 has_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  */
287 get_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  */
307 get_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  */
329 void ConfigVariableCore::
330 output(std::ostream &out) const {
331  out << get_declaration(0)->get_string_value();
332 }
333 
334 /**
335  *
336  */
337 void ConfigVariableCore::
338 write(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  */
375 void ConfigVariableCore::
376 add_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  */
386 void ConfigVariableCore::
387 remove_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.
407 class CompareConfigDeclarations {
408 public:
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  */
419 void ConfigVariableCore::
420 sort_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 }
ConfigVariableCore::clear_local_value
bool clear_local_value()
Removes the local value defined for this variable, and allows its value to be once again retrieved fr...
Definition: configVariableCore.cxx:257
ConfigVariableCore::has_local_value
bool has_local_value() const
Returns true if this variable's value has been shadowed by a local assignment (as created via make_lo...
Definition: configVariableCore.I:120
configVariableCore.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
configDeclaration.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigVariableCore::get_declaration
get_declaration
Returns the nth declarations that contributes to this variable's value.
Definition: configVariableCore.h:65
ConfigVariableCore::is_closed
is_closed
Returns true if the variable is not trusted by any prc file (and hence cannot be modified from its co...
Definition: configVariableCore.h:85
ConfigVariableCore::get_num_declarations
get_num_declarations
Returns the number of declarations that contribute to this variable's value.
Definition: configVariableCore.h:65
ConfigVariableCore::make_local_value
ConfigDeclaration * make_local_value()
Creates a new local value for this variable, if there is not already one specified.
Definition: configVariableCore.cxx:232
ConfigPage::make_declaration
ConfigDeclaration * make_declaration(const std::string &variable, const std::string &value)
Adds the indicated variable/value pair as a new declaration on the page.
Definition: configPage.cxx:237
ConfigVariableCore
The internal definition of a ConfigVariable.
Definition: configVariableCore.h:34
ConfigVariableCore::set_default_value
set_default_value
Specifies the default value for this variable if it is not defined in any prc file.
Definition: configVariableCore.h:91
configPage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigVariableCore::set_value_type
set_value_type
Specifies the type of this variable.
Definition: configVariableCore.h:89
pnotify.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigDeclaration::get_page
get_page
Returns the page on which this declaration can be found.
Definition: configDeclaration.h:46
ConfigVariableCore::has_value
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set,...
Definition: configVariableCore.cxx:273
ConfigVariableCore::get_trust_level
get_trust_level
Returns the minimum trust_level a prc file must demonstrate in order to redefine the value for this v...
Definition: configVariableCore.h:86
ConfigPage
A page of ConfigDeclarations that may be loaded or unloaded.
Definition: configPage.h:30
ConfigVariableCore::set_flags
void set_flags(int flags)
Specifies the trust level of this variable.
Definition: configVariableCore.cxx:111
config_prc.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigPage::delete_declaration
bool delete_declaration(ConfigDeclaration *decl)
Removes the indicated declaration from the page and deletes it.
Definition: configPage.cxx:263
ConfigVariableCore::set_description
set_description
Specifies the one-line description of this variable.
Definition: configVariableCore.h:90
ConfigVariableCore::get_name
get_name
Returns the name of the variable.
Definition: configVariableCore.h:83
ConfigPage::get_local_page
static ConfigPage * get_local_page()
Returns a pointer to the global "local page".
Definition: configPage.cxx:77
pset.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigDeclaration
A single declaration of a config variable, typically defined as one line in a .prc file,...
Definition: configDeclaration.h:34
ConfigDeclaration::get_string_value
const std::string & get_string_value() const
Returns the value assigned to this variable.
Definition: configDeclaration.I:53
ConfigDeclaration::set_string_value
void set_string_value(const std::string &value)
Changes the value assigned to this variable.
Definition: configDeclaration.I:61
ConfigPage::get_default_page
static ConfigPage * get_default_page()
Returns a pointer to the global "default page".
Definition: configPage.cxx:64
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49