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